Compare commits
37 Commits
add-all-ou
...
2.20.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edcb3430ef | ||
|
|
15c0a7b2ce | ||
|
|
2e78ef5612 | ||
|
|
7599d4bbed | ||
|
|
8a8172cd2b | ||
|
|
7b45cc30a1 | ||
|
|
e52d384766 | ||
|
|
0b32c8763b | ||
|
|
adb1d56862 | ||
|
|
28dd392948 | ||
|
|
7f02d17881 | ||
|
|
ce23ef4a77 | ||
|
|
98c22e8798 | ||
|
|
02f7025deb | ||
|
|
0571e6e9b4 | ||
|
|
982d07d009 | ||
|
|
7f66d4f167 | ||
|
|
52e53a2983 | ||
|
|
c5a8b9050c | ||
|
|
86dfeebb3d | ||
|
|
8f14bf4712 | ||
|
|
10e1579c81 | ||
|
|
b6bf4a80d8 | ||
|
|
955be03476 | ||
|
|
aab4a17258 | ||
|
|
df2156a5d2 | ||
|
|
db82034fee | ||
|
|
b5947b55e2 | ||
|
|
60fb31a87d | ||
|
|
b35958bd7c | ||
|
|
f36832ce13 | ||
|
|
0f4db25957 | ||
|
|
8f42912c80 | ||
|
|
a4a4ef9b53 | ||
|
|
5ad5b4447c | ||
|
|
1b2b240f22 | ||
|
|
16e1ff3bcb |
25
Makefile
25
Makefile
@@ -47,6 +47,17 @@ makefiles += \
|
||||
tests/functional/plugins/local.mk
|
||||
endif
|
||||
|
||||
# Some makefiles require access to built programs and must be included late.
|
||||
makefiles-late =
|
||||
|
||||
ifeq ($(ENABLE_DOC_GEN), yes)
|
||||
makefiles-late += doc/manual/local.mk
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_INTERNAL_API_DOCS), yes)
|
||||
makefiles-late += doc/internal-api/local.mk
|
||||
endif
|
||||
|
||||
# Miscellaneous global Flags
|
||||
|
||||
OPTIMIZE = 1
|
||||
@@ -95,24 +106,16 @@ installcheck:
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
# Documentation or else fallback stub rules.
|
||||
#
|
||||
# The documentation makefiles be included after `mk/lib.mk` so rules
|
||||
# refer to variables defined by `mk/lib.mk`. Rules are not "lazy" like
|
||||
# variables, unfortunately.
|
||||
# Documentation fallback stub rules.
|
||||
|
||||
ifeq ($(ENABLE_DOC_GEN), yes)
|
||||
$(eval $(call include-sub-makefile, doc/manual/local.mk))
|
||||
else
|
||||
ifneq ($(ENABLE_DOC_GEN), yes)
|
||||
.PHONY: manual-html manpages
|
||||
manual-html manpages:
|
||||
@echo "Generated docs are disabled. Configure without '--disable-doc-gen', or avoid calling 'make manpages' and 'make manual-html'."
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_INTERNAL_API_DOCS), yes)
|
||||
$(eval $(call include-sub-makefile, doc/internal-api/local.mk))
|
||||
else
|
||||
ifneq ($(ENABLE_INTERNAL_API_DOCS), yes)
|
||||
.PHONY: internal-api-html
|
||||
internal-api-html:
|
||||
@echo "Internal API docs are disabled. Configure with '--enable-internal-api-docs', or avoid calling 'make internal-api-html'."
|
||||
|
||||
10
doc/manual/rl-next/leading-period.md
Normal file
10
doc/manual/rl-next/leading-period.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
synopsis: Store paths are allowed to start with `.`
|
||||
issues: 912
|
||||
prs: 9867 9091 9095 9120 9121 9122 9130 9219 9224
|
||||
---
|
||||
|
||||
Leading periods were allowed by accident in Nix 2.4. The Nix team has considered this to be a bug, but this behavior has since been relied on by users, leading to unnecessary difficulties.
|
||||
From now on, leading periods are officially, definitively supported. The names `.` and `..` are disallowed, as well as those starting with `.-` or `..-`.
|
||||
|
||||
Nix versions that denied leading periods are documented [in the issue](https://github.com/NixOS/nix/issues/912#issuecomment-1919583286).
|
||||
@@ -19,7 +19,7 @@
|
||||
inherit (import (builtins.fetchTarball { url = "https://github.com/NixOS/nix/archive/1bdcd7fc8a6a40b2e805bad759b36e64e911036b.tar.gz"; sha256 = "sha256:14ljlpdsp4x7h1fkhbmc4bd3vsqnx8zdql4h3037wh09ad6a0893"; }))
|
||||
fileset;
|
||||
|
||||
officialRelease = false;
|
||||
officialRelease = true;
|
||||
|
||||
# Set to true to build the release notes for the next release.
|
||||
buildUnreleasedNotes = false;
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
nix =
|
||||
let
|
||||
officialRelease = false;
|
||||
officialRelease = true;
|
||||
versionSuffix =
|
||||
if officialRelease
|
||||
then ""
|
||||
@@ -186,7 +186,7 @@
|
||||
stdenv
|
||||
versionSuffix
|
||||
;
|
||||
officialRelease = false;
|
||||
officialRelease = true;
|
||||
boehmgc = final.boehmgc-nix;
|
||||
libgit2 = final.libgit2-nix;
|
||||
busybox-sandbox-shell = final.busybox-sandbox-shell or final.default-busybox-sandbox-shell;
|
||||
|
||||
@@ -97,6 +97,10 @@ $(foreach test-group, $(install-tests-groups), \
|
||||
$(eval $(call run-test,$(test),$(install_test_init))) \
|
||||
$(eval $(test-group).test-group: $(test).test)))
|
||||
|
||||
# Include makefiles requiring built programs.
|
||||
$(foreach mf, $(makefiles-late), $(eval $(call include-sub-makefile,$(mf))))
|
||||
|
||||
|
||||
$(foreach file, $(man-pages), $(eval $(call install-data-in, $(file), $(mandir)/man$(patsubst .%,%,$(suffix $(file))))))
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
|
||||
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||
{
|
||||
if (v.type() == nPath) {
|
||||
auto storePath = fetchToStore(*state->store, v.path());
|
||||
auto storePath = fetchToStore(*state->store, v.path(), FetchMode::Copy);
|
||||
return {{
|
||||
.path = DerivedPath::Opaque {
|
||||
.path = std::move(storePath),
|
||||
|
||||
@@ -507,13 +507,13 @@ EvalState::~EvalState()
|
||||
void EvalState::allowPath(const Path & path)
|
||||
{
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->allowPath(CanonPath(path));
|
||||
rootFS2->allowPrefix(CanonPath(path));
|
||||
}
|
||||
|
||||
void EvalState::allowPath(const StorePath & storePath)
|
||||
{
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->allowPath(CanonPath(store->toRealPath(storePath)));
|
||||
rootFS2->allowPrefix(CanonPath(store->toRealPath(storePath)));
|
||||
}
|
||||
|
||||
void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v)
|
||||
@@ -2338,7 +2338,14 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
||||
auto dstPath = i != srcToStore.end()
|
||||
? i->second
|
||||
: [&]() {
|
||||
auto dstPath = fetchToStore(*store, path, path.baseName(), FileIngestionMethod::Recursive, nullptr, repair);
|
||||
auto dstPath = fetchToStore(
|
||||
*store,
|
||||
path.resolveSymlinks(),
|
||||
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
path.baseName(),
|
||||
FileIngestionMethod::Recursive,
|
||||
nullptr,
|
||||
repair);
|
||||
allowPath(dstPath);
|
||||
srcToStore.insert_or_assign(path, dstPath);
|
||||
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
|
||||
|
||||
@@ -107,7 +107,7 @@ LockFile::LockFile(const nlohmann::json & json, const Path & path)
|
||||
std::string inputKey = i.value();
|
||||
auto k = nodeMap.find(inputKey);
|
||||
if (k == nodeMap.end()) {
|
||||
auto nodes = json["nodes"];
|
||||
auto & nodes = json["nodes"];
|
||||
auto jsonNode2 = nodes.find(inputKey);
|
||||
if (jsonNode2 == nodes.end())
|
||||
throw Error("lock file references missing node '%s'", inputKey);
|
||||
|
||||
@@ -118,7 +118,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context)
|
||||
return res;
|
||||
}
|
||||
|
||||
static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, bool resolveSymlinks = true)
|
||||
static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, std::optional<SymlinkResolution> resolveSymlinks = SymlinkResolution::Full)
|
||||
{
|
||||
NixStringContext context;
|
||||
|
||||
@@ -130,7 +130,7 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, bo
|
||||
auto realPath = state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context);
|
||||
path = {path.accessor, CanonPath(realPath)};
|
||||
}
|
||||
return resolveSymlinks ? path.resolveSymlinks() : path;
|
||||
return resolveSymlinks ? path.resolveSymlinks(*resolveSymlinks) : path;
|
||||
} catch (Error & e) {
|
||||
e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
|
||||
throw;
|
||||
@@ -170,7 +170,7 @@ static void mkOutputString(
|
||||
argument. */
|
||||
static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * vScope, Value & v)
|
||||
{
|
||||
auto path = realisePath(state, pos, vPath, false);
|
||||
auto path = realisePath(state, pos, vPath, std::nullopt);
|
||||
auto path2 = path.path.abs();
|
||||
|
||||
// FIXME
|
||||
@@ -1534,13 +1534,16 @@ static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args,
|
||||
try {
|
||||
auto & arg = *args[0];
|
||||
|
||||
auto path = realisePath(state, pos, arg);
|
||||
|
||||
/* SourcePath doesn't know about trailing slash. */
|
||||
state.forceValue(arg, pos);
|
||||
auto mustBeDir = arg.type() == nString
|
||||
&& (arg.string_view().ends_with("/")
|
||||
|| arg.string_view().ends_with("/."));
|
||||
|
||||
auto symlinkResolution =
|
||||
mustBeDir ? SymlinkResolution::Full : SymlinkResolution::Ancestors;
|
||||
auto path = realisePath(state, pos, arg, symlinkResolution);
|
||||
|
||||
auto st = path.maybeLstat();
|
||||
auto exists = st && (!mustBeDir || st->type == SourceAccessor::tDirectory);
|
||||
v.mkBool(exists);
|
||||
@@ -1777,7 +1780,7 @@ static std::string_view fileTypeToString(InputAccessor::Type type)
|
||||
|
||||
static void prim_readFileType(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
auto path = realisePath(state, pos, *args[0], false);
|
||||
auto path = realisePath(state, pos, *args[0], std::nullopt);
|
||||
/* Retrieve the directory entry type and stringize it. */
|
||||
v.mkString(fileTypeToString(path.lstat().type));
|
||||
}
|
||||
@@ -2241,7 +2244,14 @@ static void addPath(
|
||||
});
|
||||
|
||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||
auto dstPath = fetchToStore(*state.store, path, name, method, filter.get(), state.repair);
|
||||
auto dstPath = fetchToStore(
|
||||
*state.store,
|
||||
path.resolveSymlinks(),
|
||||
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
name,
|
||||
method,
|
||||
filter.get(),
|
||||
state.repair);
|
||||
if (expectedHash && expectedStorePath != dstPath)
|
||||
state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path));
|
||||
state.allowAndSetStorePathString(dstPath, v);
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace nix {
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
const SourcePath & path,
|
||||
FetchMode mode,
|
||||
std::string_view name,
|
||||
ContentAddressMethod method,
|
||||
PathFilter * filter,
|
||||
@@ -47,18 +48,19 @@ StorePath fetchToStore(
|
||||
} else
|
||||
debug("source path '%s' is uncacheable", path);
|
||||
|
||||
Activity act(*logger, lvlChatty, actUnknown, fmt("copying '%s' to the store", path));
|
||||
Activity act(*logger, lvlChatty, actUnknown,
|
||||
fmt(mode == FetchMode::DryRun ? "hashing '%s'" : "copying '%s' to the store", path));
|
||||
|
||||
auto filter2 = filter ? *filter : defaultPathFilter;
|
||||
|
||||
auto storePath =
|
||||
settings.readOnlyMode
|
||||
mode == FetchMode::DryRun
|
||||
? store.computeStorePath(
|
||||
name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2).first
|
||||
: store.addToStore(
|
||||
name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2, repair);
|
||||
|
||||
if (cacheKey)
|
||||
if (cacheKey && mode == FetchMode::Copy)
|
||||
fetchers::getCache()->add(store, *cacheKey, {}, storePath, true);
|
||||
|
||||
return storePath;
|
||||
|
||||
@@ -8,12 +8,15 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
enum struct FetchMode { DryRun, Copy };
|
||||
|
||||
/**
|
||||
* Copy the `path` to the Nix store.
|
||||
*/
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
const SourcePath & path,
|
||||
FetchMode mode,
|
||||
std::string_view name = "source",
|
||||
ContentAddressMethod method = FileIngestionMethod::Recursive,
|
||||
PathFilter * filter = nullptr,
|
||||
|
||||
@@ -376,7 +376,7 @@ void InputScheme::clone(const Input & input, const Path & destDir) const
|
||||
std::pair<StorePath, Input> InputScheme::fetch(ref<Store> store, const Input & input)
|
||||
{
|
||||
auto [accessor, input2] = getAccessor(store, input);
|
||||
auto storePath = fetchToStore(*store, SourcePath(accessor), input2.getName());
|
||||
auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy, input2.getName());
|
||||
return {storePath, input2};
|
||||
}
|
||||
|
||||
|
||||
@@ -51,33 +51,33 @@ void FilteringInputAccessor::checkAccess(const CanonPath & path)
|
||||
|
||||
struct AllowListInputAccessorImpl : AllowListInputAccessor
|
||||
{
|
||||
std::set<CanonPath> allowedPaths;
|
||||
std::set<CanonPath> allowedPrefixes;
|
||||
|
||||
AllowListInputAccessorImpl(
|
||||
ref<InputAccessor> next,
|
||||
std::set<CanonPath> && allowedPaths,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
MakeNotAllowedError && makeNotAllowedError)
|
||||
: AllowListInputAccessor(SourcePath(next), std::move(makeNotAllowedError))
|
||||
, allowedPaths(std::move(allowedPaths))
|
||||
, allowedPrefixes(std::move(allowedPrefixes))
|
||||
{ }
|
||||
|
||||
bool isAllowed(const CanonPath & path) override
|
||||
{
|
||||
return path.isAllowed(allowedPaths);
|
||||
return path.isAllowed(allowedPrefixes);
|
||||
}
|
||||
|
||||
void allowPath(CanonPath path) override
|
||||
void allowPrefix(CanonPath prefix) override
|
||||
{
|
||||
allowedPaths.insert(std::move(path));
|
||||
allowedPrefixes.insert(std::move(prefix));
|
||||
}
|
||||
};
|
||||
|
||||
ref<AllowListInputAccessor> AllowListInputAccessor::create(
|
||||
ref<InputAccessor> next,
|
||||
std::set<CanonPath> && allowedPaths,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
MakeNotAllowedError && makeNotAllowedError)
|
||||
{
|
||||
return make_ref<AllowListInputAccessorImpl>(next, std::move(allowedPaths), std::move(makeNotAllowedError));
|
||||
return make_ref<AllowListInputAccessorImpl>(next, std::move(allowedPrefixes), std::move(makeNotAllowedError));
|
||||
}
|
||||
|
||||
bool CachingFilteringInputAccessor::isAllowed(const CanonPath & path)
|
||||
|
||||
@@ -54,18 +54,19 @@ struct FilteringInputAccessor : InputAccessor
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapping `InputAccessor` that checks paths against an allow-list.
|
||||
* A wrapping `InputAccessor` that checks paths against a set of
|
||||
* allowed prefixes.
|
||||
*/
|
||||
struct AllowListInputAccessor : public FilteringInputAccessor
|
||||
{
|
||||
/**
|
||||
* Grant access to the specified path.
|
||||
* Grant access to the specified prefix.
|
||||
*/
|
||||
virtual void allowPath(CanonPath path) = 0;
|
||||
virtual void allowPrefix(CanonPath prefix) = 0;
|
||||
|
||||
static ref<AllowListInputAccessor> create(
|
||||
ref<InputAccessor> next,
|
||||
std::set<CanonPath> && allowedPaths,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
MakeNotAllowedError && makeNotAllowedError);
|
||||
|
||||
using FilteringInputAccessor::FilteringInputAccessor;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "fs-input-accessor.hh"
|
||||
#include "input-accessor.hh"
|
||||
#include "filtering-input-accessor.hh"
|
||||
#include "memory-input-accessor.hh"
|
||||
#include "cache.hh"
|
||||
#include "finally.hh"
|
||||
#include "processes.hh"
|
||||
@@ -750,17 +751,21 @@ ref<InputAccessor> GitRepoImpl::getAccessor(const Hash & rev, bool exportIgnore)
|
||||
ref<InputAccessor> GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError)
|
||||
{
|
||||
auto self = ref<GitRepoImpl>(shared_from_this());
|
||||
/* In case of an empty workdir, return an empty in-memory tree. We
|
||||
cannot use AllowListInputAccessor because it would return an
|
||||
error for the root (and we can't add the root to the allow-list
|
||||
since that would allow access to all its children). */
|
||||
ref<InputAccessor> fileAccessor =
|
||||
AllowListInputAccessor::create(
|
||||
makeFSInputAccessor(path),
|
||||
std::set<CanonPath> { wd.files },
|
||||
std::move(makeNotAllowedError));
|
||||
if (exportIgnore) {
|
||||
wd.files.empty()
|
||||
? makeEmptyInputAccessor()
|
||||
: AllowListInputAccessor::create(
|
||||
makeFSInputAccessor(path),
|
||||
std::set<CanonPath> { wd.files },
|
||||
std::move(makeNotAllowedError)).cast<InputAccessor>();
|
||||
if (exportIgnore)
|
||||
return make_ref<GitExportIgnoreInputAccessor>(self, fileAccessor, std::nullopt);
|
||||
}
|
||||
else {
|
||||
else
|
||||
return fileAccessor;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<GitRepoImpl::Submodule, Hash>> GitRepoImpl::getSubmodules(const Hash & rev, bool exportIgnore)
|
||||
|
||||
@@ -158,6 +158,8 @@ std::vector<PublicKey> getPublicKeys(const Attrs & attrs)
|
||||
|
||||
} // end namespace
|
||||
|
||||
static const Hash nullRev{HashAlgorithm::SHA1};
|
||||
|
||||
struct GitInputScheme : InputScheme
|
||||
{
|
||||
std::optional<Input> inputFromURL(const ParsedURL & url, bool requireTree) const override
|
||||
@@ -708,10 +710,12 @@ struct GitInputScheme : InputScheme
|
||||
if (auto ref = repo->getWorkdirRef())
|
||||
input.attrs.insert_or_assign("ref", *ref);
|
||||
|
||||
auto rev = repoInfo.workdirInfo.headRev.value();
|
||||
/* Return a rev of 000... if there are no commits yet. */
|
||||
auto rev = repoInfo.workdirInfo.headRev.value_or(nullRev);
|
||||
|
||||
input.attrs.insert_or_assign("rev", rev.gitRev());
|
||||
input.attrs.insert_or_assign("revCount", getRevCount(repoInfo, repoInfo.url, rev));
|
||||
input.attrs.insert_or_assign("revCount",
|
||||
rev == nullRev ? 0 : getRevCount(repoInfo, repoInfo.url, rev));
|
||||
|
||||
verifyCommit(input, repo);
|
||||
} else {
|
||||
|
||||
@@ -20,4 +20,10 @@ ref<MemoryInputAccessor> makeMemoryInputAccessor()
|
||||
return make_ref<MemoryInputAccessorImpl>();
|
||||
}
|
||||
|
||||
ref<InputAccessor> makeEmptyInputAccessor()
|
||||
{
|
||||
static auto empty = makeMemoryInputAccessor().cast<InputAccessor>();
|
||||
return empty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ struct MemoryInputAccessor : InputAccessor
|
||||
|
||||
ref<MemoryInputAccessor> makeMemoryInputAccessor();
|
||||
|
||||
ref<InputAccessor> makeEmptyInputAccessor();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
||||
writeFile(settings.netrcFile, netrcData, 0600);
|
||||
}
|
||||
|
||||
auto out = get(drv.outputs, "out");
|
||||
if (!out)
|
||||
throw Error("'builtin:fetchurl' requires an 'out' output");
|
||||
|
||||
if (!(drv.type().isFixed() || drv.type().isImpure()))
|
||||
throw Error("'builtin:fetchurl' must be a fixed-output or impure derivation");
|
||||
|
||||
auto getAttr = [&](const std::string & name) {
|
||||
auto i = drv.env.find(name);
|
||||
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
|
||||
@@ -59,13 +66,12 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
||||
};
|
||||
|
||||
/* Try the hashed mirrors first. */
|
||||
if (getAttr("outputHashMode") == "flat")
|
||||
auto dof = std::get_if<DerivationOutput::CAFixed>(&out->raw);
|
||||
if (dof && dof->ca.method.getFileIngestionMethod() == FileIngestionMethod::Flat)
|
||||
for (auto hashedMirror : settings.hashedMirrors.get())
|
||||
try {
|
||||
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
|
||||
std::optional<HashAlgorithm> ht = parseHashAlgoOpt(getAttr("outputHashAlgo"));
|
||||
Hash h = newHashAllowEmpty(getAttr("outputHash"), ht);
|
||||
fetch(hashedMirror + printHashAlgo(h.algo) + "/" + h.to_string(HashFormat::Base16, false));
|
||||
fetch(hashedMirror + printHashAlgo(dof->ca.hash.algo) + "/" + dof->ca.hash.to_string(HashFormat::Base16, false));
|
||||
return;
|
||||
} catch (Error & e) {
|
||||
debug(e.what());
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
static constexpr std::string_view nameRegexStr = R"([0-9a-zA-Z\+\-_\?=][0-9a-zA-Z\+\-\._\?=]*)";
|
||||
|
||||
static constexpr std::string_view nameRegexStr =
|
||||
// This uses a negative lookahead: (?!\.\.?(-|$))
|
||||
// - deny ".", "..", or those strings followed by '-'
|
||||
// - when it's not those, start again at the start of the input and apply the next regex, which is [0-9a-zA-Z\+\-\._\?=]+
|
||||
R"((?!\.\.?(-|$))[0-9a-zA-Z\+\-\._\?=]+)";
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,20 @@ static void checkName(std::string_view path, std::string_view name)
|
||||
if (name.size() > StorePath::MaxPathLen)
|
||||
throw BadStorePath("store path '%s' has a name longer than %d characters",
|
||||
path, StorePath::MaxPathLen);
|
||||
if (name[0] == '.')
|
||||
throw BadStorePath("store path '%s' starts with illegal character '.'", path);
|
||||
// See nameRegexStr for the definition
|
||||
if (name[0] == '.') {
|
||||
// check against "." and "..", followed by end or dash
|
||||
if (name.size() == 1)
|
||||
throw BadStorePath("store path '%s' has invalid name '%s'", path, name);
|
||||
if (name[1] == '-')
|
||||
throw BadStorePath("store path '%s' has invalid name '%s': first dash-separated component must not be '%s'", path, name, ".");
|
||||
if (name[1] == '.') {
|
||||
if (name.size() == 2)
|
||||
throw BadStorePath("store path '%s' has invalid name '%s'", path, name);
|
||||
if (name[2] == '-')
|
||||
throw BadStorePath("store path '%s' has invalid name '%s': first dash-separated component must not be '%s'", path, name, "..");
|
||||
}
|
||||
}
|
||||
for (auto c : name)
|
||||
if (!((c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Template implementations (as opposed to mere declarations).
|
||||
*
|
||||
* This file is an exmample of the "impl.hh" pattern. See the
|
||||
* This file is an example of the "impl.hh" pattern. See the
|
||||
* contributing guide.
|
||||
*
|
||||
* One only needs to include this when one is declaring a
|
||||
|
||||
@@ -84,7 +84,9 @@ void AbstractConfig::reapplyUnknownSettings()
|
||||
void Config::getSettings(std::map<std::string, SettingInfo> & res, bool overriddenOnly)
|
||||
{
|
||||
for (const auto & opt : _settings)
|
||||
if (!opt.second.isAlias && (!overriddenOnly || opt.second.setting->overridden))
|
||||
if (!opt.second.isAlias
|
||||
&& (!overriddenOnly || opt.second.setting->overridden)
|
||||
&& experimentalFeatureSettings.isEnabled(opt.second.setting->experimentalFeature))
|
||||
res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description});
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ bool SourcePath::operator<(const SourcePath & x) const
|
||||
return std::tie(*accessor, path) < std::tie(*x.accessor, x.path);
|
||||
}
|
||||
|
||||
SourcePath SourcePath::resolveSymlinks() const
|
||||
SourcePath SourcePath::resolveSymlinks(SymlinkResolution mode) const
|
||||
{
|
||||
auto res = SourcePath(accessor);
|
||||
|
||||
@@ -72,6 +72,8 @@ SourcePath SourcePath::resolveSymlinks() const
|
||||
for (auto & c : path)
|
||||
todo.push_back(std::string(c));
|
||||
|
||||
bool resolve_last = mode == SymlinkResolution::Full;
|
||||
|
||||
while (!todo.empty()) {
|
||||
auto c = *todo.begin();
|
||||
todo.pop_front();
|
||||
@@ -81,14 +83,16 @@ SourcePath SourcePath::resolveSymlinks() const
|
||||
res.path.pop();
|
||||
else {
|
||||
res.path.push(c);
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
if (resolve_last || !todo.empty()) {
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,26 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Note there is a decent chance this type soon goes away because the problem is solved another way.
|
||||
* See the discussion in https://github.com/NixOS/nix/pull/9985.
|
||||
*/
|
||||
enum class SymlinkResolution {
|
||||
/**
|
||||
* Resolve symlinks in the ancestors only.
|
||||
*
|
||||
* Only the last component of the result is possibly a symlink.
|
||||
*/
|
||||
Ancestors,
|
||||
|
||||
/**
|
||||
* Resolve symlinks fully, realpath(3)-style.
|
||||
*
|
||||
* No component of the result will be a symlink.
|
||||
*/
|
||||
Full,
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction for accessing source files during
|
||||
* evaluation. Currently, it's just a wrapper around `CanonPath` that
|
||||
@@ -102,11 +122,14 @@ struct SourcePath
|
||||
bool operator<(const SourcePath & x) const;
|
||||
|
||||
/**
|
||||
* Resolve any symlinks in this `SourcePath` (including its
|
||||
* parents). The result is a `SourcePath` in which no element is a
|
||||
* symlink.
|
||||
* Resolve any symlinks in this `SourcePath` according to the
|
||||
* given resolution mode.
|
||||
*
|
||||
* @param mode might only be a temporary solution for this.
|
||||
* See the discussion in https://github.com/NixOS/nix/pull/9985.
|
||||
*/
|
||||
SourcePath resolveSymlinks() const;
|
||||
SourcePath resolveSymlinks(
|
||||
SymlinkResolution mode = SymlinkResolution::Full) const;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
||||
|
||||
@@ -31,17 +31,19 @@ source common.sh
|
||||
NIX_CONFIG='
|
||||
experimental-features = nix-command
|
||||
accept-flake-config = true
|
||||
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||
grepQuiet "false" $TEST_ROOT/stdout
|
||||
' expect 1 nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||
[[ $(cat $TEST_ROOT/stdout) = '' ]]
|
||||
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
||||
grepQuiet "error: could not find setting 'accept-flake-config'" $TEST_ROOT/stderr
|
||||
|
||||
# 'flakes' experimental-feature is disabled after, ignore and warn
|
||||
NIX_CONFIG='
|
||||
accept-flake-config = true
|
||||
experimental-features = nix-command
|
||||
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||
grepQuiet "false" $TEST_ROOT/stdout
|
||||
' expect 1 nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||
[[ $(cat $TEST_ROOT/stdout) = '' ]]
|
||||
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
||||
grepQuiet "error: could not find setting 'accept-flake-config'" $TEST_ROOT/stderr
|
||||
|
||||
# 'flakes' experimental-feature is enabled before, process
|
||||
NIX_CONFIG='
|
||||
|
||||
@@ -30,7 +30,10 @@ echo hello >> $TEST_ROOT/worktree/hello
|
||||
rev2=$(git -C $repo rev-parse HEAD)
|
||||
git -C $repo tag -a tag2 -m tag2
|
||||
|
||||
# Fetch a worktree
|
||||
# Check whether fetching in read-only mode works.
|
||||
nix-instantiate --eval -E "builtins.readFile ((builtins.fetchGit file://$TEST_ROOT/worktree) + \"/hello\") == \"utrecht\\n\""
|
||||
|
||||
# Fetch a worktree.
|
||||
unset _NIX_FORCE_HTTP
|
||||
path0=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath")
|
||||
path0_=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = file://$TEST_ROOT/worktree; }).outPath")
|
||||
@@ -268,3 +271,28 @@ git -C "$repo" add hello .gitignore
|
||||
git -C "$repo" commit -m 'Bla1'
|
||||
cd "$repo"
|
||||
path11=$(nix eval --impure --raw --expr "(builtins.fetchGit ./.).outPath")
|
||||
|
||||
# Test a workdir with no commits.
|
||||
empty="$TEST_ROOT/empty"
|
||||
git init "$empty"
|
||||
|
||||
emptyAttrs='{ lastModified = 0; lastModifiedDate = "19700101000000"; narHash = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; rev = "0000000000000000000000000000000000000000"; revCount = 0; shortRev = "0000000"; submodules = false; }'
|
||||
|
||||
[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = $emptyAttrs ]]
|
||||
|
||||
echo foo > "$empty/x"
|
||||
|
||||
[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = $emptyAttrs ]]
|
||||
|
||||
git -C "$empty" add x
|
||||
|
||||
[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = '{ lastModified = 0; lastModifiedDate = "19700101000000"; narHash = "sha256-wzlAGjxKxpaWdqVhlq55q5Gxo4Bf860+kLeEa/v02As="; rev = "0000000000000000000000000000000000000000"; revCount = 0; shortRev = "0000000"; submodules = false; }' ]]
|
||||
|
||||
# Test a repo with an empty commit.
|
||||
git -C "$empty" rm -f x
|
||||
|
||||
git -C "$empty" config user.email "foobar@example.com"
|
||||
git -C "$empty" config user.name "Foobar"
|
||||
git -C "$empty" commit --allow-empty --allow-empty-message --message ""
|
||||
|
||||
nix eval --impure --expr "let attrs = builtins.fetchGit $empty; in assert attrs.lastModified != 0; assert attrs.rev != \"0000000000000000000000000000000000000000\"; assert attrs.revCount == 1; true"
|
||||
|
||||
@@ -78,3 +78,9 @@ outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:
|
||||
|
||||
test -x $outPath/fetchurl.sh
|
||||
test -L $outPath/symlink
|
||||
|
||||
# Make sure that *not* passing a outputHash fails.
|
||||
requireDaemonNewerThan "2.20"
|
||||
expected=100
|
||||
if [[ -v NIX_DAEMON_PACKAGE ]]; then expected=1; fi # work around the daemon not returning a 100 status correctly
|
||||
expectStderr $expected nix-build --expr '{ url }: builtins.derivation { name = "nix-cache-info"; system = "x86_64-linux"; builder = "builtin:fetchurl"; inherit url; outputHashMode = "flat"; }' --argstr url file://$narxz 2>&1 | grep 'must be a fixed-output or impure derivation'
|
||||
|
||||
@@ -63,3 +63,7 @@ path5=$(nix build -L --no-link --json --file ./impure-derivations.nix contentAdd
|
||||
path6=$(nix build -L --no-link --json --file ./impure-derivations.nix inputAddressedAfterCA | jq -r .[].outputs.out)
|
||||
[[ $(< $path6) = X ]]
|
||||
[[ $(< $TEST_ROOT/counter) = 5 ]]
|
||||
|
||||
# Test nix/fetchurl.nix.
|
||||
path7=$(nix build -L --no-link --print-out-paths --expr "import <nix/fetchurl.nix> { impure = true; url = file://$PWD/impure-derivations.sh; }")
|
||||
cmp $path7 $PWD/impure-derivations.sh
|
||||
|
||||
@@ -29,3 +29,6 @@ builtins.pathExists (./lib.nix)
|
||||
&& builtins.pathExists (builtins.toPath { outPath = builtins.toString ./lib.nix; })
|
||||
&& builtins.pathExists ./lib.nix
|
||||
&& !builtins.pathExists ./bla.nix
|
||||
&& builtins.pathExists ./symlink-resolution/foo/overlays/overlay.nix
|
||||
&& builtins.pathExists ./symlink-resolution/broken
|
||||
&& builtins.pathExists (builtins.toString ./symlink-resolution/foo/overlays + "/.")
|
||||
|
||||
1
tests/functional/lang/symlink-resolution/broken
Symbolic link
1
tests/functional/lang/symlink-resolution/broken
Symbolic link
@@ -0,0 +1 @@
|
||||
nonexistent
|
||||
@@ -29,7 +29,8 @@ unset NIX_CONFIG
|
||||
# Create a channel.
|
||||
rm -rf $TEST_ROOT/foo
|
||||
mkdir -p $TEST_ROOT/foo
|
||||
nix copy --to file://$TEST_ROOT/foo?compression="bzip2" $(nix-store -r $(nix-instantiate dependencies.nix))
|
||||
drvPath=$(nix-instantiate dependencies.nix)
|
||||
nix copy --to file://$TEST_ROOT/foo?compression="bzip2" $(nix-store -r "$drvPath")
|
||||
rm -rf $TEST_ROOT/nixexprs
|
||||
mkdir -p $TEST_ROOT/nixexprs
|
||||
cp config.nix dependencies.nix dependencies.builder*.sh $TEST_ROOT/nixexprs/
|
||||
@@ -64,3 +65,5 @@ grepQuiet 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
|
||||
nix-env -i dependencies-top
|
||||
[ -e $TEST_HOME/.nix-profile/foobar ]
|
||||
|
||||
# Test evaluation through a channel symlink (#9882).
|
||||
nix-instantiate '<foo/dependencies.nix>'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <rapidcheck/gen/Arbitrary.h>
|
||||
#include <regex>
|
||||
|
||||
#include <rapidcheck.h>
|
||||
@@ -20,63 +21,60 @@ void showValue(const StorePath & p, std::ostream & os)
|
||||
namespace rc {
|
||||
using namespace nix;
|
||||
|
||||
Gen<StorePathName> Arbitrary<StorePathName>::arbitrary()
|
||||
Gen<char> storePathChar()
|
||||
{
|
||||
auto len = *gen::inRange<size_t>(
|
||||
1,
|
||||
StorePath::MaxPathLen - StorePath::HashLen);
|
||||
|
||||
std::string pre;
|
||||
pre.reserve(len);
|
||||
|
||||
for (size_t c = 0; c < len; ++c) {
|
||||
switch (auto i = *gen::inRange<uint8_t>(0, 10 + 2 * 26 + 6)) {
|
||||
return rc::gen::apply([](uint8_t i) -> char {
|
||||
switch (i) {
|
||||
case 0 ... 9:
|
||||
pre += '0' + i;
|
||||
return '0' + i;
|
||||
case 10 ... 35:
|
||||
pre += 'A' + (i - 10);
|
||||
break;
|
||||
return 'A' + (i - 10);
|
||||
case 36 ... 61:
|
||||
pre += 'a' + (i - 36);
|
||||
break;
|
||||
return 'a' + (i - 36);
|
||||
case 62:
|
||||
pre += '+';
|
||||
break;
|
||||
return '+';
|
||||
case 63:
|
||||
pre += '-';
|
||||
break;
|
||||
return '-';
|
||||
case 64:
|
||||
// names aren't permitted to start with a period,
|
||||
// so just fall through to the next case here
|
||||
if (c != 0) {
|
||||
pre += '.';
|
||||
break;
|
||||
}
|
||||
return '.';
|
||||
case 65:
|
||||
pre += '_';
|
||||
break;
|
||||
return '_';
|
||||
case 66:
|
||||
pre += '?';
|
||||
break;
|
||||
return '?';
|
||||
case 67:
|
||||
pre += '=';
|
||||
break;
|
||||
return '=';
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
gen::inRange<uint8_t>(0, 10 + 2 * 26 + 6));
|
||||
}
|
||||
|
||||
return gen::just(StorePathName {
|
||||
.name = std::move(pre),
|
||||
});
|
||||
Gen<StorePathName> Arbitrary<StorePathName>::arbitrary()
|
||||
{
|
||||
return gen::construct<StorePathName>(
|
||||
gen::suchThat(
|
||||
gen::container<std::string>(storePathChar()),
|
||||
[](const std::string & s) {
|
||||
return
|
||||
!( s == ""
|
||||
|| s == "."
|
||||
|| s == ".."
|
||||
|| s.starts_with(".-")
|
||||
|| s.starts_with("..-")
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Gen<StorePath> Arbitrary<StorePath>::arbitrary()
|
||||
{
|
||||
return gen::just(StorePath {
|
||||
*gen::arbitrary<Hash>(),
|
||||
(*gen::arbitrary<StorePathName>()).name,
|
||||
});
|
||||
return
|
||||
gen::construct<StorePath>(
|
||||
gen::arbitrary<Hash>(),
|
||||
gen::apply([](StorePathName n){ return n.name; }, gen::arbitrary<StorePathName>())
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace rc
|
||||
|
||||
@@ -39,7 +39,12 @@ TEST_DONT_PARSE(double_star, "**")
|
||||
TEST_DONT_PARSE(star_first, "*,foo")
|
||||
TEST_DONT_PARSE(star_second, "foo,*")
|
||||
TEST_DONT_PARSE(bang, "foo!o")
|
||||
TEST_DONT_PARSE(dotfile, ".gitignore")
|
||||
TEST_DONT_PARSE(dot, ".")
|
||||
TEST_DONT_PARSE(dot_dot, "..")
|
||||
TEST_DONT_PARSE(dot_dot_dash, "..-1")
|
||||
TEST_DONT_PARSE(dot_dash, ".-1")
|
||||
TEST_DONT_PARSE(dot_dot_dash_a, "..-a")
|
||||
TEST_DONT_PARSE(dot_dash_a, ".-a")
|
||||
|
||||
#undef TEST_DONT_PARSE
|
||||
|
||||
@@ -63,6 +68,11 @@ TEST_DO_PARSE(underscore, "foo_bar")
|
||||
TEST_DO_PARSE(period, "foo.txt")
|
||||
TEST_DO_PARSE(question_mark, "foo?why")
|
||||
TEST_DO_PARSE(equals_sign, "foo=foo")
|
||||
TEST_DO_PARSE(dotfile, ".gitignore")
|
||||
TEST_DO_PARSE(triple_dot_a, "...a")
|
||||
TEST_DO_PARSE(triple_dot_1, "...1")
|
||||
TEST_DO_PARSE(triple_dot_dash, "...-")
|
||||
TEST_DO_PARSE(triple_dot, "...")
|
||||
|
||||
#undef TEST_DO_PARSE
|
||||
|
||||
@@ -84,6 +94,64 @@ RC_GTEST_FIXTURE_PROP(
|
||||
RC_ASSERT(p == store->parseStorePath(store->printStorePath(p)));
|
||||
}
|
||||
|
||||
|
||||
RC_GTEST_FIXTURE_PROP(
|
||||
StorePathTest,
|
||||
prop_check_regex_eq_parse,
|
||||
())
|
||||
{
|
||||
static auto nameFuzzer =
|
||||
rc::gen::container<std::string>(
|
||||
rc::gen::oneOf(
|
||||
// alphanum, repeated to weigh heavier
|
||||
rc::gen::oneOf(
|
||||
rc::gen::inRange('0', '9'),
|
||||
rc::gen::inRange('a', 'z'),
|
||||
rc::gen::inRange('A', 'Z')
|
||||
),
|
||||
// valid symbols
|
||||
rc::gen::oneOf(
|
||||
rc::gen::just('+'),
|
||||
rc::gen::just('-'),
|
||||
rc::gen::just('.'),
|
||||
rc::gen::just('_'),
|
||||
rc::gen::just('?'),
|
||||
rc::gen::just('=')
|
||||
),
|
||||
// symbols for scary .- and ..- cases, repeated for weight
|
||||
rc::gen::just('.'), rc::gen::just('.'),
|
||||
rc::gen::just('.'), rc::gen::just('.'),
|
||||
rc::gen::just('-'), rc::gen::just('-'),
|
||||
// ascii symbol ranges
|
||||
rc::gen::oneOf(
|
||||
rc::gen::inRange(' ', '/'),
|
||||
rc::gen::inRange(':', '@'),
|
||||
rc::gen::inRange('[', '`'),
|
||||
rc::gen::inRange('{', '~')
|
||||
),
|
||||
// typical whitespace
|
||||
rc::gen::oneOf(
|
||||
rc::gen::just(' '),
|
||||
rc::gen::just('\t'),
|
||||
rc::gen::just('\n'),
|
||||
rc::gen::just('\r')
|
||||
),
|
||||
// some chance of control codes, non-ascii or other garbage we missed
|
||||
rc::gen::inRange('\0', '\xff')
|
||||
));
|
||||
|
||||
auto name = *nameFuzzer;
|
||||
|
||||
std::string path = store->storeDir + "/575s52sh487i0ylmbs9pvi606ljdszr0-" + name;
|
||||
bool parsed = false;
|
||||
try {
|
||||
store->parseStorePath(path);
|
||||
parsed = true;
|
||||
} catch (const BadStorePath &) {
|
||||
}
|
||||
RC_ASSERT(parsed == std::regex_match(std::string { name }, nameRegex));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -11,10 +11,17 @@ using namespace nix;
|
||||
|
||||
Gen<Hash> Arbitrary<Hash>::arbitrary()
|
||||
{
|
||||
Hash hash(HashAlgorithm::SHA1);
|
||||
for (size_t i = 0; i < hash.hashSize; ++i)
|
||||
hash.hash[i] = *gen::arbitrary<uint8_t>();
|
||||
return gen::just(hash);
|
||||
Hash prototype(HashAlgorithm::SHA1);
|
||||
return
|
||||
gen::apply(
|
||||
[](const std::vector<uint8_t> & v) {
|
||||
Hash hash(HashAlgorithm::SHA1);
|
||||
assert(v.size() == hash.hashSize);
|
||||
std::copy(v.begin(), v.end(), hash.hash);
|
||||
return hash;
|
||||
},
|
||||
gen::container<std::vector<uint8_t>>(prototype.hashSize, gen::arbitrary<uint8_t>())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user