forked from lix-project/lix
Merge pull request #7708 from ShamrockLee/primop-rebasehash
primops: add builtins.convertHash
This commit is contained in:
commit
8b48fb146b
|
@ -8,4 +8,6 @@
|
|||
|
||||
- Introduce new flake installable syntax `flakeref#.attrPath` where the "." prefix denotes no searching of default attribute prefixes like `packages.<SYSTEM>` or `legacyPackages.<SYSTEM>`.
|
||||
|
||||
- Introduce a new built-in function [`builtins.convertHash`](@docroot@/language/builtins.md#builtins-convertHash).
|
||||
|
||||
- `builtins.fetchTree` is now marked as stable.
|
||||
|
|
|
@ -78,7 +78,7 @@ SV * queryReferences(char * path)
|
|||
SV * queryPathHash(char * path)
|
||||
PPCODE:
|
||||
try {
|
||||
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(Base32, true);
|
||||
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(HashFormat::Base32, true);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -104,7 +104,7 @@ SV * queryPathInfo(char * path, int base32)
|
|||
XPUSHs(&PL_sv_undef);
|
||||
else
|
||||
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
|
||||
auto s = info->narHash.to_string(base32 ? Base32 : Base16, true);
|
||||
auto s = info->narHash.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, true);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
mXPUSHi(info->registrationTime);
|
||||
mXPUSHi(info->narSize);
|
||||
|
@ -206,7 +206,7 @@ SV * hashPath(char * algo, int base32, char * path)
|
|||
PPCODE:
|
||||
try {
|
||||
Hash h = hashPath(parseHashType(algo), path).first;
|
||||
auto s = h.to_string(base32 ? Base32 : Base16, false);
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -217,7 +217,7 @@ SV * hashFile(char * algo, int base32, char * path)
|
|||
PPCODE:
|
||||
try {
|
||||
Hash h = hashFile(parseHashType(algo), path);
|
||||
auto s = h.to_string(base32 ? Base32 : Base16, false);
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -228,7 +228,7 @@ SV * hashString(char * algo, int base32, char * s)
|
|||
PPCODE:
|
||||
try {
|
||||
Hash h = hashString(parseHashType(algo), s);
|
||||
auto s = h.to_string(base32 ? Base32 : Base16, false);
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -239,7 +239,7 @@ SV * convertHash(char * algo, char * s, int toBase32)
|
|||
PPCODE:
|
||||
try {
|
||||
auto h = Hash::parseAny(s, parseHashType(algo));
|
||||
auto s = h.to_string(toBase32 ? Base32 : Base16, false);
|
||||
auto s = h.to_string(toBase32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
|
|
@ -50,7 +50,7 @@ struct AttrDb
|
|||
Path cacheDir = getCacheDir() + "/nix/eval-cache-v5";
|
||||
createDirs(cacheDir);
|
||||
|
||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(HashFormat::Base16, false) + ".sqlite";
|
||||
|
||||
state->db = SQLite(dbPath);
|
||||
state->db.isCache();
|
||||
|
|
|
@ -1758,7 +1758,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, V
|
|||
|
||||
auto path = realisePath(state, pos, *args[1]);
|
||||
|
||||
v.mkString(hashString(*ht, path.readFile()).to_string(Base16, false));
|
||||
v.mkString(hashString(*ht, path.readFile()).to_string(HashFormat::Base16, false));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_hashFile({
|
||||
|
@ -3760,7 +3760,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args,
|
|||
NixStringContext context; // discarded
|
||||
auto s = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString");
|
||||
|
||||
v.mkString(hashString(*ht, s).to_string(Base16, false));
|
||||
v.mkString(hashString(*ht, s).to_string(HashFormat::Base16, false));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_hashString({
|
||||
|
@ -3774,6 +3774,101 @@ static RegisterPrimOp primop_hashString({
|
|||
.fun = prim_hashString,
|
||||
});
|
||||
|
||||
static void prim_convertHash(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.convertHash");
|
||||
auto &inputAttrs = args[0]->attrs;
|
||||
|
||||
Bindings::iterator iteratorHash = getAttr(state, state.symbols.create("hash"), inputAttrs, "while locating the attribute 'hash'");
|
||||
auto hash = state.forceStringNoCtx(*iteratorHash->value, pos, "while evaluating the attribute 'hash'");
|
||||
|
||||
Bindings::iterator iteratorHashAlgo = inputAttrs->find(state.symbols.create("hashAlgo"));
|
||||
std::optional<HashType> ht = std::nullopt;
|
||||
if (iteratorHashAlgo != inputAttrs->end()) {
|
||||
ht = parseHashType(state.forceStringNoCtx(*iteratorHashAlgo->value, pos, "while evaluating the attribute 'hashAlgo'"));
|
||||
}
|
||||
|
||||
Bindings::iterator iteratorToHashFormat = getAttr(state, state.symbols.create("toHashFormat"), args[0]->attrs, "while locating the attribute 'toHashFormat'");
|
||||
HashFormat hf = parseHashFormat(state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'"));
|
||||
|
||||
v.mkString(Hash::parseAny(hash, ht).to_string(hf, hf == HashFormat::SRI));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_convertHash({
|
||||
.name = "__convertHash",
|
||||
.args = {"args"},
|
||||
.doc = R"(
|
||||
Return the specified representation of a hash string, based on the attributes presented in *args*:
|
||||
|
||||
- `hash`
|
||||
|
||||
The hash to be converted.
|
||||
The hash format is detected automatically.
|
||||
|
||||
- `hashAlgo`
|
||||
|
||||
The algorithm used to create the hash. Must be one of
|
||||
- `"md5"`
|
||||
- `"sha1"`
|
||||
- `"sha256"`
|
||||
- `"sha512"`
|
||||
|
||||
The attribute may be omitted when `hash` is an [SRI hash](https://www.w3.org/TR/SRI/#the-integrity-attribute) or when the hash is prefixed with the hash algorithm name followed by a colon.
|
||||
That `<hashAlgo>:<hashBody>` syntax is supported for backwards compatibility with existing tooling.
|
||||
|
||||
- `toHashFormat`
|
||||
|
||||
The format of the resulting hash. Must be one of
|
||||
- `"base16"`
|
||||
- `"base32"`
|
||||
- `"base64"`
|
||||
- `"sri"`
|
||||
|
||||
The result hash is the *toHashFormat* representation of the hash *hash*.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Convert a SHA256 hash in Base16 to SRI:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.convertHash {
|
||||
> hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
> toHashFormat = "sri";
|
||||
> hashAlgo = "sha256";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Convert a SHA256 hash in SRI to Base16:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.convertHash {
|
||||
> hash = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
|
||||
> toHashFormat = "base16";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Convert a hash in the form `<hashAlgo>:<hashBody>` in Base16 to SRI:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.convertHash {
|
||||
> hash = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
> toHashFormat = "sri";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
|
||||
)",
|
||||
.fun = prim_convertHash,
|
||||
});
|
||||
|
||||
struct RegexCache
|
||||
{
|
||||
// TODO use C++20 transparent comparison when available
|
||||
|
|
|
@ -31,7 +31,7 @@ void emitTreeAttrs(
|
|||
|
||||
auto narHash = input.getNarHash();
|
||||
assert(narHash);
|
||||
attrs.alloc("narHash").mkString(narHash->to_string(SRI, true));
|
||||
attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true));
|
||||
|
||||
if (input.getType() == "git")
|
||||
attrs.alloc("submodules").mkBool(
|
||||
|
@ -297,7 +297,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
|||
: hashFile(htSHA256, state.store->toRealPath(storePath));
|
||||
if (hash != *expectedHash)
|
||||
state.debugThrowLastTrace(EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s",
|
||||
*url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)));
|
||||
*url, expectedHash->to_string(HashFormat::Base32, true), hash.to_string(HashFormat::Base32, true)));
|
||||
}
|
||||
|
||||
state.allowAndSetStorePathString(storePath, v);
|
||||
|
|
|
@ -1084,7 +1084,7 @@ namespace nix {
|
|||
|
||||
ASSERT_TRACE1("hashString \"foo\" \"content\"",
|
||||
UsageError,
|
||||
hintfmt("unknown hash algorithm '%s'", "foo"));
|
||||
hintfmt("unknown hash algorithm '%s', expect 'md5', 'sha1', 'sha256', or 'sha512'", "foo"));
|
||||
|
||||
ASSERT_TRACE2("hashString \"sha256\" {}",
|
||||
TypeError,
|
||||
|
|
|
@ -147,12 +147,12 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
|
|||
};
|
||||
|
||||
auto narHash = store->queryPathInfo(tree.storePath)->narHash;
|
||||
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
|
||||
input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
|
||||
|
||||
if (auto prevNarHash = getNarHash()) {
|
||||
if (narHash != *prevNarHash)
|
||||
throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
|
||||
to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash.to_string(SRI, true));
|
||||
to_string(), tree.actualPath, prevNarHash->to_string(HashFormat::SRI, true), narHash.to_string(HashFormat::SRI, true));
|
||||
}
|
||||
|
||||
if (auto prevLastModified = getLastModified()) {
|
||||
|
|
|
@ -46,7 +46,7 @@ bool touchCacheFile(const Path & path, time_t touch_time)
|
|||
Path getCachePath(std::string_view key)
|
||||
{
|
||||
return getCacheDir() + "/nix/gitv3/" +
|
||||
hashString(htSHA256, key).to_string(Base32, false);
|
||||
hashString(htSHA256, key).to_string(HashFormat::Base32, false);
|
||||
}
|
||||
|
||||
// Returns the name of the HEAD branch.
|
||||
|
@ -417,7 +417,7 @@ struct GitInputScheme : InputScheme
|
|||
auto checkHashType = [&](const std::optional<Hash> & hash)
|
||||
{
|
||||
if (hash.has_value() && !(hash->type == htSHA1 || hash->type == htSHA256))
|
||||
throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(Base16, true));
|
||||
throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(HashFormat::Base16, true));
|
||||
};
|
||||
|
||||
auto getLockedAttrs = [&]()
|
||||
|
|
|
@ -125,7 +125,7 @@ struct GitArchiveInputScheme : InputScheme
|
|||
auto path = owner + "/" + repo;
|
||||
assert(!(ref && rev));
|
||||
if (ref) path += "/" + *ref;
|
||||
if (rev) path += "/" + rev->to_string(Base16, false);
|
||||
if (rev) path += "/" + rev->to_string(HashFormat::Base16, false);
|
||||
return ParsedURL {
|
||||
.scheme = type(),
|
||||
.path = path,
|
||||
|
@ -296,7 +296,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
|||
: "https://api.%s/repos/%s/%s/tarball/%s";
|
||||
|
||||
const auto url = fmt(urlFmt, host, getOwner(input), getRepo(input),
|
||||
input.getRev()->to_string(Base16, false));
|
||||
input.getRev()->to_string(HashFormat::Base16, false));
|
||||
|
||||
return DownloadUrl { url, headers };
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
|||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
|
||||
auto url = fmt("https://%s/api/v4/projects/%s%%2F%s/repository/archive.tar.gz?sha=%s",
|
||||
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
|
||||
input.getRev()->to_string(Base16, false));
|
||||
input.getRev()->to_string(HashFormat::Base16, false));
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(host);
|
||||
return DownloadUrl { url, headers };
|
||||
|
@ -449,7 +449,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
|||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||
auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz",
|
||||
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
|
||||
input.getRev()->to_string(Base16, false));
|
||||
input.getRev()->to_string(HashFormat::Base16, false));
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(host);
|
||||
return DownloadUrl { url, headers };
|
||||
|
|
|
@ -206,7 +206,7 @@ struct MercurialInputScheme : InputScheme
|
|||
auto checkHashType = [&](const std::optional<Hash> & hash)
|
||||
{
|
||||
if (hash.has_value() && hash->type != htSHA1)
|
||||
throw Error("Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(Base16, true));
|
||||
throw Error("Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(HashFormat::Base16, true));
|
||||
};
|
||||
|
||||
|
||||
|
@ -252,7 +252,7 @@ struct MercurialInputScheme : InputScheme
|
|||
}
|
||||
}
|
||||
|
||||
Path cacheDir = fmt("%s/nix/hg/%s", getCacheDir(), hashString(htSHA256, actualUrl).to_string(Base32, false));
|
||||
Path cacheDir = fmt("%s/nix/hg/%s", getCacheDir(), hashString(htSHA256, actualUrl).to_string(HashFormat::Base32, false));
|
||||
|
||||
/* If this is a commit hash that we already have, we don't
|
||||
have to pull again. */
|
||||
|
|
|
@ -250,7 +250,7 @@ struct CurlInputScheme : InputScheme
|
|||
// NAR hashes are preferred over file hashes since tar/zip
|
||||
// files don't have a canonical representation.
|
||||
if (auto narHash = input.getNarHash())
|
||||
url.query.insert_or_assign("narHash", narHash->to_string(SRI, true));
|
||||
url.query.insert_or_assign("narHash", narHash->to_string(HashFormat::SRI, true));
|
||||
return url;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
|||
auto [fileHash, fileSize] = fileHashSink.finish();
|
||||
narInfo->fileHash = fileHash;
|
||||
narInfo->fileSize = fileSize;
|
||||
narInfo->url = "nar/" + narInfo->fileHash->to_string(Base32, false) + ".nar"
|
||||
narInfo->url = "nar/" + narInfo->fileHash->to_string(HashFormat::Base32, false) + ".nar"
|
||||
+ (compression == "xz" ? ".xz" :
|
||||
compression == "bzip2" ? ".bz2" :
|
||||
compression == "zstd" ? ".zst" :
|
||||
|
|
|
@ -1066,7 +1066,7 @@ void LocalDerivationGoal::initTmpDir() {
|
|||
env[i.first] = i.second;
|
||||
} else {
|
||||
auto hash = hashString(htSHA256, i.first);
|
||||
std::string fn = ".attr-" + hash.to_string(Base32, false);
|
||||
std::string fn = ".attr-" + hash.to_string(HashFormat::Base32, false);
|
||||
Path p = tmpDir + "/" + fn;
|
||||
writeFile(p, rewriteStrings(i.second, inputRewrites));
|
||||
chownToBuilder(p);
|
||||
|
@ -2583,8 +2583,8 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
delayedException = std::make_exception_ptr(
|
||||
BuildError("hash mismatch in fixed-output derivation '%s':\n specified: %s\n got: %s",
|
||||
worker.store.printStorePath(drvPath),
|
||||
wanted.to_string(SRI, true),
|
||||
got.to_string(SRI, true)));
|
||||
wanted.to_string(HashFormat::SRI, true),
|
||||
got.to_string(HashFormat::SRI, true)));
|
||||
}
|
||||
if (!newInfo0.references.empty())
|
||||
delayedException = std::make_exception_ptr(
|
||||
|
|
|
@ -65,7 +65,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
|||
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
|
||||
std::optional<HashType> ht = parseHashTypeOpt(getAttr("outputHashAlgo"));
|
||||
Hash h = newHashAllowEmpty(getAttr("outputHash"), ht);
|
||||
fetch(hashedMirror + printHashType(h.type) + "/" + h.to_string(Base16, false));
|
||||
fetch(hashedMirror + printHashType(h.type) + "/" + h.to_string(HashFormat::Base16, false));
|
||||
return;
|
||||
} catch (Error & e) {
|
||||
debug(e.what());
|
||||
|
|
|
@ -60,7 +60,7 @@ std::string ContentAddress::render() const
|
|||
+ makeFileIngestionPrefix(method);
|
||||
},
|
||||
}, method.raw)
|
||||
+ this->hash.to_string(Base32, true);
|
||||
+ this->hash.to_string(HashFormat::Base32, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -334,7 +334,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
logger->startWork();
|
||||
auto hash = store->queryPathInfo(path)->narHash;
|
||||
logger->stopWork();
|
||||
to << hash.to_string(Base16, false);
|
||||
to << hash.to_string(HashFormat::Base16, false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -542,7 +542,7 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs,
|
|||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first)));
|
||||
s += ','; printUnquotedString(s, dof.ca.printMethodAlgo());
|
||||
s += ','; printUnquotedString(s, dof.ca.hash.to_string(Base16, false));
|
||||
s += ','; printUnquotedString(s, dof.ca.hash.to_string(HashFormat::Base16, false));
|
||||
},
|
||||
[&](const DerivationOutput::CAFloating & dof) {
|
||||
s += ','; printUnquotedString(s, "");
|
||||
|
@ -775,7 +775,7 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut
|
|||
auto & dof = std::get<DerivationOutput::CAFixed>(i.second.raw);
|
||||
auto hash = hashString(htSHA256, "fixed:out:"
|
||||
+ dof.ca.printMethodAlgo() + ":"
|
||||
+ dof.ca.hash.to_string(Base16, false) + ":"
|
||||
+ dof.ca.hash.to_string(HashFormat::Base16, false) + ":"
|
||||
+ store.printStorePath(dof.path(store, drv.name, i.first)));
|
||||
outputHashes.insert_or_assign(i.first, std::move(hash));
|
||||
}
|
||||
|
@ -820,7 +820,7 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut
|
|||
const auto h = get(res.hashes, outputName);
|
||||
if (!h)
|
||||
throw Error("no hash for output '%s' of derivation '%s'", outputName, drv.name);
|
||||
inputs2[h->to_string(Base16, false)].value.insert(outputName);
|
||||
inputs2[h->to_string(HashFormat::Base16, false)].value.insert(outputName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -925,7 +925,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
|||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
out << store.printStorePath(dof.path(store, drv.name, i.first))
|
||||
<< dof.ca.printMethodAlgo()
|
||||
<< dof.ca.hash.to_string(Base16, false);
|
||||
<< dof.ca.hash.to_string(HashFormat::Base16, false);
|
||||
},
|
||||
[&](const DerivationOutput::CAFloating & dof) {
|
||||
out << ""
|
||||
|
@ -957,7 +957,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
|||
std::string hashPlaceholder(const OutputNameView outputName)
|
||||
{
|
||||
// FIXME: memoize?
|
||||
return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(Base32, false);
|
||||
return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(HashFormat::Base32, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ nlohmann::json DerivationOutput::toJSON(
|
|||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
res["path"] = store.printStorePath(dof.path(store, drvName, outputName));
|
||||
res["hashAlgo"] = dof.ca.printMethodAlgo();
|
||||
res["hash"] = dof.ca.hash.to_string(Base16, false);
|
||||
res["hash"] = dof.ca.hash.to_string(HashFormat::Base16, false);
|
||||
// FIXME print refs?
|
||||
},
|
||||
[&](const DerivationOutput::CAFloating & dof) {
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace nix {
|
|||
|
||||
std::string DownstreamPlaceholder::render() const
|
||||
{
|
||||
return "/" + hash.to_string(Base32, false);
|
||||
return "/" + hash.to_string(HashFormat::Base32, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ DownstreamPlaceholder DownstreamPlaceholder::unknownDerivation(
|
|||
xpSettings.require(Xp::DynamicDerivations);
|
||||
auto compressed = compressHash(placeholder.hash, 20);
|
||||
auto clearText = "nix-computed-output:"
|
||||
+ compressed.to_string(Base32, false)
|
||||
+ compressed.to_string(HashFormat::Base32, false)
|
||||
+ ":" + std::string { outputName };
|
||||
return DownstreamPlaceholder {
|
||||
hashString(htSHA256, clearText)
|
||||
|
|
|
@ -41,7 +41,7 @@ void Store::exportPath(const StorePath & path, Sink & sink)
|
|||
Hash hash = hashSink.currentHash().first;
|
||||
if (hash != info->narHash && info->narHash != Hash(info->narHash.type))
|
||||
throw Error("hash of path '%s' has changed from '%s' to '%s'!",
|
||||
printStorePath(path), info->narHash.to_string(Base32, true), hash.to_string(Base32, true));
|
||||
printStorePath(path), info->narHash.to_string(HashFormat::Base32, true), hash.to_string(HashFormat::Base32, true));
|
||||
|
||||
teeSink
|
||||
<< exportMagic
|
||||
|
|
|
@ -43,7 +43,7 @@ static void makeSymlink(const Path & link, const Path & target)
|
|||
|
||||
void LocalStore::addIndirectRoot(const Path & path)
|
||||
{
|
||||
std::string hash = hashString(htSHA1, path).to_string(Base32, false);
|
||||
std::string hash = hashString(htSHA1, path).to_string(HashFormat::Base32, false);
|
||||
Path realRoot = canonPath(fmt("%1%/%2%/auto/%3%", stateDir, gcRootsDir, hash));
|
||||
makeSymlink(realRoot, path);
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
|||
<< ServeProto::Command::AddToStoreNar
|
||||
<< printStorePath(info.path)
|
||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||
<< info.narHash.to_string(Base16, false);
|
||||
<< info.narHash.to_string(HashFormat::Base16, false);
|
||||
ServeProto::write(*this, *conn, info.references);
|
||||
conn->to
|
||||
<< info.registrationTime
|
||||
|
|
|
@ -826,7 +826,7 @@ uint64_t LocalStore::addValidPath(State & state,
|
|||
|
||||
state.stmts->RegisterValidPath.use()
|
||||
(printStorePath(info.path))
|
||||
(info.narHash.to_string(Base16, true))
|
||||
(info.narHash.to_string(HashFormat::Base16, true))
|
||||
(info.registrationTime == 0 ? time(0) : info.registrationTime)
|
||||
(info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver)
|
||||
(info.narSize, info.narSize != 0)
|
||||
|
@ -933,7 +933,7 @@ void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info)
|
|||
{
|
||||
state.stmts->UpdatePathInfo.use()
|
||||
(info.narSize, info.narSize != 0)
|
||||
(info.narHash.to_string(Base16, true))
|
||||
(info.narHash.to_string(HashFormat::Base16, true))
|
||||
(info.ultimate ? 1 : 0, info.ultimate)
|
||||
(concatStringsSep(" ", info.sigs), !info.sigs.empty())
|
||||
(renderContentAddress(info.ca), (bool) info.ca)
|
||||
|
@ -1236,7 +1236,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
|
||||
if (hashResult.first != info.narHash)
|
||||
throw Error("hash mismatch importing path '%s';\n specified: %s\n got: %s",
|
||||
printStorePath(info.path), info.narHash.to_string(Base32, true), hashResult.first.to_string(Base32, true));
|
||||
printStorePath(info.path), info.narHash.to_string(HashFormat::Base32, true), hashResult.first.to_string(HashFormat::Base32, true));
|
||||
|
||||
if (hashResult.second != info.narSize)
|
||||
throw Error("size mismatch importing path '%s';\n specified: %s\n got: %s",
|
||||
|
@ -1252,8 +1252,8 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
if (specified.hash != actualHash.hash) {
|
||||
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
|
||||
printStorePath(info.path),
|
||||
specified.hash.to_string(Base32, true),
|
||||
actualHash.hash.to_string(Base32, true));
|
||||
specified.hash.to_string(HashFormat::Base32, true),
|
||||
actualHash.hash.to_string(HashFormat::Base32, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1545,7 +1545,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
|||
for (auto & link : readDirectory(linksDir)) {
|
||||
printMsg(lvlTalkative, "checking contents of '%s'", link.name);
|
||||
Path linkPath = linksDir + "/" + link.name;
|
||||
std::string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
|
||||
std::string hash = hashPath(htSHA256, linkPath).first.to_string(HashFormat::Base32, false);
|
||||
if (hash != link.name) {
|
||||
printError("link '%s' was modified! expected hash '%s', got '%s'",
|
||||
linkPath, link.name, hash);
|
||||
|
@ -1578,7 +1578,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
|||
|
||||
if (info->narHash != nullHash && info->narHash != current.first) {
|
||||
printError("path '%s' was modified! expected hash '%s', got '%s'",
|
||||
printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true));
|
||||
printStorePath(i), info->narHash.to_string(HashFormat::Base32, true), current.first.to_string(HashFormat::Base32, true));
|
||||
if (repair) repairPath(i); else errors = true;
|
||||
} else {
|
||||
|
||||
|
|
|
@ -332,9 +332,9 @@ public:
|
|||
(std::string(info->path.name()))
|
||||
(narInfo ? narInfo->url : "", narInfo != 0)
|
||||
(narInfo ? narInfo->compression : "", narInfo != 0)
|
||||
(narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(Base32, true) : "", narInfo && narInfo->fileHash)
|
||||
(narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(HashFormat::Base32, true) : "", narInfo && narInfo->fileHash)
|
||||
(narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)
|
||||
(info->narHash.to_string(Base32, true))
|
||||
(info->narHash.to_string(HashFormat::Base32, true))
|
||||
(info->narSize)
|
||||
(concatStringsSep(" ", info->shortRefs()))
|
||||
(info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver)
|
||||
|
|
|
@ -105,10 +105,10 @@ std::string NarInfo::to_string(const Store & store) const
|
|||
assert(compression != "");
|
||||
res += "Compression: " + compression + "\n";
|
||||
assert(fileHash && fileHash->type == htSHA256);
|
||||
res += "FileHash: " + fileHash->to_string(Base32, true) + "\n";
|
||||
res += "FileHash: " + fileHash->to_string(HashFormat::Base32, true) + "\n";
|
||||
res += "FileSize: " + std::to_string(fileSize) + "\n";
|
||||
assert(narHash.type == htSHA256);
|
||||
res += "NarHash: " + narHash.to_string(Base32, true) + "\n";
|
||||
res += "NarHash: " + narHash.to_string(HashFormat::Base32, true) + "\n";
|
||||
res += "NarSize: " + std::to_string(narSize) + "\n";
|
||||
|
||||
res += "References: " + concatStringsSep(" ", shortRefs()) + "\n";
|
||||
|
|
|
@ -146,10 +146,10 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
|
|||
contents of the symlink (i.e. the result of readlink()), not
|
||||
the contents of the target (which may not even exist). */
|
||||
Hash hash = hashPath(htSHA256, path).first;
|
||||
debug("'%1%' has hash '%2%'", path, hash.to_string(Base32, true));
|
||||
debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Base32, true));
|
||||
|
||||
/* Check if this is a known hash. */
|
||||
Path linkPath = linksDir + "/" + hash.to_string(Base32, false);
|
||||
Path linkPath = linksDir + "/" + hash.to_string(HashFormat::Base32, false);
|
||||
|
||||
/* Maybe delete the link, if it has been corrupted. */
|
||||
if (pathExists(linkPath)) {
|
||||
|
|
|
@ -12,7 +12,7 @@ std::string ValidPathInfo::fingerprint(const Store & store) const
|
|||
store.printStorePath(path));
|
||||
return
|
||||
"1;" + store.printStorePath(path) + ";"
|
||||
+ narHash.to_string(Base32, true) + ";"
|
||||
+ narHash.to_string(HashFormat::Base32, true) + ";"
|
||||
+ std::to_string(narSize) + ";"
|
||||
+ concatStringsSep(",", store.printStorePathSet(references));
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ void ValidPathInfo::write(
|
|||
if (includePath)
|
||||
sink << store.printStorePath(path);
|
||||
sink << (deriver ? store.printStorePath(*deriver) : "")
|
||||
<< narHash.to_string(Base16, false);
|
||||
<< narHash.to_string(HashFormat::Base16, false);
|
||||
WorkerProto::write(store,
|
||||
WorkerProto::WriteConn { .to = sink },
|
||||
references);
|
||||
|
|
|
@ -35,7 +35,7 @@ StorePath::StorePath(std::string_view _baseName)
|
|||
}
|
||||
|
||||
StorePath::StorePath(const Hash & hash, std::string_view _name)
|
||||
: baseName((hash.to_string(Base32, false) + "-").append(std::string(_name)))
|
||||
: baseName((hash.to_string(HashFormat::Base32, false) + "-").append(std::string(_name)))
|
||||
{
|
||||
checkName(baseName, name());
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ struct DrvOutput {
|
|||
std::string to_string() const;
|
||||
|
||||
std::string strHash() const
|
||||
{ return drvHash.to_string(Base16, true); }
|
||||
{ return drvHash.to_string(HashFormat::Base16, true); }
|
||||
|
||||
static DrvOutput parse(const std::string &);
|
||||
|
||||
|
|
|
@ -541,7 +541,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
conn->to << WorkerProto::Op::AddToStoreNar
|
||||
<< printStorePath(info.path)
|
||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||
<< info.narHash.to_string(Base16, false);
|
||||
<< info.narHash.to_string(HashFormat::Base16, false);
|
||||
WorkerProto::write(*this, *conn, info.references);
|
||||
conn->to << info.registrationTime << info.narSize
|
||||
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
|
||||
|
|
|
@ -154,7 +154,7 @@ StorePath Store::makeStorePath(std::string_view type,
|
|||
StorePath Store::makeStorePath(std::string_view type,
|
||||
const Hash & hash, std::string_view name) const
|
||||
{
|
||||
return makeStorePath(type, hash.to_string(Base16, true), name);
|
||||
return makeStorePath(type, hash.to_string(HashFormat::Base16, true), name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -192,7 +192,7 @@ StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInf
|
|||
hashString(htSHA256,
|
||||
"fixed:out:"
|
||||
+ makeFileIngestionPrefix(info.method)
|
||||
+ info.hash.to_string(Base16, true) + ":"),
|
||||
+ info.hash.to_string(HashFormat::Base16, true) + ":"),
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
@ -884,7 +884,7 @@ std::string Store::makeValidityRegistration(const StorePathSet & paths,
|
|||
auto info = queryPathInfo(i);
|
||||
|
||||
if (showHash) {
|
||||
s += info->narHash.to_string(Base16, false) + "\n";
|
||||
s += info->narHash.to_string(HashFormat::Base16, false) + "\n";
|
||||
s += fmt("%1%\n", info->narSize);
|
||||
}
|
||||
|
||||
|
@ -938,7 +938,7 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor
|
|||
|
||||
json Store::pathInfoToJSON(const StorePathSet & storePaths,
|
||||
bool includeImpureInfo, bool showClosureSize,
|
||||
Base hashBase,
|
||||
HashFormat hashFormat,
|
||||
AllowInvalidFlag allowInvalid)
|
||||
{
|
||||
json::array_t jsonList = json::array();
|
||||
|
@ -951,7 +951,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
|
|||
|
||||
jsonPath["path"] = printStorePath(info->path);
|
||||
jsonPath["valid"] = true;
|
||||
jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
|
||||
jsonPath["narHash"] = info->narHash.to_string(hashFormat, true);
|
||||
jsonPath["narSize"] = info->narSize;
|
||||
|
||||
{
|
||||
|
@ -993,7 +993,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
|
|||
if (!narInfo->url.empty())
|
||||
jsonPath["url"] = narInfo->url;
|
||||
if (narInfo->fileHash)
|
||||
jsonPath["downloadHash"] = narInfo->fileHash->to_string(hashBase, true);
|
||||
jsonPath["downloadHash"] = narInfo->fileHash->to_string(hashFormat, true);
|
||||
if (narInfo->fileSize)
|
||||
jsonPath["downloadSize"] = narInfo->fileSize;
|
||||
if (showClosureSize)
|
||||
|
|
|
@ -676,7 +676,7 @@ public:
|
|||
*/
|
||||
nlohmann::json pathInfoToJSON(const StorePathSet & storePaths,
|
||||
bool includeImpureInfo, bool showClosureSize,
|
||||
Base hashBase = Base32,
|
||||
HashFormat hashFormat = HashFormat::Base32,
|
||||
AllowInvalidFlag allowInvalid = DisallowInvalid);
|
||||
|
||||
/**
|
||||
|
|
|
@ -111,26 +111,26 @@ static std::string printHash32(const Hash & hash)
|
|||
std::string printHash16or32(const Hash & hash)
|
||||
{
|
||||
assert(hash.type);
|
||||
return hash.to_string(hash.type == htMD5 ? Base16 : Base32, false);
|
||||
return hash.to_string(hash.type == htMD5 ? HashFormat::Base16 : HashFormat::Base32, false);
|
||||
}
|
||||
|
||||
|
||||
std::string Hash::to_string(Base base, bool includeType) const
|
||||
std::string Hash::to_string(HashFormat hashFormat, bool includeType) const
|
||||
{
|
||||
std::string s;
|
||||
if (base == SRI || includeType) {
|
||||
if (hashFormat == HashFormat::SRI || includeType) {
|
||||
s += printHashType(type);
|
||||
s += base == SRI ? '-' : ':';
|
||||
s += hashFormat == HashFormat::SRI ? '-' : ':';
|
||||
}
|
||||
switch (base) {
|
||||
case Base16:
|
||||
switch (hashFormat) {
|
||||
case HashFormat::Base16:
|
||||
s += printHash16(*this);
|
||||
break;
|
||||
case Base32:
|
||||
case HashFormat::Base32:
|
||||
s += printHash32(*this);
|
||||
break;
|
||||
case Base64:
|
||||
case SRI:
|
||||
case HashFormat::Base64:
|
||||
case HashFormat::SRI:
|
||||
s += base64Encode(std::string_view((const char *) hash, hashSize));
|
||||
break;
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht)
|
|||
if (!ht)
|
||||
throw BadHash("empty hash requires explicit hash type");
|
||||
Hash h(*ht);
|
||||
warn("found empty hash, assuming '%s'", h.to_string(SRI, true));
|
||||
warn("found empty hash, assuming '%s'", h.to_string(HashFormat::SRI, true));
|
||||
return h;
|
||||
} else
|
||||
return Hash::parseAny(hashStr, ht);
|
||||
|
@ -386,13 +386,48 @@ Hash compressHash(const Hash & hash, unsigned int newSize)
|
|||
}
|
||||
|
||||
|
||||
std::optional<HashFormat> parseHashFormatOpt(std::string_view hashFormatName)
|
||||
{
|
||||
if (hashFormatName == "base16") return HashFormat::Base16;
|
||||
if (hashFormatName == "base32") return HashFormat::Base32;
|
||||
if (hashFormatName == "base64") return HashFormat::Base64;
|
||||
if (hashFormatName == "sri") return HashFormat::SRI;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
HashFormat parseHashFormat(std::string_view hashFormatName)
|
||||
{
|
||||
auto opt_f = parseHashFormatOpt(hashFormatName);
|
||||
if (opt_f)
|
||||
return *opt_f;
|
||||
throw UsageError("unknown hash format '%1%', expect 'base16', 'base32', 'base64', or 'sri'", hashFormatName);
|
||||
}
|
||||
|
||||
std::string_view printHashFormat(HashFormat HashFormat)
|
||||
{
|
||||
switch (HashFormat) {
|
||||
case HashFormat::Base64:
|
||||
return "base64";
|
||||
case HashFormat::Base32:
|
||||
return "base32";
|
||||
case HashFormat::Base16:
|
||||
return "base16";
|
||||
case HashFormat::SRI:
|
||||
return "sri";
|
||||
default:
|
||||
// illegal hash base enum value internally, as opposed to external input
|
||||
// which should be validated with nice error message.
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<HashType> parseHashTypeOpt(std::string_view s)
|
||||
{
|
||||
if (s == "md5") return htMD5;
|
||||
else if (s == "sha1") return htSHA1;
|
||||
else if (s == "sha256") return htSHA256;
|
||||
else if (s == "sha512") return htSHA512;
|
||||
else return std::optional<HashType> {};
|
||||
if (s == "sha1") return htSHA1;
|
||||
if (s == "sha256") return htSHA256;
|
||||
if (s == "sha512") return htSHA512;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
HashType parseHashType(std::string_view s)
|
||||
|
@ -401,7 +436,7 @@ HashType parseHashType(std::string_view s)
|
|||
if (opt_h)
|
||||
return *opt_h;
|
||||
else
|
||||
throw UsageError("unknown hash algorithm '%1%'", s);
|
||||
throw UsageError("unknown hash algorithm '%1%', expect 'md5', 'sha1', 'sha256', or 'sha512'", s);
|
||||
}
|
||||
|
||||
std::string_view printHashType(HashType ht)
|
||||
|
|
|
@ -23,7 +23,21 @@ extern std::set<std::string> hashTypes;
|
|||
|
||||
extern const std::string base32Chars;
|
||||
|
||||
enum Base : int { Base64, Base32, Base16, SRI };
|
||||
/**
|
||||
* @brief Enumeration representing the hash formats.
|
||||
*/
|
||||
enum struct HashFormat : int {
|
||||
/// @brief Base 64 encoding.
|
||||
/// @see [IETF RFC 4648, section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4).
|
||||
Base64,
|
||||
/// @brief Nix-specific base-32 encoding. @see base32Chars
|
||||
Base32,
|
||||
/// @brief Lowercase hexadecimal encoding. @see base16Chars
|
||||
Base16,
|
||||
/// @brief "<hash algo>:<Base 64 hash>", format of the SRI integrity attribute.
|
||||
/// @see W3C recommendation [Subresource Intergrity](https://www.w3.org/TR/SRI/).
|
||||
SRI
|
||||
};
|
||||
|
||||
|
||||
struct Hash
|
||||
|
@ -114,16 +128,16 @@ public:
|
|||
* or base-64. By default, this is prefixed by the hash type
|
||||
* (e.g. "sha256:").
|
||||
*/
|
||||
std::string to_string(Base base, bool includeType) const;
|
||||
std::string to_string(HashFormat hashFormat, bool includeType) const;
|
||||
|
||||
std::string gitRev() const
|
||||
{
|
||||
return to_string(Base16, false);
|
||||
return to_string(HashFormat::Base16, false);
|
||||
}
|
||||
|
||||
std::string gitShortRev() const
|
||||
{
|
||||
return std::string(to_string(Base16, false), 0, 7);
|
||||
return std::string(to_string(HashFormat::Base16, false), 0, 7);
|
||||
}
|
||||
|
||||
static Hash dummy;
|
||||
|
@ -167,6 +181,21 @@ HashResult hashPath(HashType ht, const Path & path,
|
|||
*/
|
||||
Hash compressHash(const Hash & hash, unsigned int newSize);
|
||||
|
||||
/**
|
||||
* Parse a string representing a hash format.
|
||||
*/
|
||||
HashFormat parseHashFormat(std::string_view hashFormatName);
|
||||
|
||||
/**
|
||||
* std::optional version of parseHashFormat that doesn't throw error.
|
||||
*/
|
||||
std::optional<HashFormat> parseHashFormatOpt(std::string_view hashFormatName);
|
||||
|
||||
/**
|
||||
* The reverse of parseHashFormat.
|
||||
*/
|
||||
std::string_view printHashFormat(HashFormat hashFormat);
|
||||
|
||||
/**
|
||||
* Parse a string representing a hash type.
|
||||
*/
|
||||
|
|
|
@ -18,28 +18,28 @@ namespace nix {
|
|||
// values taken from: https://tools.ietf.org/html/rfc1321
|
||||
auto s1 = "";
|
||||
auto hash = hashString(HashType::htMD5, s1);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e");
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e");
|
||||
}
|
||||
|
||||
TEST(hashString, testKnownMD5Hashes2) {
|
||||
// values taken from: https://tools.ietf.org/html/rfc1321
|
||||
auto s2 = "abc";
|
||||
auto hash = hashString(HashType::htMD5, s2);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72");
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72");
|
||||
}
|
||||
|
||||
TEST(hashString, testKnownSHA1Hashes1) {
|
||||
// values taken from: https://tools.ietf.org/html/rfc3174
|
||||
auto s = "abc";
|
||||
auto hash = hashString(HashType::htSHA1, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:a9993e364706816aba3e25717850c26c9cd0d89d");
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),"sha1:a9993e364706816aba3e25717850c26c9cd0d89d");
|
||||
}
|
||||
|
||||
TEST(hashString, testKnownSHA1Hashes2) {
|
||||
// values taken from: https://tools.ietf.org/html/rfc3174
|
||||
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
auto hash = hashString(HashType::htSHA1, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1");
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),"sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1");
|
||||
}
|
||||
|
||||
TEST(hashString, testKnownSHA256Hashes1) {
|
||||
|
@ -47,7 +47,7 @@ namespace nix {
|
|||
auto s = "abc";
|
||||
|
||||
auto hash = hashString(HashType::htSHA256, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||
"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace nix {
|
|||
// values taken from: https://tools.ietf.org/html/rfc4634
|
||||
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
auto hash = hashString(HashType::htSHA256, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||
"sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace nix {
|
|||
// values taken from: https://tools.ietf.org/html/rfc4634
|
||||
auto s = "abc";
|
||||
auto hash = hashString(HashType::htSHA512, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||
"sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9"
|
||||
"7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd"
|
||||
"454d4423643ce80e2a9ac94fa54ca49f");
|
||||
|
@ -74,11 +74,26 @@ namespace nix {
|
|||
auto s = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
|
||||
|
||||
auto hash = hashString(HashType::htSHA512, s);
|
||||
ASSERT_EQ(hash.to_string(Base::Base16, true),
|
||||
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||
"sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1"
|
||||
"7299aeadb6889018501d289e4900f7e4331b99dec4b5433a"
|
||||
"c7d329eeb6dd26545e96e55b874be909");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* parseHashFormat, parseHashFormatOpt, printHashFormat
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(hashFormat, testRoundTripPrintParse) {
|
||||
for (const HashFormat hashFormat: { HashFormat::Base64, HashFormat::Base32, HashFormat::Base16, HashFormat::SRI}) {
|
||||
ASSERT_EQ(parseHashFormat(printHashFormat(hashFormat)), hashFormat);
|
||||
ASSERT_EQ(*parseHashFormatOpt(printHashFormat(hashFormat)), hashFormat);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hashFormat, testParseHashFormatOptException) {
|
||||
ASSERT_EQ(parseHashFormatOpt("sha0042"), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
namespace rc {
|
||||
|
|
|
@ -406,7 +406,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||
auto info = store->queryPathInfo(j);
|
||||
if (query == qHash) {
|
||||
assert(info->narHash.type == htSHA256);
|
||||
cout << fmt("%s\n", info->narHash.to_string(Base32, true));
|
||||
cout << fmt("%s\n", info->narHash.to_string(HashFormat::Base32, true));
|
||||
} else if (query == qSize)
|
||||
cout << fmt("%d\n", info->narSize);
|
||||
}
|
||||
|
@ -769,8 +769,8 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
|
|||
if (current.first != info->narHash) {
|
||||
printError("path '%s' was modified! expected hash '%s', got '%s'",
|
||||
store->printStorePath(path),
|
||||
info->narHash.to_string(Base32, true),
|
||||
current.first.to_string(Base32, true));
|
||||
info->narHash.to_string(HashFormat::Base32, true),
|
||||
current.first.to_string(HashFormat::Base32, true));
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +892,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||
out << info->narSize // downloadSize
|
||||
<< info->narSize;
|
||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 4)
|
||||
out << info->narHash.to_string(Base32, true)
|
||||
out << info->narHash.to_string(HashFormat::Base32, true)
|
||||
<< renderContentAddress(info->ca)
|
||||
<< info->sigs;
|
||||
} catch (InvalidPath &) {
|
||||
|
|
|
@ -179,7 +179,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
|||
j["url"] = flake.lockedRef.to_string(); // FIXME: rename to lockedUrl
|
||||
j["locked"] = fetchers::attrsToJSON(flake.lockedRef.toAttrs());
|
||||
if (auto rev = flake.lockedRef.input.getRev())
|
||||
j["revision"] = rev->to_string(Base16, false);
|
||||
j["revision"] = rev->to_string(HashFormat::Base16, false);
|
||||
if (auto dirtyRev = fetchers::maybeGetStrAttr(flake.lockedRef.toAttrs(), "dirtyRev"))
|
||||
j["dirtyRevision"] = *dirtyRev;
|
||||
if (auto revCount = flake.lockedRef.input.getRevCount())
|
||||
|
@ -206,7 +206,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
|||
if (auto rev = flake.lockedRef.input.getRev())
|
||||
logger->cout(
|
||||
ANSI_BOLD "Revision:" ANSI_NORMAL " %s",
|
||||
rev->to_string(Base16, false));
|
||||
rev->to_string(HashFormat::Base16, false));
|
||||
if (auto dirtyRev = fetchers::maybeGetStrAttr(flake.lockedRef.toAttrs(), "dirtyRev"))
|
||||
logger->cout(
|
||||
ANSI_BOLD "Revision:" ANSI_NORMAL " %s",
|
||||
|
@ -1345,7 +1345,7 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON
|
|||
if (json) {
|
||||
auto res = nlohmann::json::object();
|
||||
res["storePath"] = store->printStorePath(tree.storePath);
|
||||
res["hash"] = hash.to_string(SRI, true);
|
||||
res["hash"] = hash.to_string(HashFormat::SRI, true);
|
||||
res["original"] = fetchers::attrsToJSON(resolvedRef.toAttrs());
|
||||
res["locked"] = fetchers::attrsToJSON(lockedRef.toAttrs());
|
||||
logger->cout(res.dump());
|
||||
|
@ -1353,7 +1353,7 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON
|
|||
notice("Downloaded '%s' to '%s' (hash '%s').",
|
||||
lockedRef.to_string(),
|
||||
store->printStorePath(tree.storePath),
|
||||
hash.to_string(SRI, true));
|
||||
hash.to_string(HashFormat::SRI, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ using namespace nix;
|
|||
struct CmdHashBase : Command
|
||||
{
|
||||
FileIngestionMethod mode;
|
||||
Base base = SRI;
|
||||
HashFormat hashFormat = HashFormat::SRI;
|
||||
bool truncate = false;
|
||||
HashType ht = htSHA256;
|
||||
std::vector<std::string> paths;
|
||||
|
@ -22,25 +22,25 @@ struct CmdHashBase : Command
|
|||
addFlag({
|
||||
.longName = "sri",
|
||||
.description = "Print the hash in SRI format.",
|
||||
.handler = {&base, SRI},
|
||||
.handler = {&hashFormat, HashFormat::SRI},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
.longName = "base64",
|
||||
.description = "Print the hash in base-64 format.",
|
||||
.handler = {&base, Base64},
|
||||
.handler = {&hashFormat, HashFormat::Base64},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
.longName = "base32",
|
||||
.description = "Print the hash in base-32 (Nix-specific) format.",
|
||||
.handler = {&base, Base32},
|
||||
.handler = {&hashFormat, HashFormat::Base32},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
.longName = "base16",
|
||||
.description = "Print the hash in base-16 format.",
|
||||
.handler = {&base, Base16},
|
||||
.handler = {&hashFormat, HashFormat::Base16},
|
||||
});
|
||||
|
||||
addFlag(Flag::mkHashTypeFlag("type", &ht));
|
||||
|
@ -94,18 +94,18 @@ struct CmdHashBase : Command
|
|||
|
||||
Hash h = hashSink->finish().first;
|
||||
if (truncate && h.hashSize > 20) h = compressHash(h, 20);
|
||||
logger->cout(h.to_string(base, base == SRI));
|
||||
logger->cout(h.to_string(hashFormat, hashFormat == HashFormat::SRI));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdToBase : Command
|
||||
{
|
||||
Base base;
|
||||
HashFormat hashFormat;
|
||||
std::optional<HashType> ht;
|
||||
std::vector<std::string> args;
|
||||
|
||||
CmdToBase(Base base) : base(base)
|
||||
CmdToBase(HashFormat hashFormat) : hashFormat(hashFormat)
|
||||
{
|
||||
addFlag(Flag::mkHashTypeOptFlag("type", &ht));
|
||||
expectArgs("strings", &args);
|
||||
|
@ -114,16 +114,16 @@ struct CmdToBase : Command
|
|||
std::string description() override
|
||||
{
|
||||
return fmt("convert a hash to %s representation",
|
||||
base == Base16 ? "base-16" :
|
||||
base == Base32 ? "base-32" :
|
||||
base == Base64 ? "base-64" :
|
||||
hashFormat == HashFormat::Base16 ? "base-16" :
|
||||
hashFormat == HashFormat::Base32 ? "base-32" :
|
||||
hashFormat == HashFormat::Base64 ? "base-64" :
|
||||
"SRI");
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
for (auto s : args)
|
||||
logger->cout(Hash::parseAny(s, ht).to_string(base, base == SRI));
|
||||
logger->cout(Hash::parseAny(s, ht).to_string(hashFormat, hashFormat == HashFormat::SRI));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -133,10 +133,10 @@ struct CmdHash : NixMultiCommand
|
|||
: MultiCommand({
|
||||
{"file", []() { return make_ref<CmdHashBase>(FileIngestionMethod::Flat);; }},
|
||||
{"path", []() { return make_ref<CmdHashBase>(FileIngestionMethod::Recursive); }},
|
||||
{"to-base16", []() { return make_ref<CmdToBase>(Base16); }},
|
||||
{"to-base32", []() { return make_ref<CmdToBase>(Base32); }},
|
||||
{"to-base64", []() { return make_ref<CmdToBase>(Base64); }},
|
||||
{"to-sri", []() { return make_ref<CmdToBase>(SRI); }},
|
||||
{"to-base16", []() { return make_ref<CmdToBase>(HashFormat::Base16); }},
|
||||
{"to-base32", []() { return make_ref<CmdToBase>(HashFormat::Base32); }},
|
||||
{"to-base64", []() { return make_ref<CmdToBase>(HashFormat::Base64); }},
|
||||
{"to-sri", []() { return make_ref<CmdToBase>(HashFormat::SRI); }},
|
||||
})
|
||||
{ }
|
||||
|
||||
|
@ -162,7 +162,7 @@ static int compatNixHash(int argc, char * * argv)
|
|||
{
|
||||
std::optional<HashType> ht;
|
||||
bool flat = false;
|
||||
Base base = Base16;
|
||||
HashFormat hashFormat = HashFormat::Base16;
|
||||
bool truncate = false;
|
||||
enum { opHash, opTo } op = opHash;
|
||||
std::vector<std::string> ss;
|
||||
|
@ -173,10 +173,10 @@ static int compatNixHash(int argc, char * * argv)
|
|||
else if (*arg == "--version")
|
||||
printVersion("nix-hash");
|
||||
else if (*arg == "--flat") flat = true;
|
||||
else if (*arg == "--base16") base = Base16;
|
||||
else if (*arg == "--base32") base = Base32;
|
||||
else if (*arg == "--base64") base = Base64;
|
||||
else if (*arg == "--sri") base = SRI;
|
||||
else if (*arg == "--base16") hashFormat = HashFormat::Base16;
|
||||
else if (*arg == "--base32") hashFormat = HashFormat::Base32;
|
||||
else if (*arg == "--base64") hashFormat = HashFormat::Base64;
|
||||
else if (*arg == "--sri") hashFormat = HashFormat::SRI;
|
||||
else if (*arg == "--truncate") truncate = true;
|
||||
else if (*arg == "--type") {
|
||||
std::string s = getArg(*arg, arg, end);
|
||||
|
@ -184,19 +184,19 @@ static int compatNixHash(int argc, char * * argv)
|
|||
}
|
||||
else if (*arg == "--to-base16") {
|
||||
op = opTo;
|
||||
base = Base16;
|
||||
hashFormat = HashFormat::Base16;
|
||||
}
|
||||
else if (*arg == "--to-base32") {
|
||||
op = opTo;
|
||||
base = Base32;
|
||||
hashFormat = HashFormat::Base32;
|
||||
}
|
||||
else if (*arg == "--to-base64") {
|
||||
op = opTo;
|
||||
base = Base64;
|
||||
hashFormat = HashFormat::Base64;
|
||||
}
|
||||
else if (*arg == "--to-sri") {
|
||||
op = opTo;
|
||||
base = SRI;
|
||||
hashFormat = HashFormat::SRI;
|
||||
}
|
||||
else if (*arg != "" && arg->at(0) == '-')
|
||||
return false;
|
||||
|
@ -209,14 +209,14 @@ static int compatNixHash(int argc, char * * argv)
|
|||
CmdHashBase cmd(flat ? FileIngestionMethod::Flat : FileIngestionMethod::Recursive);
|
||||
if (!ht.has_value()) ht = htMD5;
|
||||
cmd.ht = ht.value();
|
||||
cmd.base = base;
|
||||
cmd.hashFormat = hashFormat;
|
||||
cmd.truncate = truncate;
|
||||
cmd.paths = ss;
|
||||
cmd.run();
|
||||
}
|
||||
|
||||
else {
|
||||
CmdToBase cmd(base);
|
||||
CmdToBase cmd(hashFormat);
|
||||
cmd.args = ss;
|
||||
if (ht.has_value()) cmd.ht = ht;
|
||||
cmd.run();
|
||||
|
|
|
@ -90,7 +90,7 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
|
|||
std::cout << store->pathInfoToJSON(
|
||||
// FIXME: preserve order?
|
||||
StorePathSet(storePaths.begin(), storePaths.end()),
|
||||
true, showClosureSize, SRI, AllowInvalid).dump();
|
||||
true, showClosureSize, HashFormat::SRI, AllowInvalid).dump();
|
||||
}
|
||||
|
||||
else {
|
||||
|
|
|
@ -310,13 +310,13 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON
|
|||
if (json) {
|
||||
auto res = nlohmann::json::object();
|
||||
res["storePath"] = store->printStorePath(storePath);
|
||||
res["hash"] = hash.to_string(SRI, true);
|
||||
res["hash"] = hash.to_string(HashFormat::SRI, true);
|
||||
logger->cout(res.dump());
|
||||
} else {
|
||||
notice("Downloaded '%s' to '%s' (hash '%s').",
|
||||
url,
|
||||
store->printStorePath(storePath),
|
||||
hash.to_string(SRI, true));
|
||||
hash.to_string(HashFormat::SRI, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -108,8 +108,8 @@ struct CmdVerify : StorePathsCommand
|
|||
act2.result(resCorruptedPath, store->printStorePath(info->path));
|
||||
printError("path '%s' was modified! expected hash '%s', got '%s'",
|
||||
store->printStorePath(info->path),
|
||||
info->narHash.to_string(Base32, true),
|
||||
hash.first.to_string(Base32, true));
|
||||
info->narHash.to_string(HashFormat::Base32, true),
|
||||
hash.first.to_string(HashFormat::Base32, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
tests/functional/lang/eval-okay-convertHash.exp
Normal file
1
tests/functional/lang/eval-okay-convertHash.exp
Normal file
|
@ -0,0 +1 @@
|
|||
{ hashesBase16 = [ "d41d8cd98f00b204e9800998ecf8427e" "6c69ee7f211c640419d5366cc076ae46" "bb3438fbabd460ea6dbd27d153e2233b" "da39a3ee5e6b4b0d3255bfef95601890afd80709" "cd54e8568c1b37cf1e5badb0779bcbf382212189" "6d12e10b1d331dad210e47fd25d4f260802b7e77" "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" "900a4469df00ccbfd0c145c6d1e4b7953dd0afafadd7534e3a4019e8d38fc663" "ad0387b3bd8652f730ca46d25f9c170af0fd589f42e7f23f5a9e6412d97d7e56" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" "9d0886f8c6b389398a16257bc79780fab9831c7fc11c8ab07fa732cb7b348feade382f92617c9c5305fefba0af02ab5fd39a587d330997ff5bd0db19f7666653" "21644b72aa259e5a588cd3afbafb1d4310f4889680f6c83b9d531596a5a284f34dbebff409d23bcc86aee6bad10c891606f075c6f4755cb536da27db5693f3a7" ]; hashesBase32 = [ "3y8bwfr609h3lh9ch0izcqq7fl" "26mrvc0v1nslch8r0w45zywsbc" "1v4gi57l97pmnylq6lmgxkhd5v" "143xibwh31h9bvxzalr0sjvbbvpa6ffs" "i4hj30pkrfdpgc5dbcgcydqviibfhm6d" "fxz2p030yba2bza71qhss79k3l5y24kd" "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73" "0qy6iz9yh6a079757mxdmypx0gcmnzjd3ij5q78bzk00vxll82lh" "0mkygpci4r4yb8zz5rs2kxcgvw0a2yf5zlj6r8qgfll6pnrqf0xd" "0zdl9zrg8r3i9c1g90lgg9ip5ijzv3yhz91i0zzn3r8ap9ws784gkp9dk9j3aglhgf1amqb0pj21mh7h1nxcl18akqvvf7ggqsy30yg" "19ncrpp37dx0nzzjw4k6zaqkb9mzaq2myhgpzh5aff7qqcj5wwdxslg6ixwncm7gyq8l761gwf87fgsh2bwfyr52s53k2dkqvw8c24x" "2kz74snvckxldmmbisz9ikmy031d28cs6xfdbl6rhxx42glpyz4vww4lajrc5akklxwixl0js4g84233pxvmbykiic5m7i5m9r4nr11" ]; hashesBase64 = [ "1B2M2Y8AsgTpgAmY7PhCfg==" "bGnufyEcZAQZ1TZswHauRg==" "uzQ4+6vUYOptvSfRU+IjOw==" "2jmj7l5rSw0yVb/vlWAYkK/YBwk=" "zVToVowbN88eW62wd5vL84IhIYk=" "bRLhCx0zHa0hDkf9JdTyYIArfnc=" "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=" "kApEad8AzL/QwUXG0eS3lT3Qr6+t11NOOkAZ6NOPxmM=" "rQOHs72GUvcwykbSX5wXCvD9WJ9C5/I/Wp5kEtl9flY=" "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==" "nQiG+MaziTmKFiV7x5eA+rmDHH/BHIqwf6cyy3s0j+reOC+SYXycUwX++6CvAqtf05pYfTMJl/9b0NsZ92ZmUw==" "IWRLcqolnlpYjNOvuvsdQxD0iJaA9sg7nVMVlqWihPNNvr/0CdI7zIau5rrRDIkWBvB1xvR1XLU22ifbVpPzpw==" ]; hashesSRI = [ "md5-1B2M2Y8AsgTpgAmY7PhCfg==" "md5-bGnufyEcZAQZ1TZswHauRg==" "md5-uzQ4+6vUYOptvSfRU+IjOw==" "sha1-2jmj7l5rSw0yVb/vlWAYkK/YBwk=" "sha1-zVToVowbN88eW62wd5vL84IhIYk=" "sha1-bRLhCx0zHa0hDkf9JdTyYIArfnc=" "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=" "sha256-kApEad8AzL/QwUXG0eS3lT3Qr6+t11NOOkAZ6NOPxmM=" "sha256-rQOHs72GUvcwykbSX5wXCvD9WJ9C5/I/Wp5kEtl9flY=" "sha512-z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==" "sha512-nQiG+MaziTmKFiV7x5eA+rmDHH/BHIqwf6cyy3s0j+reOC+SYXycUwX++6CvAqtf05pYfTMJl/9b0NsZ92ZmUw==" "sha512-IWRLcqolnlpYjNOvuvsdQxD0iJaA9sg7nVMVlqWihPNNvr/0CdI7zIau5rrRDIkWBvB1xvR1XLU22ifbVpPzpw==" ]; }
|
31
tests/functional/lang/eval-okay-convertHash.nix
Normal file
31
tests/functional/lang/eval-okay-convertHash.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
let
|
||||
hashAlgos = [ "md5" "md5" "md5" "sha1" "sha1" "sha1" "sha256" "sha256" "sha256" "sha512" "sha512" "sha512" ];
|
||||
hashesBase16 = import ./eval-okay-hashstring.exp;
|
||||
map2 = f: { fsts, snds }: if fsts == [ ] then [ ] else [ (f (builtins.head fsts) (builtins.head snds)) ] ++ map2 f { fsts = builtins.tail fsts; snds = builtins.tail snds; };
|
||||
map2' = f: fsts: snds: map2 f { inherit fsts snds; };
|
||||
getOutputHashes = hashes: {
|
||||
hashesBase16 = map2' (hashAlgo: hash: builtins.convertHash { inherit hash hashAlgo; toHashFormat = "base16";}) hashAlgos hashes;
|
||||
hashesBase32 = map2' (hashAlgo: hash: builtins.convertHash { inherit hash hashAlgo; toHashFormat = "base32";}) hashAlgos hashes;
|
||||
hashesBase64 = map2' (hashAlgo: hash: builtins.convertHash { inherit hash hashAlgo; toHashFormat = "base64";}) hashAlgos hashes;
|
||||
hashesSRI = map2' (hashAlgo: hash: builtins.convertHash { inherit hash hashAlgo; toHashFormat = "sri" ;}) hashAlgos hashes;
|
||||
};
|
||||
getOutputHashesColon = hashes: {
|
||||
hashesBase16 = map2' (hashAlgo: hashBody: builtins.convertHash { hash = hashAlgo + ":" + hashBody; toHashFormat = "base16";}) hashAlgos hashes;
|
||||
hashesBase32 = map2' (hashAlgo: hashBody: builtins.convertHash { hash = hashAlgo + ":" + hashBody; toHashFormat = "base32";}) hashAlgos hashes;
|
||||
hashesBase64 = map2' (hashAlgo: hashBody: builtins.convertHash { hash = hashAlgo + ":" + hashBody; toHashFormat = "base64";}) hashAlgos hashes;
|
||||
hashesSRI = map2' (hashAlgo: hashBody: builtins.convertHash { hash = hashAlgo + ":" + hashBody; toHashFormat = "sri" ;}) hashAlgos hashes;
|
||||
};
|
||||
outputHashes = getOutputHashes hashesBase16;
|
||||
in
|
||||
# map2'`
|
||||
assert map2' (s1: s2: s1 + s2) [ "a" "b" ] [ "c" "d" ] == [ "ac" "bd" ];
|
||||
# hashesBase16
|
||||
assert outputHashes.hashesBase16 == hashesBase16;
|
||||
# standard SRI hashes
|
||||
assert outputHashes.hashesSRI == (map2' (hashAlgo: hashBody: hashAlgo + "-" + hashBody) hashAlgos outputHashes.hashesBase64);
|
||||
# without prefix
|
||||
assert builtins.all (x: getOutputHashes x == outputHashes) (builtins.attrValues outputHashes);
|
||||
# colon-separated.
|
||||
# Note that colon prefix must not be applied to the standard SRI. e.g. "sha256:sha256-..." is illegal.
|
||||
assert builtins.all (x: getOutputHashesColon x == outputHashes) (with outputHashes; [ hashesBase16 hashesBase32 hashesBase64 ]);
|
||||
outputHashes
|
Loading…
Reference in a new issue