forked from lix-project/lix
Merge remote-tracking branch 'upstream/master' into indexed-store-path-outputs
This commit is contained in:
commit
dabb03b8d0
|
@ -177,7 +177,7 @@ fi
|
||||||
PKG_CHECK_MODULES([OPENSSL], [libcrypto], [CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"])
|
PKG_CHECK_MODULES([OPENSSL], [libcrypto], [CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"])
|
||||||
|
|
||||||
|
|
||||||
# Checks for libarchive
|
# Look for libarchive.
|
||||||
PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.1.2], [CXXFLAGS="$LIBARCHIVE_CFLAGS $CXXFLAGS"])
|
PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.1.2], [CXXFLAGS="$LIBARCHIVE_CFLAGS $CXXFLAGS"])
|
||||||
# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed
|
# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed
|
||||||
if test "$shared" != yes; then
|
if test "$shared" != yes; then
|
||||||
|
|
|
@ -7,42 +7,11 @@ Most Nix commands interpret the following environment variables:
|
||||||
`nix-shell`. It can have the values `pure` or `impure`.
|
`nix-shell`. It can have the values `pure` or `impure`.
|
||||||
|
|
||||||
- [`NIX_PATH`]{#env-NIX_PATH}\
|
- [`NIX_PATH`]{#env-NIX_PATH}\
|
||||||
A colon-separated list of directories used to look up Nix
|
A colon-separated list of directories used to look up the location of Nix
|
||||||
expressions enclosed in angle brackets (i.e., `<path>`). For
|
expressions using [paths](../language/values.md#type-path)
|
||||||
instance, the value
|
enclosed in angle brackets (i.e., `<path>`),
|
||||||
|
e.g. `/home/eelco/Dev:/etc/nixos`. It can be extended using the
|
||||||
/home/eelco/Dev:/etc/nixos
|
[`-I` option](./opt-common#opt-I).
|
||||||
|
|
||||||
will cause Nix to look for paths relative to `/home/eelco/Dev` and
|
|
||||||
`/etc/nixos`, in this order. It is also possible to match paths
|
|
||||||
against a prefix. For example, the value
|
|
||||||
|
|
||||||
nixpkgs=/home/eelco/Dev/nixpkgs-branch:/etc/nixos
|
|
||||||
|
|
||||||
will cause Nix to search for `<nixpkgs/path>` in
|
|
||||||
`/home/eelco/Dev/nixpkgs-branch/path` and `/etc/nixos/nixpkgs/path`.
|
|
||||||
|
|
||||||
If a path in the Nix search path starts with `http://` or
|
|
||||||
`https://`, it is interpreted as the URL of a tarball that will be
|
|
||||||
downloaded and unpacked to a temporary location. The tarball must
|
|
||||||
consist of a single top-level directory. For example, setting
|
|
||||||
`NIX_PATH` to
|
|
||||||
|
|
||||||
nixpkgs=https://github.com/NixOS/nixpkgs/archive/master.tar.gz
|
|
||||||
|
|
||||||
tells Nix to download and use the current contents of the
|
|
||||||
`master` branch in the `nixpkgs` repository.
|
|
||||||
|
|
||||||
The URLs of the tarballs from the official nixos.org channels (see
|
|
||||||
[the manual for `nix-channel`](nix-channel.md)) can be abbreviated
|
|
||||||
as `channel:<channel-name>`. For instance, the following two
|
|
||||||
values of `NIX_PATH` are equivalent:
|
|
||||||
|
|
||||||
nixpkgs=channel:nixos-21.05
|
|
||||||
nixpkgs=https://nixos.org/channels/nixos-21.05/nixexprs.tar.xz
|
|
||||||
|
|
||||||
The Nix search path can also be extended using the `-I` option to
|
|
||||||
many Nix commands, which takes precedence over `NIX_PATH`.
|
|
||||||
|
|
||||||
- [`NIX_IGNORE_SYMLINK_STORE`]{#env-NIX_IGNORE_SYMLINK_STORE}\
|
- [`NIX_IGNORE_SYMLINK_STORE`]{#env-NIX_IGNORE_SYMLINK_STORE}\
|
||||||
Normally, the Nix store directory (typically `/nix/store`) is not
|
Normally, the Nix store directory (typically `/nix/store`) is not
|
||||||
|
|
|
@ -32,7 +32,60 @@ MixEvalArgs::MixEvalArgs()
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "include",
|
.longName = "include",
|
||||||
.shortName = 'I',
|
.shortName = 'I',
|
||||||
.description = "Add *path* to the list of locations used to look up `<...>` file names.",
|
.description = R"(
|
||||||
|
Add *path* to the Nix search path. The Nix search path is
|
||||||
|
initialized from the colon-separated [`NIX_PATH`](./env-common.md#env-NIX_PATH) environment
|
||||||
|
variable, and is used to look up the location of Nix expressions using [paths](../language/values.md#type-path) enclosed in angle
|
||||||
|
brackets (i.e., `<nixpkgs>`).
|
||||||
|
|
||||||
|
For instance, passing
|
||||||
|
|
||||||
|
```
|
||||||
|
-I /home/eelco/Dev
|
||||||
|
-I /etc/nixos
|
||||||
|
```
|
||||||
|
|
||||||
|
will cause Nix to look for paths relative to `/home/eelco/Dev` and
|
||||||
|
`/etc/nixos`, in that order. This is equivalent to setting the
|
||||||
|
`NIX_PATH` environment variable to
|
||||||
|
|
||||||
|
```
|
||||||
|
/home/eelco/Dev:/etc/nixos
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to match paths against a prefix. For example,
|
||||||
|
passing
|
||||||
|
|
||||||
|
```
|
||||||
|
-I nixpkgs=/home/eelco/Dev/nixpkgs-branch
|
||||||
|
-I /etc/nixos
|
||||||
|
```
|
||||||
|
|
||||||
|
will cause Nix to search for `<nixpkgs/path>` in
|
||||||
|
`/home/eelco/Dev/nixpkgs-branch/path` and `/etc/nixos/nixpkgs/path`.
|
||||||
|
|
||||||
|
If a path in the Nix search path starts with `http://` or `https://`,
|
||||||
|
it is interpreted as the URL of a tarball that will be downloaded and
|
||||||
|
unpacked to a temporary location. The tarball must consist of a single
|
||||||
|
top-level directory. For example, passing
|
||||||
|
|
||||||
|
```
|
||||||
|
-I nixpkgs=https://github.com/NixOS/nixpkgs/archive/master.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
tells Nix to download and use the current contents of the `master`
|
||||||
|
branch in the `nixpkgs` repository.
|
||||||
|
|
||||||
|
The URLs of the tarballs from the official `nixos.org` channels
|
||||||
|
(see [the manual page for `nix-channel`](nix-channel.md)) can be
|
||||||
|
abbreviated as `channel:<channel-name>`. For instance, the
|
||||||
|
following two flags are equivalent:
|
||||||
|
|
||||||
|
```
|
||||||
|
-I nixpkgs=channel:nixos-21.05
|
||||||
|
-I nixpkgs=https://nixos.org/channels/nixos-21.05/nixexprs.tar.xz
|
||||||
|
```
|
||||||
|
)",
|
||||||
.category = category,
|
.category = category,
|
||||||
.labels = {"path"},
|
.labels = {"path"},
|
||||||
.handler = {[&](std::string s) { searchPath.push_back(s); }}
|
.handler = {[&](std::string s) { searchPath.push_back(s); }}
|
||||||
|
|
|
@ -793,7 +793,8 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
if (file == "-") {
|
if (file == "-") {
|
||||||
auto e = state->parseStdin();
|
auto e = state->parseStdin();
|
||||||
state->eval(e, *vFile);
|
state->eval(e, *vFile);
|
||||||
} else if (file)
|
}
|
||||||
|
else if (file)
|
||||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||||
else {
|
else {
|
||||||
auto e = state->parseExprFromString(*expr, absPath("."));
|
auto e = state->parseExprFromString(*expr, absPath("."));
|
||||||
|
|
|
@ -787,7 +787,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||||
flake::LockFlags {
|
flake::LockFlags {
|
||||||
.updateLockFile = false,
|
.updateLockFile = false,
|
||||||
.useRegistries = !evalSettings.pureEval,
|
.useRegistries = !evalSettings.pureEval,
|
||||||
.allowMutable = !evalSettings.pureEval,
|
.allowUnlocked = !evalSettings.pureEval,
|
||||||
}),
|
}),
|
||||||
v);
|
v);
|
||||||
addAttrsToScope(v);
|
addAttrsToScope(v);
|
||||||
|
|
|
@ -645,17 +645,17 @@ NixInt AttrCursor::getInt()
|
||||||
cachedValue = root->db->getAttr(getKey());
|
cachedValue = root->db->getAttr(getKey());
|
||||||
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
|
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
|
||||||
if (auto i = std::get_if<int_t>(&cachedValue->second)) {
|
if (auto i = std::get_if<int_t>(&cachedValue->second)) {
|
||||||
debug("using cached Integer attribute '%s'", getAttrPathStr());
|
debug("using cached integer attribute '%s'", getAttrPathStr());
|
||||||
return i->x;
|
return i->x;
|
||||||
} else
|
} else
|
||||||
throw TypeError("'%s' is not an Integer", getAttrPathStr());
|
throw TypeError("'%s' is not an integer", getAttrPathStr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & v = forceValue();
|
auto & v = forceValue();
|
||||||
|
|
||||||
if (v.type() != nInt)
|
if (v.type() != nInt)
|
||||||
throw TypeError("'%s' is not an Integer", getAttrPathStr());
|
throw TypeError("'%s' is not an integer", getAttrPathStr());
|
||||||
|
|
||||||
return v.integer;
|
return v.integer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1806,7 +1806,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
Nix attempted to evaluate a function as a top level expression; in
|
Nix attempted to evaluate a function as a top level expression; in
|
||||||
this case it must have its arguments supplied either by default
|
this case it must have its arguments supplied either by default
|
||||||
values, or passed explicitly with '--arg' or '--argstr'. See
|
values, or passed explicitly with '--arg' or '--argstr'. See
|
||||||
https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.)", symbols[i.name],
|
https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbols[i.name],
|
||||||
*fun.lambda.env, *fun.lambda.fun);
|
*fun.lambda.env, *fun.lambda.fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,7 +353,7 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
std::function<void(
|
std::function<void(
|
||||||
const FlakeInputs & flakeInputs,
|
const FlakeInputs & flakeInputs,
|
||||||
std::shared_ptr<Node> node,
|
ref<Node> node,
|
||||||
const InputPath & inputPathPrefix,
|
const InputPath & inputPathPrefix,
|
||||||
std::shared_ptr<const Node> oldNode,
|
std::shared_ptr<const Node> oldNode,
|
||||||
const InputPath & lockRootPath,
|
const InputPath & lockRootPath,
|
||||||
|
@ -362,9 +362,15 @@ LockedFlake lockFlake(
|
||||||
computeLocks;
|
computeLocks;
|
||||||
|
|
||||||
computeLocks = [&](
|
computeLocks = [&](
|
||||||
|
/* The inputs of this node, either from flake.nix or
|
||||||
|
flake.lock. */
|
||||||
const FlakeInputs & flakeInputs,
|
const FlakeInputs & flakeInputs,
|
||||||
std::shared_ptr<Node> node,
|
/* The node whose locks are to be updated.*/
|
||||||
|
ref<Node> node,
|
||||||
|
/* The path to this node in the lock file graph. */
|
||||||
const InputPath & inputPathPrefix,
|
const InputPath & inputPathPrefix,
|
||||||
|
/* The old node, if any, from which locks can be
|
||||||
|
copied. */
|
||||||
std::shared_ptr<const Node> oldNode,
|
std::shared_ptr<const Node> oldNode,
|
||||||
const InputPath & lockRootPath,
|
const InputPath & lockRootPath,
|
||||||
const Path & parentPath,
|
const Path & parentPath,
|
||||||
|
@ -452,7 +458,7 @@ LockedFlake lockFlake(
|
||||||
/* Copy the input from the old lock since its flakeref
|
/* Copy the input from the old lock since its flakeref
|
||||||
didn't change and there is no override from a
|
didn't change and there is no override from a
|
||||||
higher level flake. */
|
higher level flake. */
|
||||||
auto childNode = std::make_shared<LockedNode>(
|
auto childNode = make_ref<LockedNode>(
|
||||||
oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
|
oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
|
||||||
|
|
||||||
node->inputs.insert_or_assign(id, childNode);
|
node->inputs.insert_or_assign(id, childNode);
|
||||||
|
@ -481,7 +487,7 @@ LockedFlake lockFlake(
|
||||||
.isFlake = (*lockedNode)->isFlake,
|
.isFlake = (*lockedNode)->isFlake,
|
||||||
});
|
});
|
||||||
} else if (auto follows = std::get_if<1>(&i.second)) {
|
} else if (auto follows = std::get_if<1>(&i.second)) {
|
||||||
if (! trustLock) {
|
if (!trustLock) {
|
||||||
// It is possible that the flake has changed,
|
// It is possible that the flake has changed,
|
||||||
// so we must confirm all the follows that are in the lock file are also in the flake.
|
// so we must confirm all the follows that are in the lock file are also in the flake.
|
||||||
auto overridePath(inputPath);
|
auto overridePath(inputPath);
|
||||||
|
@ -521,8 +527,8 @@ LockedFlake lockFlake(
|
||||||
this input. */
|
this input. */
|
||||||
debug("creating new input '%s'", inputPathS);
|
debug("creating new input '%s'", inputPathS);
|
||||||
|
|
||||||
if (!lockFlags.allowMutable && !input.ref->input.isLocked())
|
if (!lockFlags.allowUnlocked && !input.ref->input.isLocked())
|
||||||
throw Error("cannot update flake input '%s' in pure mode", inputPathS);
|
throw Error("cannot update unlocked flake input '%s' in pure mode", inputPathS);
|
||||||
|
|
||||||
/* Note: in case of an --override-input, we use
|
/* Note: in case of an --override-input, we use
|
||||||
the *original* ref (input2.ref) for the
|
the *original* ref (input2.ref) for the
|
||||||
|
@ -544,7 +550,7 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
auto inputFlake = getFlake(state, localRef, useRegistries, flakeCache, inputPath);
|
auto inputFlake = getFlake(state, localRef, useRegistries, flakeCache, inputPath);
|
||||||
|
|
||||||
auto childNode = std::make_shared<LockedNode>(inputFlake.lockedRef, ref);
|
auto childNode = make_ref<LockedNode>(inputFlake.lockedRef, ref);
|
||||||
|
|
||||||
node->inputs.insert_or_assign(id, childNode);
|
node->inputs.insert_or_assign(id, childNode);
|
||||||
|
|
||||||
|
@ -564,15 +570,19 @@ LockedFlake lockFlake(
|
||||||
oldLock
|
oldLock
|
||||||
? std::dynamic_pointer_cast<const Node>(oldLock)
|
? std::dynamic_pointer_cast<const Node>(oldLock)
|
||||||
: LockFile::read(
|
: LockFile::read(
|
||||||
inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root,
|
inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root.get_ptr(),
|
||||||
oldLock ? lockRootPath : inputPath, localPath, false);
|
oldLock ? lockRootPath : inputPath,
|
||||||
|
localPath,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
|
auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
|
||||||
state, *input.ref, useRegistries, flakeCache);
|
state, *input.ref, useRegistries, flakeCache);
|
||||||
node->inputs.insert_or_assign(id,
|
|
||||||
std::make_shared<LockedNode>(lockedRef, ref, false));
|
auto childNode = make_ref<LockedNode>(lockedRef, ref, false);
|
||||||
|
|
||||||
|
node->inputs.insert_or_assign(id, childNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,8 +597,13 @@ LockedFlake lockFlake(
|
||||||
auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir, true);
|
auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir, true);
|
||||||
|
|
||||||
computeLocks(
|
computeLocks(
|
||||||
flake.inputs, newLockFile.root, {},
|
flake.inputs,
|
||||||
lockFlags.recreateLockFile ? nullptr : oldLockFile.root, {}, parentPath, false);
|
newLockFile.root,
|
||||||
|
{},
|
||||||
|
lockFlags.recreateLockFile ? nullptr : oldLockFile.root.get_ptr(),
|
||||||
|
{},
|
||||||
|
parentPath,
|
||||||
|
false);
|
||||||
|
|
||||||
for (auto & i : lockFlags.inputOverrides)
|
for (auto & i : lockFlags.inputOverrides)
|
||||||
if (!overridesUsed.count(i.first))
|
if (!overridesUsed.count(i.first))
|
||||||
|
@ -611,9 +626,9 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
if (lockFlags.writeLockFile) {
|
if (lockFlags.writeLockFile) {
|
||||||
if (auto sourcePath = topRef.input.getSourcePath()) {
|
if (auto sourcePath = topRef.input.getSourcePath()) {
|
||||||
if (!newLockFile.isImmutable()) {
|
if (auto unlockedInput = newLockFile.isUnlocked()) {
|
||||||
if (fetchSettings.warnDirty)
|
if (fetchSettings.warnDirty)
|
||||||
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
|
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
||||||
} else {
|
} else {
|
||||||
if (!lockFlags.updateLockFile)
|
if (!lockFlags.updateLockFile)
|
||||||
throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
|
throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
|
||||||
|
@ -737,7 +752,7 @@ static void prim_getFlake(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
.updateLockFile = false,
|
.updateLockFile = false,
|
||||||
.writeLockFile = false,
|
.writeLockFile = false,
|
||||||
.useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries,
|
.useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries,
|
||||||
.allowMutable = !evalSettings.pureEval,
|
.allowUnlocked = !evalSettings.pureEval,
|
||||||
}),
|
}),
|
||||||
v);
|
v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,11 +108,11 @@ struct LockFlags
|
||||||
|
|
||||||
bool applyNixConfig = false;
|
bool applyNixConfig = false;
|
||||||
|
|
||||||
/* Whether mutable flake references (i.e. those without a Git
|
/* Whether unlocked flake references (i.e. those without a Git
|
||||||
revision or similar) without a corresponding lock are
|
revision or similar) without a corresponding lock are
|
||||||
allowed. Mutable flake references with a lock are always
|
allowed. Unlocked flake references with a lock are always
|
||||||
allowed. */
|
allowed. */
|
||||||
bool allowMutable = true;
|
bool allowUnlocked = true;
|
||||||
|
|
||||||
/* Whether to commit changes to flake.lock. */
|
/* Whether to commit changes to flake.lock. */
|
||||||
bool commitLockFile = false;
|
bool commitLockFile = false;
|
||||||
|
|
|
@ -35,7 +35,7 @@ typedef std::string FlakeId;
|
||||||
|
|
||||||
struct FlakeRef
|
struct FlakeRef
|
||||||
{
|
{
|
||||||
/* fetcher-specific representation of the input, sufficient to
|
/* Fetcher-specific representation of the input, sufficient to
|
||||||
perform the fetch operation. */
|
perform the fetch operation. */
|
||||||
fetchers::Input input;
|
fetchers::Input input;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ FlakeRef getFlakeRef(
|
||||||
}
|
}
|
||||||
|
|
||||||
LockedNode::LockedNode(const nlohmann::json & json)
|
LockedNode::LockedNode(const nlohmann::json & json)
|
||||||
: lockedRef(getFlakeRef(json, "locked", "info"))
|
: lockedRef(getFlakeRef(json, "locked", "info")) // FIXME: remove "info"
|
||||||
, originalRef(getFlakeRef(json, "original", nullptr))
|
, originalRef(getFlakeRef(json, "original", nullptr))
|
||||||
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
||||||
{
|
{
|
||||||
|
@ -49,15 +49,15 @@ std::shared_ptr<Node> LockFile::findInput(const InputPath & path)
|
||||||
{
|
{
|
||||||
auto pos = root;
|
auto pos = root;
|
||||||
|
|
||||||
if (!pos) return {};
|
|
||||||
|
|
||||||
for (auto & elem : path) {
|
for (auto & elem : path) {
|
||||||
if (auto i = get(pos->inputs, elem)) {
|
if (auto i = get(pos->inputs, elem)) {
|
||||||
if (auto node = std::get_if<0>(&*i))
|
if (auto node = std::get_if<0>(&*i))
|
||||||
pos = *node;
|
pos = *node;
|
||||||
else if (auto follows = std::get_if<1>(&*i)) {
|
else if (auto follows = std::get_if<1>(&*i)) {
|
||||||
pos = findInput(*follows);
|
if (auto p = findInput(*follows))
|
||||||
if (!pos) return {};
|
pos = ref(p);
|
||||||
|
else
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
return {};
|
return {};
|
||||||
|
@ -72,7 +72,7 @@ LockFile::LockFile(const nlohmann::json & json, const Path & path)
|
||||||
if (version < 5 || version > 7)
|
if (version < 5 || version > 7)
|
||||||
throw Error("lock file '%s' has unsupported version %d", path, version);
|
throw Error("lock file '%s' has unsupported version %d", path, version);
|
||||||
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Node>> nodeMap;
|
std::map<std::string, ref<Node>> nodeMap;
|
||||||
|
|
||||||
std::function<void(Node & node, const nlohmann::json & jsonNode)> getInputs;
|
std::function<void(Node & node, const nlohmann::json & jsonNode)> getInputs;
|
||||||
|
|
||||||
|
@ -93,12 +93,12 @@ LockFile::LockFile(const nlohmann::json & json, const Path & path)
|
||||||
auto jsonNode2 = nodes.find(inputKey);
|
auto jsonNode2 = nodes.find(inputKey);
|
||||||
if (jsonNode2 == nodes.end())
|
if (jsonNode2 == nodes.end())
|
||||||
throw Error("lock file references missing node '%s'", inputKey);
|
throw Error("lock file references missing node '%s'", inputKey);
|
||||||
auto input = std::make_shared<LockedNode>(*jsonNode2);
|
auto input = make_ref<LockedNode>(*jsonNode2);
|
||||||
k = nodeMap.insert_or_assign(inputKey, input).first;
|
k = nodeMap.insert_or_assign(inputKey, input).first;
|
||||||
getInputs(*input, *jsonNode2);
|
getInputs(*input, *jsonNode2);
|
||||||
}
|
}
|
||||||
if (auto child = std::dynamic_pointer_cast<LockedNode>(k->second))
|
if (auto child = k->second.dynamic_pointer_cast<LockedNode>())
|
||||||
node.inputs.insert_or_assign(i.key(), child);
|
node.inputs.insert_or_assign(i.key(), ref(child));
|
||||||
else
|
else
|
||||||
// FIXME: replace by follows node
|
// FIXME: replace by follows node
|
||||||
throw Error("lock file contains cycle to root node");
|
throw Error("lock file contains cycle to root node");
|
||||||
|
@ -122,9 +122,9 @@ nlohmann::json LockFile::toJSON() const
|
||||||
std::unordered_map<std::shared_ptr<const Node>, std::string> nodeKeys;
|
std::unordered_map<std::shared_ptr<const Node>, std::string> nodeKeys;
|
||||||
std::unordered_set<std::string> keys;
|
std::unordered_set<std::string> keys;
|
||||||
|
|
||||||
std::function<std::string(const std::string & key, std::shared_ptr<const Node> node)> dumpNode;
|
std::function<std::string(const std::string & key, ref<const Node> node)> dumpNode;
|
||||||
|
|
||||||
dumpNode = [&](std::string key, std::shared_ptr<const Node> node) -> std::string
|
dumpNode = [&](std::string key, ref<const Node> node) -> std::string
|
||||||
{
|
{
|
||||||
auto k = nodeKeys.find(node);
|
auto k = nodeKeys.find(node);
|
||||||
if (k != nodeKeys.end())
|
if (k != nodeKeys.end())
|
||||||
|
@ -159,10 +159,11 @@ nlohmann::json LockFile::toJSON() const
|
||||||
n["inputs"] = std::move(inputs);
|
n["inputs"] = std::move(inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(node)) {
|
if (auto lockedNode = node.dynamic_pointer_cast<const LockedNode>()) {
|
||||||
n["original"] = fetchers::attrsToJSON(lockedNode->originalRef.toAttrs());
|
n["original"] = fetchers::attrsToJSON(lockedNode->originalRef.toAttrs());
|
||||||
n["locked"] = fetchers::attrsToJSON(lockedNode->lockedRef.toAttrs());
|
n["locked"] = fetchers::attrsToJSON(lockedNode->lockedRef.toAttrs());
|
||||||
if (!lockedNode->isFlake) n["flake"] = false;
|
if (!lockedNode->isFlake)
|
||||||
|
n["flake"] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes[key] = std::move(n);
|
nodes[key] = std::move(n);
|
||||||
|
@ -201,13 +202,13 @@ void LockFile::write(const Path & path) const
|
||||||
writeFile(path, fmt("%s\n", *this));
|
writeFile(path, fmt("%s\n", *this));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LockFile::isImmutable() const
|
std::optional<FlakeRef> LockFile::isUnlocked() const
|
||||||
{
|
{
|
||||||
std::unordered_set<std::shared_ptr<const Node>> nodes;
|
std::set<ref<const Node>> nodes;
|
||||||
|
|
||||||
std::function<void(std::shared_ptr<const Node> node)> visit;
|
std::function<void(ref<const Node> node)> visit;
|
||||||
|
|
||||||
visit = [&](std::shared_ptr<const Node> node)
|
visit = [&](ref<const Node> node)
|
||||||
{
|
{
|
||||||
if (!nodes.insert(node).second) return;
|
if (!nodes.insert(node).second) return;
|
||||||
for (auto & i : node->inputs)
|
for (auto & i : node->inputs)
|
||||||
|
@ -219,11 +220,12 @@ bool LockFile::isImmutable() const
|
||||||
|
|
||||||
for (auto & i : nodes) {
|
for (auto & i : nodes) {
|
||||||
if (i == root) continue;
|
if (i == root) continue;
|
||||||
auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(i);
|
auto node = i.dynamic_pointer_cast<const LockedNode>();
|
||||||
if (lockedNode && !lockedNode->lockedRef.input.isLocked()) return false;
|
if (node && !node->lockedRef.input.isLocked())
|
||||||
|
return node->lockedRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LockFile::operator ==(const LockFile & other) const
|
bool LockFile::operator ==(const LockFile & other) const
|
||||||
|
@ -247,12 +249,12 @@ InputPath parseInputPath(std::string_view s)
|
||||||
|
|
||||||
std::map<InputPath, Node::Edge> LockFile::getAllInputs() const
|
std::map<InputPath, Node::Edge> LockFile::getAllInputs() const
|
||||||
{
|
{
|
||||||
std::unordered_set<std::shared_ptr<Node>> done;
|
std::set<ref<Node>> done;
|
||||||
std::map<InputPath, Node::Edge> res;
|
std::map<InputPath, Node::Edge> res;
|
||||||
|
|
||||||
std::function<void(const InputPath & prefix, std::shared_ptr<Node> node)> recurse;
|
std::function<void(const InputPath & prefix, ref<Node> node)> recurse;
|
||||||
|
|
||||||
recurse = [&](const InputPath & prefix, std::shared_ptr<Node> node)
|
recurse = [&](const InputPath & prefix, ref<Node> node)
|
||||||
{
|
{
|
||||||
if (!done.insert(node).second) return;
|
if (!done.insert(node).second) return;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct LockedNode;
|
||||||
type LockedNode. */
|
type LockedNode. */
|
||||||
struct Node : std::enable_shared_from_this<Node>
|
struct Node : std::enable_shared_from_this<Node>
|
||||||
{
|
{
|
||||||
typedef std::variant<std::shared_ptr<LockedNode>, InputPath> Edge;
|
typedef std::variant<ref<LockedNode>, InputPath> Edge;
|
||||||
|
|
||||||
std::map<FlakeId, Edge> inputs;
|
std::map<FlakeId, Edge> inputs;
|
||||||
|
|
||||||
|
@ -47,11 +47,13 @@ struct LockedNode : Node
|
||||||
|
|
||||||
struct LockFile
|
struct LockFile
|
||||||
{
|
{
|
||||||
std::shared_ptr<Node> root = std::make_shared<Node>();
|
ref<Node> root = make_ref<Node>();
|
||||||
|
|
||||||
LockFile() {};
|
LockFile() {};
|
||||||
LockFile(const nlohmann::json & json, const Path & path);
|
LockFile(const nlohmann::json & json, const Path & path);
|
||||||
|
|
||||||
|
typedef std::map<ref<const Node>, std::string> KeyMap;
|
||||||
|
|
||||||
nlohmann::json toJSON() const;
|
nlohmann::json toJSON() const;
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
@ -60,7 +62,8 @@ struct LockFile
|
||||||
|
|
||||||
void write(const Path & path) const;
|
void write(const Path & path) const;
|
||||||
|
|
||||||
bool isImmutable() const;
|
/* Check whether this lock file has any unlocked inputs. */
|
||||||
|
std::optional<FlakeRef> isUnlocked() const;
|
||||||
|
|
||||||
bool operator ==(const LockFile & other) const;
|
bool operator ==(const LockFile & other) const;
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall
|
||||||
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
/* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */
|
||||||
const Value * outTI = queryMeta("outputsToInstall");
|
const Value * outTI = queryMeta("outputsToInstall");
|
||||||
if (!outTI) return outputs;
|
if (!outTI) return outputs;
|
||||||
const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'");
|
||||||
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
/* ^ this shows during `nix-env -i` right under the bad derivation */
|
||||||
if (!outTI->isList()) throw errMsg;
|
if (!outTI->isList()) throw errMsg;
|
||||||
Outputs result;
|
Outputs result;
|
||||||
|
|
|
@ -289,7 +289,6 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Computing levels/displacements for variables. */
|
/* Computing levels/displacements for variables. */
|
||||||
|
|
||||||
void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||||
|
|
|
@ -1461,10 +1461,10 @@ static RegisterPrimOp primop_storePath({
|
||||||
static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
/* We don’t check the path right now, because we don’t want to
|
/* We don’t check the path right now, because we don’t want to
|
||||||
throw if the path isn’t allowed, but just return false (and we
|
throw if the path isn’t allowed, but just return false (and we
|
||||||
can’t just catch the exception here because we still want to
|
can’t just catch the exception here because we still want to
|
||||||
throw if something in the evaluation of `*args[0]` tries to
|
throw if something in the evaluation of `*args[0]` tries to
|
||||||
access an unauthorized path). */
|
access an unauthorized path). */
|
||||||
auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false });
|
auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -266,7 +266,7 @@ std::optional<time_t> Input::getLastModified() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL InputScheme::toURL(const Input & input)
|
ParsedURL InputScheme::toURL(const Input & input) const
|
||||||
{
|
{
|
||||||
throw Error("don't know how to convert input '%s' to a URL", attrsToJSON(input.attrs));
|
throw Error("don't know how to convert input '%s' to a URL", attrsToJSON(input.attrs));
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ ParsedURL InputScheme::toURL(const Input & input)
|
||||||
Input InputScheme::applyOverrides(
|
Input InputScheme::applyOverrides(
|
||||||
const Input & input,
|
const Input & input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev)
|
std::optional<Hash> rev) const
|
||||||
{
|
{
|
||||||
if (ref)
|
if (ref)
|
||||||
throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref);
|
throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref);
|
||||||
|
@ -293,7 +293,7 @@ void InputScheme::markChangedFile(const Input & input, std::string_view file, st
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputScheme::clone(const Input & input, const Path & destDir)
|
void InputScheme::clone(const Input & input, const Path & destDir) const
|
||||||
{
|
{
|
||||||
throw Error("do not know how to clone input '%s'", input.to_string());
|
throw Error("do not know how to clone input '%s'", input.to_string());
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,26 +107,25 @@ public:
|
||||||
* recognized. The Input object contains the information the fetcher
|
* recognized. The Input object contains the information the fetcher
|
||||||
* needs to actually perform the "fetch()" when called.
|
* needs to actually perform the "fetch()" when called.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct InputScheme
|
struct InputScheme
|
||||||
{
|
{
|
||||||
virtual ~InputScheme()
|
virtual ~InputScheme()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual std::optional<Input> inputFromURL(const ParsedURL & url) = 0;
|
virtual std::optional<Input> inputFromURL(const ParsedURL & url) const = 0;
|
||||||
|
|
||||||
virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) = 0;
|
virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) const = 0;
|
||||||
|
|
||||||
virtual ParsedURL toURL(const Input & input);
|
virtual ParsedURL toURL(const Input & input) const;
|
||||||
|
|
||||||
virtual bool hasAllInfo(const Input & input) = 0;
|
virtual bool hasAllInfo(const Input & input) const = 0;
|
||||||
|
|
||||||
virtual Input applyOverrides(
|
virtual Input applyOverrides(
|
||||||
const Input & input,
|
const Input & input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev);
|
std::optional<Hash> rev) const;
|
||||||
|
|
||||||
virtual void clone(const Input & input, const Path & destDir);
|
virtual void clone(const Input & input, const Path & destDir) const;
|
||||||
|
|
||||||
virtual std::optional<Path> getSourcePath(const Input & input);
|
virtual std::optional<Path> getSourcePath(const Input & input);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
namespace nix::fetchers {
|
namespace nix::fetchers {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Explicit initial branch of our bare repo to suppress warnings from new version of git.
|
// Explicit initial branch of our bare repo to suppress warnings from new version of git.
|
||||||
|
@ -26,23 +27,23 @@ namespace {
|
||||||
// old version of git, which will ignore unrecognized `-c` options.
|
// old version of git, which will ignore unrecognized `-c` options.
|
||||||
const std::string gitInitialBranch = "__nix_dummy_branch";
|
const std::string gitInitialBranch = "__nix_dummy_branch";
|
||||||
|
|
||||||
bool isCacheFileWithinTtl(const time_t now, const struct stat & st)
|
bool isCacheFileWithinTtl(time_t now, const struct stat & st)
|
||||||
{
|
{
|
||||||
return st.st_mtime + settings.tarballTtl > now;
|
return st.st_mtime + settings.tarballTtl > now;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool touchCacheFile(const Path& path, const time_t& touch_time)
|
bool touchCacheFile(const Path & path, time_t touch_time)
|
||||||
{
|
{
|
||||||
struct timeval times[2];
|
struct timeval times[2];
|
||||||
times[0].tv_sec = touch_time;
|
times[0].tv_sec = touch_time;
|
||||||
times[0].tv_usec = 0;
|
times[0].tv_usec = 0;
|
||||||
times[1].tv_sec = touch_time;
|
times[1].tv_sec = touch_time;
|
||||||
times[1].tv_usec = 0;
|
times[1].tv_usec = 0;
|
||||||
|
|
||||||
return lutimes(path.c_str(), times) == 0;
|
return lutimes(path.c_str(), times) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path getCachePath(std::string key)
|
Path getCachePath(std::string_view key)
|
||||||
{
|
{
|
||||||
return getCacheDir() + "/nix/gitv3/" +
|
return getCacheDir() + "/nix/gitv3/" +
|
||||||
hashString(htSHA256, key).to_string(Base32, false);
|
hashString(htSHA256, key).to_string(Base32, false);
|
||||||
|
@ -57,13 +58,12 @@ Path getCachePath(std::string key)
|
||||||
// ...
|
// ...
|
||||||
std::optional<std::string> readHead(const Path & path)
|
std::optional<std::string> readHead(const Path & path)
|
||||||
{
|
{
|
||||||
auto [exit_code, output] = runProgram(RunOptions {
|
auto [status, output] = runProgram(RunOptions {
|
||||||
.program = "git",
|
.program = "git",
|
||||||
|
// FIXME: use 'HEAD' to avoid returning all refs
|
||||||
.args = {"ls-remote", "--symref", path},
|
.args = {"ls-remote", "--symref", path},
|
||||||
});
|
});
|
||||||
if (exit_code != 0) {
|
if (status != 0) return std::nullopt;
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view line = output;
|
std::string_view line = output;
|
||||||
line = line.substr(0, line.find("\n"));
|
line = line.substr(0, line.find("\n"));
|
||||||
|
@ -82,12 +82,11 @@ std::optional<std::string> readHead(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist the HEAD ref from the remote repo in the local cached repo.
|
// Persist the HEAD ref from the remote repo in the local cached repo.
|
||||||
bool storeCachedHead(const std::string& actualUrl, const std::string& headRef)
|
bool storeCachedHead(const std::string & actualUrl, const std::string & headRef)
|
||||||
{
|
{
|
||||||
Path cacheDir = getCachePath(actualUrl);
|
Path cacheDir = getCachePath(actualUrl);
|
||||||
auto gitDir = ".";
|
|
||||||
try {
|
try {
|
||||||
runProgram("git", true, { "-C", cacheDir, "--git-dir", gitDir, "symbolic-ref", "--", "HEAD", headRef });
|
runProgram("git", true, { "-C", cacheDir, "--git-dir", ".", "symbolic-ref", "--", "HEAD", headRef });
|
||||||
} catch (ExecError &e) {
|
} catch (ExecError &e) {
|
||||||
if (!WIFEXITED(e.status)) throw;
|
if (!WIFEXITED(e.status)) throw;
|
||||||
return false;
|
return false;
|
||||||
|
@ -96,7 +95,7 @@ bool storeCachedHead(const std::string& actualUrl, const std::string& headRef)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> readHeadCached(const std::string& actualUrl)
|
std::optional<std::string> readHeadCached(const std::string & actualUrl)
|
||||||
{
|
{
|
||||||
// Create a cache path to store the branch of the HEAD ref. Append something
|
// Create a cache path to store the branch of the HEAD ref. Append something
|
||||||
// in front of the URL to prevent collision with the repository itself.
|
// in front of the URL to prevent collision with the repository itself.
|
||||||
|
@ -110,16 +109,15 @@ std::optional<std::string> readHeadCached(const std::string& actualUrl)
|
||||||
cachedRef = readHead(cacheDir);
|
cachedRef = readHead(cacheDir);
|
||||||
if (cachedRef != std::nullopt &&
|
if (cachedRef != std::nullopt &&
|
||||||
*cachedRef != gitInitialBranch &&
|
*cachedRef != gitInitialBranch &&
|
||||||
isCacheFileWithinTtl(now, st)) {
|
isCacheFileWithinTtl(now, st))
|
||||||
|
{
|
||||||
debug("using cached HEAD ref '%s' for repo '%s'", *cachedRef, actualUrl);
|
debug("using cached HEAD ref '%s' for repo '%s'", *cachedRef, actualUrl);
|
||||||
return cachedRef;
|
return cachedRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref = readHead(actualUrl);
|
auto ref = readHead(actualUrl);
|
||||||
if (ref) {
|
if (ref) return ref;
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedRef) {
|
if (cachedRef) {
|
||||||
// If the cached git ref is expired in fetch() below, and the 'git fetch'
|
// If the cached git ref is expired in fetch() below, and the 'git fetch'
|
||||||
|
@ -250,7 +248,7 @@ std::pair<StorePath, Input> fetchFromWorkdir(ref<Store> store, Input & input, co
|
||||||
|
|
||||||
struct GitInputScheme : InputScheme
|
struct GitInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (url.scheme != "git" &&
|
if (url.scheme != "git" &&
|
||||||
url.scheme != "git+http" &&
|
url.scheme != "git+http" &&
|
||||||
|
@ -265,7 +263,7 @@ struct GitInputScheme : InputScheme
|
||||||
Attrs attrs;
|
Attrs attrs;
|
||||||
attrs.emplace("type", "git");
|
attrs.emplace("type", "git");
|
||||||
|
|
||||||
for (auto &[name, value] : url.query) {
|
for (auto & [name, value] : url.query) {
|
||||||
if (name == "rev" || name == "ref")
|
if (name == "rev" || name == "ref")
|
||||||
attrs.emplace(name, value);
|
attrs.emplace(name, value);
|
||||||
else if (name == "shallow" || name == "submodules")
|
else if (name == "shallow" || name == "submodules")
|
||||||
|
@ -279,7 +277,7 @@ struct GitInputScheme : InputScheme
|
||||||
return inputFromAttrs(attrs);
|
return inputFromAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
if (maybeGetStrAttr(attrs, "type") != "git") return {};
|
if (maybeGetStrAttr(attrs, "type") != "git") return {};
|
||||||
|
|
||||||
|
@ -302,7 +300,7 @@ struct GitInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
if (url.scheme != "git") url.scheme = "git+" + url.scheme;
|
if (url.scheme != "git") url.scheme = "git+" + url.scheme;
|
||||||
|
@ -313,7 +311,7 @@ struct GitInputScheme : InputScheme
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
bool maybeDirty = !input.getRef();
|
bool maybeDirty = !input.getRef();
|
||||||
bool shallow = maybeGetBoolAttr(input.attrs, "shallow").value_or(false);
|
bool shallow = maybeGetBoolAttr(input.attrs, "shallow").value_or(false);
|
||||||
|
@ -325,7 +323,7 @@ struct GitInputScheme : InputScheme
|
||||||
Input applyOverrides(
|
Input applyOverrides(
|
||||||
const Input & input,
|
const Input & input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev) override
|
std::optional<Hash> rev) const override
|
||||||
{
|
{
|
||||||
auto res(input);
|
auto res(input);
|
||||||
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
|
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
|
||||||
|
@ -335,7 +333,7 @@ struct GitInputScheme : InputScheme
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clone(const Input & input, const Path & destDir) override
|
void clone(const Input & input, const Path & destDir) const override
|
||||||
{
|
{
|
||||||
auto [isLocal, actualUrl] = getActualUrl(input);
|
auto [isLocal, actualUrl] = getActualUrl(input);
|
||||||
|
|
||||||
|
@ -603,9 +601,9 @@ struct GitInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
throw Error(
|
throw Error(
|
||||||
"Cannot find Git revision '%s' in ref '%s' of repository '%s'! "
|
"Cannot find Git revision '%s' in ref '%s' of repository '%s'! "
|
||||||
"Please make sure that the " ANSI_BOLD "rev" ANSI_NORMAL " exists on the "
|
"Please make sure that the " ANSI_BOLD "rev" ANSI_NORMAL " exists on the "
|
||||||
ANSI_BOLD "ref" ANSI_NORMAL " you've specified or add " ANSI_BOLD
|
ANSI_BOLD "ref" ANSI_NORMAL " you've specified or add " ANSI_BOLD
|
||||||
"allRefs = true;" ANSI_NORMAL " to " ANSI_BOLD "fetchGit" ANSI_NORMAL ".",
|
"allRefs = true;" ANSI_NORMAL " to " ANSI_BOLD "fetchGit" ANSI_NORMAL ".",
|
||||||
input.getRev()->gitRev(),
|
input.getRev()->gitRev(),
|
||||||
*input.getRef(),
|
*input.getRef(),
|
||||||
actualUrl
|
actualUrl
|
||||||
|
|
|
@ -26,11 +26,11 @@ std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
|
||||||
|
|
||||||
struct GitArchiveInputScheme : InputScheme
|
struct GitArchiveInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
virtual std::string type() = 0;
|
virtual std::string type() const = 0;
|
||||||
|
|
||||||
virtual std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const = 0;
|
virtual std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const = 0;
|
||||||
|
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (url.scheme != type()) return {};
|
if (url.scheme != type()) return {};
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
if (maybeGetStrAttr(attrs, "type") != type()) return {};
|
if (maybeGetStrAttr(attrs, "type") != type()) return {};
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto owner = getStrAttr(input.attrs, "owner");
|
auto owner = getStrAttr(input.attrs, "owner");
|
||||||
auto repo = getStrAttr(input.attrs, "repo");
|
auto repo = getStrAttr(input.attrs, "repo");
|
||||||
|
@ -132,7 +132,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
return input.getRev() && maybeGetIntAttr(input.attrs, "lastModified");
|
return input.getRev() && maybeGetIntAttr(input.attrs, "lastModified");
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
Input applyOverrides(
|
Input applyOverrides(
|
||||||
const Input & _input,
|
const Input & _input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev) override
|
std::optional<Hash> rev) const override
|
||||||
{
|
{
|
||||||
auto input(_input);
|
auto input(_input);
|
||||||
if (rev && ref)
|
if (rev && ref)
|
||||||
|
@ -227,7 +227,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
|
|
||||||
struct GitHubInputScheme : GitArchiveInputScheme
|
struct GitHubInputScheme : GitArchiveInputScheme
|
||||||
{
|
{
|
||||||
std::string type() override { return "github"; }
|
std::string type() const override { return "github"; }
|
||||||
|
|
||||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||||
{
|
{
|
||||||
|
@ -240,14 +240,29 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||||
return std::pair<std::string, std::string>("Authorization", fmt("token %s", token));
|
return std::pair<std::string, std::string>("Authorization", fmt("token %s", token));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getHost(const Input & input) const
|
||||||
|
{
|
||||||
|
return maybeGetStrAttr(input.attrs, "host").value_or("github.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getOwner(const Input & input) const
|
||||||
|
{
|
||||||
|
return getStrAttr(input.attrs, "owner");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRepo(const Input & input) const
|
||||||
|
{
|
||||||
|
return getStrAttr(input.attrs, "repo");
|
||||||
|
}
|
||||||
|
|
||||||
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||||
{
|
{
|
||||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com");
|
auto host = getHost(input);
|
||||||
auto url = fmt(
|
auto url = fmt(
|
||||||
host == "github.com"
|
host == "github.com"
|
||||||
? "https://api.%s/repos/%s/%s/commits/%s"
|
? "https://api.%s/repos/%s/%s/commits/%s"
|
||||||
: "https://%s/api/v3/repos/%s/%s/commits/%s",
|
: "https://%s/api/v3/repos/%s/%s/commits/%s",
|
||||||
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), *input.getRef());
|
host, getOwner(input), getRepo(input), *input.getRef());
|
||||||
|
|
||||||
Headers headers = makeHeadersWithAuthTokens(host);
|
Headers headers = makeHeadersWithAuthTokens(host);
|
||||||
|
|
||||||
|
@ -262,8 +277,10 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||||
|
|
||||||
DownloadUrl getDownloadUrl(const Input & input) const override
|
DownloadUrl getDownloadUrl(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com");
|
auto host = getHost(input);
|
||||||
|
|
||||||
Headers headers = makeHeadersWithAuthTokens(host);
|
Headers headers = makeHeadersWithAuthTokens(host);
|
||||||
|
|
||||||
// If we have no auth headers then we default to the public archive
|
// If we have no auth headers then we default to the public archive
|
||||||
// urls so we do not run into rate limits.
|
// urls so we do not run into rate limits.
|
||||||
const auto urlFmt =
|
const auto urlFmt =
|
||||||
|
@ -273,17 +290,17 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||||
? "https://%s/%s/%s/archive/%s.tar.gz"
|
? "https://%s/%s/%s/archive/%s.tar.gz"
|
||||||
: "https://api.%s/repos/%s/%s/tarball/%s";
|
: "https://api.%s/repos/%s/%s/tarball/%s";
|
||||||
|
|
||||||
const auto url = fmt(urlFmt, host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
|
const auto url = fmt(urlFmt, host, getOwner(input), getRepo(input),
|
||||||
input.getRev()->to_string(Base16, false));
|
input.getRev()->to_string(Base16, false));
|
||||||
|
|
||||||
return DownloadUrl { url, headers };
|
return DownloadUrl { url, headers };
|
||||||
}
|
}
|
||||||
|
|
||||||
void clone(const Input & input, const Path & destDir) override
|
void clone(const Input & input, const Path & destDir) const override
|
||||||
{
|
{
|
||||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com");
|
auto host = getHost(input);
|
||||||
Input::fromURL(fmt("git+https://%s/%s/%s.git",
|
Input::fromURL(fmt("git+https://%s/%s/%s.git",
|
||||||
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
|
host, getOwner(input), getRepo(input)))
|
||||||
.applyOverrides(input.getRef(), input.getRev())
|
.applyOverrides(input.getRef(), input.getRev())
|
||||||
.clone(destDir);
|
.clone(destDir);
|
||||||
}
|
}
|
||||||
|
@ -291,7 +308,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||||
|
|
||||||
struct GitLabInputScheme : GitArchiveInputScheme
|
struct GitLabInputScheme : GitArchiveInputScheme
|
||||||
{
|
{
|
||||||
std::string type() override { return "gitlab"; }
|
std::string type() const override { return "gitlab"; }
|
||||||
|
|
||||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||||
{
|
{
|
||||||
|
@ -346,7 +363,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||||
return DownloadUrl { url, headers };
|
return DownloadUrl { url, headers };
|
||||||
}
|
}
|
||||||
|
|
||||||
void clone(const Input & input, const Path & destDir) override
|
void clone(const Input & input, const Path & destDir) const override
|
||||||
{
|
{
|
||||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
|
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
|
||||||
// FIXME: get username somewhere
|
// FIXME: get username somewhere
|
||||||
|
@ -359,7 +376,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||||
|
|
||||||
struct SourceHutInputScheme : GitArchiveInputScheme
|
struct SourceHutInputScheme : GitArchiveInputScheme
|
||||||
{
|
{
|
||||||
std::string type() override { return "sourcehut"; }
|
std::string type() const override { return "sourcehut"; }
|
||||||
|
|
||||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||||
{
|
{
|
||||||
|
@ -433,7 +450,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||||
return DownloadUrl { url, headers };
|
return DownloadUrl { url, headers };
|
||||||
}
|
}
|
||||||
|
|
||||||
void clone(const Input & input, const Path & destDir) override
|
void clone(const Input & input, const Path & destDir) const override
|
||||||
{
|
{
|
||||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||||
Input::fromURL(fmt("git+https://%s/%s/%s",
|
Input::fromURL(fmt("git+https://%s/%s/%s",
|
||||||
|
|
|
@ -7,7 +7,7 @@ std::regex flakeRegex("[a-zA-Z][a-zA-Z0-9_-]*", std::regex::ECMAScript);
|
||||||
|
|
||||||
struct IndirectInputScheme : InputScheme
|
struct IndirectInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (url.scheme != "flake") return {};
|
if (url.scheme != "flake") return {};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ struct IndirectInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
if (maybeGetStrAttr(attrs, "type") != "indirect") return {};
|
if (maybeGetStrAttr(attrs, "type") != "indirect") return {};
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ struct IndirectInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
ParsedURL url;
|
ParsedURL url;
|
||||||
url.scheme = "flake";
|
url.scheme = "flake";
|
||||||
|
@ -78,7 +78,7 @@ struct IndirectInputScheme : InputScheme
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ struct IndirectInputScheme : InputScheme
|
||||||
Input applyOverrides(
|
Input applyOverrides(
|
||||||
const Input & _input,
|
const Input & _input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev) override
|
std::optional<Hash> rev) const override
|
||||||
{
|
{
|
||||||
auto input(_input);
|
auto input(_input);
|
||||||
if (rev) input.attrs.insert_or_assign("rev", rev->gitRev());
|
if (rev) input.attrs.insert_or_assign("rev", rev->gitRev());
|
||||||
|
|
|
@ -43,7 +43,7 @@ static std::string runHg(const Strings & args, const std::optional<std::string>
|
||||||
|
|
||||||
struct MercurialInputScheme : InputScheme
|
struct MercurialInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (url.scheme != "hg+http" &&
|
if (url.scheme != "hg+http" &&
|
||||||
url.scheme != "hg+https" &&
|
url.scheme != "hg+https" &&
|
||||||
|
@ -69,7 +69,7 @@ struct MercurialInputScheme : InputScheme
|
||||||
return inputFromAttrs(attrs);
|
return inputFromAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
if (maybeGetStrAttr(attrs, "type") != "hg") return {};
|
if (maybeGetStrAttr(attrs, "type") != "hg") return {};
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ struct MercurialInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
url.scheme = "hg+" + url.scheme;
|
url.scheme = "hg+" + url.scheme;
|
||||||
|
@ -98,7 +98,7 @@ struct MercurialInputScheme : InputScheme
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
// FIXME: ugly, need to distinguish between dirty and clean
|
// FIXME: ugly, need to distinguish between dirty and clean
|
||||||
// default trees.
|
// default trees.
|
||||||
|
@ -108,7 +108,7 @@ struct MercurialInputScheme : InputScheme
|
||||||
Input applyOverrides(
|
Input applyOverrides(
|
||||||
const Input & input,
|
const Input & input,
|
||||||
std::optional<std::string> ref,
|
std::optional<std::string> ref,
|
||||||
std::optional<Hash> rev) override
|
std::optional<Hash> rev) const override
|
||||||
{
|
{
|
||||||
auto res(input);
|
auto res(input);
|
||||||
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
|
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace nix::fetchers {
|
||||||
|
|
||||||
struct PathInputScheme : InputScheme
|
struct PathInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (url.scheme != "path") return {};
|
if (url.scheme != "path") return {};
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ struct PathInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
if (maybeGetStrAttr(attrs, "type") != "path") return {};
|
if (maybeGetStrAttr(attrs, "type") != "path") return {};
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ struct PathInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto query = attrsToQuery(input.attrs);
|
auto query = attrsToQuery(input.attrs);
|
||||||
query.erase("path");
|
query.erase("path");
|
||||||
|
@ -66,7 +66,7 @@ struct PathInputScheme : InputScheme
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ struct CurlInputScheme : InputScheme
|
||||||
|
|
||||||
virtual bool isValidURL(const ParsedURL & url) const = 0;
|
virtual bool isValidURL(const ParsedURL & url) const = 0;
|
||||||
|
|
||||||
std::optional<Input> inputFromURL(const ParsedURL & url) override
|
std::optional<Input> inputFromURL(const ParsedURL & url) const override
|
||||||
{
|
{
|
||||||
if (!isValidURL(url))
|
if (!isValidURL(url))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -203,7 +203,7 @@ struct CurlInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
|
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
|
||||||
{
|
{
|
||||||
auto type = maybeGetStrAttr(attrs, "type");
|
auto type = maybeGetStrAttr(attrs, "type");
|
||||||
if (type != inputType()) return {};
|
if (type != inputType()) return {};
|
||||||
|
@ -220,16 +220,17 @@ struct CurlInputScheme : InputScheme
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL toURL(const Input & input) override
|
ParsedURL toURL(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
// NAR hashes are preferred over file hashes since tar/zip files // don't have a canonical representation.
|
// NAR hashes are preferred over file hashes since tar/zip
|
||||||
|
// files don't have a canonical representation.
|
||||||
if (auto narHash = input.getNarHash())
|
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(SRI, true));
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasAllInfo(const Input & input) override
|
bool hasAllInfo(const Input & input) const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ public:
|
||||||
log(*state, lvl, fs.s);
|
log(*state, lvl, fs.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logEI(const ErrorInfo &ei) override
|
void logEI(const ErrorInfo & ei) override
|
||||||
{
|
{
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,7 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
|
||||||
try {
|
try {
|
||||||
getFile(info->url, *decompressor);
|
getFile(info->url, *decompressor);
|
||||||
} catch (NoSuchBinaryCacheFile & e) {
|
} catch (NoSuchBinaryCacheFile & e) {
|
||||||
throw SubstituteGone(e.info());
|
throw SubstituteGone(std::move(e.info()));
|
||||||
}
|
}
|
||||||
|
|
||||||
decompressor->finish();
|
decompressor->finish();
|
||||||
|
|
|
@ -134,7 +134,7 @@ void DerivationGoal::killChild()
|
||||||
void DerivationGoal::timedOut(Error && ex)
|
void DerivationGoal::timedOut(Error && ex)
|
||||||
{
|
{
|
||||||
killChild();
|
killChild();
|
||||||
done(BuildResult::TimedOut, {}, ex);
|
done(BuildResult::TimedOut, {}, std::move(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -971,7 +971,7 @@ void DerivationGoal::buildDone()
|
||||||
BuildResult::PermanentFailure;
|
BuildResult::PermanentFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
done(st, {}, e);
|
done(st, {}, std::move(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1434,7 +1434,7 @@ void DerivationGoal::done(
|
||||||
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
|
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
amDone(buildResult.success() ? ecSuccess : ecFailed, ex);
|
amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
|
||||||
if (ex)
|
if (ex)
|
||||||
logError(i->ex->info());
|
logError(i->ex->info());
|
||||||
else
|
else
|
||||||
ex = i->ex;
|
ex = std::move(i->ex);
|
||||||
}
|
}
|
||||||
if (i->exitCode != Goal::ecSuccess) {
|
if (i->exitCode != Goal::ecSuccess) {
|
||||||
if (auto i2 = dynamic_cast<DerivationGoal *>(i.get())) failed.insert(i2->drvPath);
|
if (auto i2 = dynamic_cast<DerivationGoal *>(i.get())) failed.insert(i2->drvPath);
|
||||||
|
@ -40,7 +40,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
|
||||||
|
|
||||||
if (failed.size() == 1 && ex) {
|
if (failed.size() == 1 && ex) {
|
||||||
ex->status = worker.exitStatus();
|
ex->status = worker.exitStatus();
|
||||||
throw *ex;
|
throw std::move(*ex);
|
||||||
} else if (!failed.empty()) {
|
} else if (!failed.empty()) {
|
||||||
if (ex) logError(ex->info());
|
if (ex) logError(ex->info());
|
||||||
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
|
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
|
||||||
|
@ -109,7 +109,7 @@ void Store::ensurePath(const StorePath & path)
|
||||||
if (goal->exitCode != Goal::ecSuccess) {
|
if (goal->exitCode != Goal::ecSuccess) {
|
||||||
if (goal->ex) {
|
if (goal->ex) {
|
||||||
goal->ex->status = worker.exitStatus();
|
goal->ex->status = worker.exitStatus();
|
||||||
throw *goal->ex;
|
throw std::move(*goal->ex);
|
||||||
} else
|
} else
|
||||||
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,7 @@ void LocalDerivationGoal::tryLocalBuild() {
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
buildUser.reset();
|
buildUser.reset();
|
||||||
worker.permanentFailure = true;
|
worker.permanentFailure = true;
|
||||||
done(BuildResult::InputRejected, {}, e);
|
done(BuildResult::InputRejected, {}, std::move(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,7 +448,7 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs,
|
||||||
|
|
||||||
|
|
||||||
// FIXME: remove
|
// FIXME: remove
|
||||||
bool isDerivation(const std::string & fileName)
|
bool isDerivation(std::string_view fileName)
|
||||||
{
|
{
|
||||||
return hasSuffix(fileName, drvExtension);
|
return hasSuffix(fileName, drvExtension);
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ StorePath writeDerivation(Store & store,
|
||||||
Derivation parseDerivation(const Store & store, std::string && s, std::string_view name);
|
Derivation parseDerivation(const Store & store, std::string && s, std::string_view name);
|
||||||
|
|
||||||
// FIXME: remove
|
// FIXME: remove
|
||||||
bool isDerivation(const std::string & fileName);
|
bool isDerivation(std::string_view fileName);
|
||||||
|
|
||||||
/* Calculate the name that will be used for the store path for this
|
/* Calculate the name that will be used for the store path for this
|
||||||
output.
|
output.
|
||||||
|
|
|
@ -142,9 +142,9 @@ struct curlFileTransfer : public FileTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void fail(const T & e)
|
void fail(T && e)
|
||||||
{
|
{
|
||||||
failEx(std::make_exception_ptr(e));
|
failEx(std::make_exception_ptr(std::move(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
LambdaSink finalSink;
|
LambdaSink finalSink;
|
||||||
|
@ -472,7 +472,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
fileTransfer.enqueueItem(shared_from_this());
|
fileTransfer.enqueueItem(shared_from_this());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fail(exc);
|
fail(std::move(exc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -447,7 +447,7 @@ void RemoteStore::queryPathInfoUncached(const StorePath & path,
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
// Ugly backwards compatibility hack.
|
// Ugly backwards compatibility hack.
|
||||||
if (e.msg().find("is not valid") != std::string::npos)
|
if (e.msg().find("is not valid") != std::string::npos)
|
||||||
throw InvalidPath(e.info());
|
throw InvalidPath(std::move(e.info()));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) {
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) {
|
||||||
|
|
|
@ -19,21 +19,21 @@ using json = nlohmann::json;
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
bool Store::isInStore(const Path & path) const
|
bool Store::isInStore(PathView path) const
|
||||||
{
|
{
|
||||||
return isInDir(path, storeDir);
|
return isInDir(path, storeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair<StorePath, Path> Store::toStorePath(const Path & path) const
|
std::pair<StorePath, Path> Store::toStorePath(PathView path) const
|
||||||
{
|
{
|
||||||
if (!isInStore(path))
|
if (!isInStore(path))
|
||||||
throw Error("path '%1%' is not in the Nix store", path);
|
throw Error("path '%1%' is not in the Nix store", path);
|
||||||
Path::size_type slash = path.find('/', storeDir.size() + 1);
|
auto slash = path.find('/', storeDir.size() + 1);
|
||||||
if (slash == Path::npos)
|
if (slash == Path::npos)
|
||||||
return {parseStorePath(path), ""};
|
return {parseStorePath(path), ""};
|
||||||
else
|
else
|
||||||
return {parseStorePath(std::string_view(path).substr(0, slash)), path.substr(slash)};
|
return {parseStorePath(path.substr(0, slash)), (Path) path.substr(slash)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ public:
|
||||||
|
|
||||||
/* Return true if ‘path’ is in the Nix store (but not the Nix
|
/* Return true if ‘path’ is in the Nix store (but not the Nix
|
||||||
store itself). */
|
store itself). */
|
||||||
bool isInStore(const Path & path) const;
|
bool isInStore(PathView path) const;
|
||||||
|
|
||||||
/* Return true if ‘path’ is a store path, i.e. a direct child of
|
/* Return true if ‘path’ is a store path, i.e. a direct child of
|
||||||
the Nix store. */
|
the Nix store. */
|
||||||
|
@ -187,7 +187,7 @@ public:
|
||||||
|
|
||||||
/* Split a path like /nix/store/<hash>-<name>/<bla> into
|
/* Split a path like /nix/store/<hash>-<name>/<bla> into
|
||||||
/nix/store/<hash>-<name> and /<bla>. */
|
/nix/store/<hash>-<name> and /<bla>. */
|
||||||
std::pair<StorePath, Path> toStorePath(const Path & path) const;
|
std::pair<StorePath, Path> toStorePath(PathView path) const;
|
||||||
|
|
||||||
/* Follow symlinks until we end up with a path in the Nix store. */
|
/* Follow symlinks until we end up with a path in the Nix store. */
|
||||||
Path followLinksToStore(std::string_view path) const;
|
Path followLinksToStore(std::string_view path) const;
|
||||||
|
|
|
@ -35,10 +35,6 @@ static ArchiveSettings archiveSettings;
|
||||||
|
|
||||||
static GlobalConfig::Register rArchiveSettings(&archiveSettings);
|
static GlobalConfig::Register rArchiveSettings(&archiveSettings);
|
||||||
|
|
||||||
const std::string narVersionMagic1 = "nix-archive-1";
|
|
||||||
|
|
||||||
static std::string caseHackSuffix = "~nix~case~hack~";
|
|
||||||
|
|
||||||
PathFilter defaultPathFilter = [](const Path &) { return true; };
|
PathFilter defaultPathFilter = [](const Path &) { return true; };
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,9 @@ void copyNAR(Source & source, Sink & sink);
|
||||||
void copyPath(const Path & from, const Path & to);
|
void copyPath(const Path & from, const Path & to);
|
||||||
|
|
||||||
|
|
||||||
extern const std::string narVersionMagic1;
|
inline constexpr std::string_view narVersionMagic1 = "nix-archive-1";
|
||||||
|
|
||||||
|
inline constexpr std::string_view caseHackSuffix = "~nix~case~hack~";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ inline hintformat hintfmt(const std::string & fs, const Args & ... args)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline hintformat hintfmt(std::string plain_string)
|
inline hintformat hintfmt(const std::string & plain_string)
|
||||||
{
|
{
|
||||||
// we won't be receiving any args in this case, so just print the original string
|
// we won't be receiving any args in this case, so just print the original string
|
||||||
return hintfmt("%s", normaltxt(plain_string));
|
return hintfmt("%s", normaltxt(plain_string));
|
||||||
|
|
|
@ -105,14 +105,6 @@ public:
|
||||||
|
|
||||||
Verbosity verbosity = lvlInfo;
|
Verbosity verbosity = lvlInfo;
|
||||||
|
|
||||||
void warnOnce(bool & haveWarned, const FormatOrString & fs)
|
|
||||||
{
|
|
||||||
if (!haveWarned) {
|
|
||||||
warn(fs.s);
|
|
||||||
haveWarned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeToStderr(std::string_view s)
|
void writeToStderr(std::string_view s)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -130,11 +122,11 @@ Logger * makeSimpleLogger(bool printBuildLogs)
|
||||||
return new SimpleLogger(printBuildLogs);
|
return new SimpleLogger(printBuildLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32};
|
std::atomic<uint64_t> nextId{0};
|
||||||
|
|
||||||
Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type,
|
Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type,
|
||||||
const std::string & s, const Logger::Fields & fields, ActivityId parent)
|
const std::string & s, const Logger::Fields & fields, ActivityId parent)
|
||||||
: logger(logger), id(nextId++)
|
: logger(logger), id(nextId++ + (((uint64_t) getpid()) << 32))
|
||||||
{
|
{
|
||||||
logger.startActivity(id, lvl, type, s, fields, parent);
|
logger.startActivity(id, lvl, type, s, fields, parent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public:
|
||||||
log(lvlInfo, fs);
|
log(lvlInfo, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void logEI(const ErrorInfo &ei) = 0;
|
virtual void logEI(const ErrorInfo & ei) = 0;
|
||||||
|
|
||||||
void logEI(Verbosity lvl, ErrorInfo ei)
|
void logEI(Verbosity lvl, ErrorInfo ei)
|
||||||
{
|
{
|
||||||
|
@ -225,7 +225,11 @@ inline void warn(const std::string & fs, const Args & ... args)
|
||||||
logger->warn(f.str());
|
logger->warn(f.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void warnOnce(bool & haveWarned, const FormatOrString & fs);
|
#define warnOnce(haveWarned, args...) \
|
||||||
|
if (!haveWarned) { \
|
||||||
|
haveWarned = true; \
|
||||||
|
warn(args); \
|
||||||
|
}
|
||||||
|
|
||||||
void writeToStderr(std::string_view s);
|
void writeToStderr(std::string_view s);
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,11 @@ public:
|
||||||
return p != other.p;
|
return p != other.p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator < (const ref<T> & other) const
|
||||||
|
{
|
||||||
|
return p < other.p;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template<typename T2, typename... Args>
|
template<typename T2, typename... Args>
|
||||||
|
|
|
@ -338,7 +338,7 @@ Sink & operator << (Sink & sink, const StringSet & s)
|
||||||
|
|
||||||
Sink & operator << (Sink & sink, const Error & ex)
|
Sink & operator << (Sink & sink, const Error & ex)
|
||||||
{
|
{
|
||||||
auto info = ex.info();
|
auto & info = ex.info();
|
||||||
sink
|
sink
|
||||||
<< "Error"
|
<< "Error"
|
||||||
<< info.level
|
<< info.level
|
||||||
|
|
|
@ -331,17 +331,9 @@ T readNum(Source & source)
|
||||||
unsigned char buf[8];
|
unsigned char buf[8];
|
||||||
source((char *) buf, sizeof(buf));
|
source((char *) buf, sizeof(buf));
|
||||||
|
|
||||||
uint64_t n =
|
auto n = readLittleEndian<uint64_t>(buf);
|
||||||
((uint64_t) buf[0]) |
|
|
||||||
((uint64_t) buf[1] << 8) |
|
|
||||||
((uint64_t) buf[2] << 16) |
|
|
||||||
((uint64_t) buf[3] << 24) |
|
|
||||||
((uint64_t) buf[4] << 32) |
|
|
||||||
((uint64_t) buf[5] << 40) |
|
|
||||||
((uint64_t) buf[6] << 48) |
|
|
||||||
((uint64_t) buf[7] << 56);
|
|
||||||
|
|
||||||
if (n > (uint64_t)std::numeric_limits<T>::max())
|
if (n > (uint64_t) std::numeric_limits<T>::max())
|
||||||
throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name());
|
throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name());
|
||||||
|
|
||||||
return (T) n;
|
return (T) n;
|
||||||
|
|
|
@ -1594,6 +1594,21 @@ std::string stripIndentation(std::string_view s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<std::string_view, std::string_view> getLine(std::string_view s)
|
||||||
|
{
|
||||||
|
auto newline = s.find('\n');
|
||||||
|
|
||||||
|
if (newline == s.npos) {
|
||||||
|
return {s, ""};
|
||||||
|
} else {
|
||||||
|
auto line = s.substr(0, newline);
|
||||||
|
if (!line.empty() && line[line.size() - 1] == '\r')
|
||||||
|
line = line.substr(0, line.size() - 1);
|
||||||
|
return {line, s.substr(newline + 1)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
||||||
|
|
|
@ -510,6 +510,18 @@ std::optional<N> string2Float(const std::string_view s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert a little-endian integer to host order. */
|
||||||
|
template<typename T>
|
||||||
|
T readLittleEndian(unsigned char * p)
|
||||||
|
{
|
||||||
|
T x = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(x); ++i, ++p) {
|
||||||
|
x |= ((T) *p) << (i * 8);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return true iff `s' starts with `prefix'. */
|
/* Return true iff `s' starts with `prefix'. */
|
||||||
bool hasPrefix(std::string_view s, std::string_view prefix);
|
bool hasPrefix(std::string_view s, std::string_view prefix);
|
||||||
|
|
||||||
|
@ -563,6 +575,12 @@ std::string base64Decode(std::string_view s);
|
||||||
std::string stripIndentation(std::string_view s);
|
std::string stripIndentation(std::string_view s);
|
||||||
|
|
||||||
|
|
||||||
|
/* Get the prefix of 's' up to and excluding the next line break (LF
|
||||||
|
optionally preceded by CR), and the remainder following the line
|
||||||
|
break. */
|
||||||
|
std::pair<std::string_view, std::string_view> getLine(std::string_view s);
|
||||||
|
|
||||||
|
|
||||||
/* Get a value for the specified key from an associate container. */
|
/* Get a value for the specified key from an associate container. */
|
||||||
template <class T>
|
template <class T>
|
||||||
const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
|
const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
|
||||||
|
@ -737,4 +755,13 @@ inline std::string operator + (std::string && s, std::string_view s2)
|
||||||
return std::move(s);
|
return std::move(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string operator + (std::string_view s1, const char * s2)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
s.reserve(s1.size() + strlen(s2));
|
||||||
|
s.append(s1);
|
||||||
|
s.append(s2);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -932,7 +932,6 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
worker_proto::write(*store, out, status.builtOutputs);
|
worker_proto::write(*store, out, status.builtOutputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ static void daemonLoop()
|
||||||
} catch (Interrupted & e) {
|
} catch (Interrupted & e) {
|
||||||
return;
|
return;
|
||||||
} catch (Error & error) {
|
} catch (Error & error) {
|
||||||
ErrorInfo ei = error.info();
|
auto ei = error.info();
|
||||||
// FIXME: add to trace?
|
// FIXME: add to trace?
|
||||||
ei.msg = hintfmt("error processing connection: %1%", ei.msg.str());
|
ei.msg = hintfmt("error processing connection: %1%", ei.msg.str());
|
||||||
logError(ei);
|
logError(ei);
|
||||||
|
|
|
@ -16,7 +16,7 @@ R""(
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
This command recreates the lock file of a flake (`flake.lock`), thus
|
This command recreates the lock file of a flake (`flake.lock`), thus
|
||||||
updating the lock for every mutable input (like `nixpkgs`) to its
|
updating the lock for every unlocked input (like `nixpkgs`) to its
|
||||||
current version. This is equivalent to passing `--recreate-lock-file`
|
current version. This is equivalent to passing `--recreate-lock-file`
|
||||||
to any command that operates on a flake. That is,
|
to any command that operates on a flake. That is,
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||||
if (!lockedFlake.lockFile.root->inputs.empty())
|
if (!lockedFlake.lockFile.root->inputs.empty())
|
||||||
logger->cout(ANSI_BOLD "Inputs:" ANSI_NORMAL);
|
logger->cout(ANSI_BOLD "Inputs:" ANSI_NORMAL);
|
||||||
|
|
||||||
std::unordered_set<std::shared_ptr<Node>> visited;
|
std::set<ref<Node>> visited;
|
||||||
|
|
||||||
std::function<void(const Node & node, const std::string & prefix)> recurse;
|
std::function<void(const Node & node, const std::string & prefix)> recurse;
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||||
if (auto lockedNode = std::get_if<0>(&input.second)) {
|
if (auto lockedNode = std::get_if<0>(&input.second)) {
|
||||||
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
|
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
|
||||||
prefix + (last ? treeLast : treeConn), input.first,
|
prefix + (last ? treeLast : treeConn), input.first,
|
||||||
*lockedNode ? (*lockedNode)->lockedRef : flake.lockedRef);
|
(*lockedNode)->lockedRef);
|
||||||
|
|
||||||
bool firstVisit = visited.insert(*lockedNode).second;
|
bool firstVisit = visited.insert(*lockedNode).second;
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,11 @@ following fields:
|
||||||
* An integer that can be used to unambiguously identify the package in
|
* An integer that can be used to unambiguously identify the package in
|
||||||
invocations of `nix profile remove` and `nix profile upgrade`.
|
invocations of `nix profile remove` and `nix profile upgrade`.
|
||||||
|
|
||||||
* The original ("mutable") flake reference and output attribute path
|
* The original ("unlocked") flake reference and output attribute path
|
||||||
used at installation time.
|
used at installation time.
|
||||||
|
|
||||||
* The immutable flake reference to which the mutable flake reference
|
* The locked flake reference to which the unlocked flake reference was
|
||||||
was resolved.
|
resolved.
|
||||||
|
|
||||||
* The store path(s) of the package.
|
* The store path(s) of the package.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ R""(
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
* Upgrade all packages that were installed using a mutable flake
|
* Upgrade all packages that were installed using an unlocked flake
|
||||||
reference:
|
reference:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
@ -32,9 +32,9 @@ the package was installed.
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
> This only works if you used a *mutable* flake reference at
|
> This only works if you used an *unlocked* flake reference at
|
||||||
> installation time, e.g. `nixpkgs#hello`. It does not work if you
|
> installation time, e.g. `nixpkgs#hello`. It does not work if you
|
||||||
> used an *immutable* flake reference
|
> used a *locked* flake reference
|
||||||
> (e.g. `github:NixOS/nixpkgs/13d0c311e3ae923a00f734b43fd1d35b47d8943a#hello`),
|
> (e.g. `github:NixOS/nixpkgs/13d0c311e3ae923a00f734b43fd1d35b47d8943a#hello`),
|
||||||
> since in that case the "latest version" is always the same.
|
> since in that case the "latest version" is always the same.
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,7 @@ has the following fields:
|
||||||
the user at the time of installation (e.g. `nixpkgs`). This is also
|
the user at the time of installation (e.g. `nixpkgs`). This is also
|
||||||
the flake reference that will be used by `nix profile upgrade`.
|
the flake reference that will be used by `nix profile upgrade`.
|
||||||
|
|
||||||
* `uri`: The immutable flake reference to which `originalUrl`
|
* `uri`: The locked flake reference to which `originalUrl` resolved.
|
||||||
resolved.
|
|
||||||
|
|
||||||
* `attrPath`: The flake output attribute that provided this
|
* `attrPath`: The flake output attribute that provided this
|
||||||
package. Note that this is not necessarily the attribute that the
|
package. Note that this is not necessarily the attribute that the
|
||||||
|
|
|
@ -183,14 +183,12 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand
|
||||||
|
|
||||||
void run(nix::ref<nix::Store> store) override
|
void run(nix::ref<nix::Store> store) override
|
||||||
{
|
{
|
||||||
if (locked.empty()) {
|
if (locked.empty()) locked = url;
|
||||||
locked = url;
|
|
||||||
}
|
|
||||||
auto registry = getRegistry();
|
auto registry = getRegistry();
|
||||||
auto ref = parseFlakeRef(url);
|
auto ref = parseFlakeRef(url);
|
||||||
auto locked_ref = parseFlakeRef(locked);
|
auto lockedRef = parseFlakeRef(locked);
|
||||||
registry->remove(ref.input);
|
registry->remove(ref.input);
|
||||||
auto [tree, resolved] = locked_ref.resolve(store).input.fetch(store);
|
auto [tree, resolved] = lockedRef.resolve(store).input.fetch(store);
|
||||||
fetchers::Attrs extraAttrs;
|
fetchers::Attrs extraAttrs;
|
||||||
if (ref.subdir != "") extraAttrs["dir"] = ref.subdir;
|
if (ref.subdir != "") extraAttrs["dir"] = ref.subdir;
|
||||||
registry->add(ref.input, resolved, extraAttrs);
|
registry->add(ref.input, resolved, extraAttrs);
|
||||||
|
|
|
@ -29,3 +29,7 @@ nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
||||||
[[ $(nix-instantiate -A attr --eval "./eval.nix") == '{ foo = "bar"; }' ]]
|
[[ $(nix-instantiate -A attr --eval "./eval.nix") == '{ foo = "bar"; }' ]]
|
||||||
[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
|
[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
|
||||||
[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
|
[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
|
||||||
|
|
||||||
|
# Check that symlink cycles don't cause a hang.
|
||||||
|
ln -sfn cycle.nix $TEST_ROOT/cycle.nix
|
||||||
|
(! nix eval --file $TEST_ROOT/cycle.nix)
|
||||||
|
|
|
@ -122,6 +122,7 @@ git -C $repo commit -m 'Bla3' -a
|
||||||
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
||||||
[[ $path2 = $path4 ]]
|
[[ $path2 = $path4 ]]
|
||||||
|
|
||||||
|
status=0
|
||||||
nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$?
|
nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$?
|
||||||
[[ "$status" = "102" ]]
|
[[ "$status" = "102" ]]
|
||||||
|
|
||||||
|
|
17
tests/flakes/absolute-paths.sh
Normal file
17
tests/flakes/absolute-paths.sh
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
requireGit
|
||||||
|
|
||||||
|
flake1Dir=$TEST_ROOT/flake1
|
||||||
|
flake2Dir=$TEST_ROOT/flake2
|
||||||
|
|
||||||
|
createGitRepo $flake1Dir
|
||||||
|
cat > $flake1Dir/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
outputs = { self }: { x = builtins.readFile $(pwd)/absolute-paths.sh; };
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
git -C $flake1Dir add flake.nix
|
||||||
|
git -C $flake1Dir commit -m Initial
|
||||||
|
|
||||||
|
nix eval --impure --json $flake1Dir#x
|
|
@ -53,7 +53,11 @@ cat > $flake3Dir/flake.nix <<EOF
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
git -C $flake3Dir add flake.nix
|
cat > $flake3Dir/default.nix <<EOF
|
||||||
|
{ x = 123; }
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git -C $flake3Dir add flake.nix default.nix
|
||||||
git -C $flake3Dir commit -m 'Initial'
|
git -C $flake3Dir commit -m 'Initial'
|
||||||
|
|
||||||
cat > $nonFlakeDir/README.md <<EOF
|
cat > $nonFlakeDir/README.md <<EOF
|
||||||
|
@ -109,11 +113,12 @@ nix build -o $TEST_ROOT/result git+file://$flake1Dir
|
||||||
nix build -o $flake1Dir/result git+file://$flake1Dir
|
nix build -o $flake1Dir/result git+file://$flake1Dir
|
||||||
nix path-info $flake1Dir/result
|
nix path-info $flake1Dir/result
|
||||||
|
|
||||||
# 'getFlake' on a mutable flakeref should fail in pure mode, but succeed in impure mode.
|
# 'getFlake' on an unlocked flakeref should fail in pure mode, but
|
||||||
|
# succeed in impure mode.
|
||||||
(! nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default")
|
(! nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default")
|
||||||
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default" --impure
|
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default" --impure
|
||||||
|
|
||||||
# 'getFlake' on an immutable flakeref should succeed even in pure mode.
|
# 'getFlake' on a locked flakeref should succeed even in pure mode.
|
||||||
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"git+file://$flake1Dir?rev=$hash2\").packages.$system.default"
|
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"git+file://$flake1Dir?rev=$hash2\").packages.$system.default"
|
||||||
|
|
||||||
# Building a flake with an unlocked dependency should fail in pure mode.
|
# Building a flake with an unlocked dependency should fail in pure mode.
|
||||||
|
@ -460,7 +465,7 @@ nix flake lock $flake3Dir --update-input flake2/flake1
|
||||||
# Test 'nix flake metadata --json'.
|
# Test 'nix flake metadata --json'.
|
||||||
nix flake metadata $flake3Dir --json | jq .
|
nix flake metadata $flake3Dir --json | jq .
|
||||||
|
|
||||||
# Test flake in store does not evaluate
|
# Test flake in store does not evaluate.
|
||||||
rm -rf $badFlakeDir
|
rm -rf $badFlakeDir
|
||||||
mkdir $badFlakeDir
|
mkdir $badFlakeDir
|
||||||
echo INVALID > $badFlakeDir/flake.nix
|
echo INVALID > $badFlakeDir/flake.nix
|
||||||
|
|
30
tests/flakes/unlocked-override.sh
Normal file
30
tests/flakes/unlocked-override.sh
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
requireGit
|
||||||
|
|
||||||
|
flake1Dir=$TEST_ROOT/flake1
|
||||||
|
flake2Dir=$TEST_ROOT/flake2
|
||||||
|
|
||||||
|
createGitRepo $flake1Dir
|
||||||
|
cat > $flake1Dir/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
outputs = { self }: { x = import ./x.nix; };
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
echo 123 > $flake1Dir/x.nix
|
||||||
|
git -C $flake1Dir add flake.nix x.nix
|
||||||
|
git -C $flake1Dir commit -m Initial
|
||||||
|
|
||||||
|
createGitRepo $flake2Dir
|
||||||
|
cat > $flake2Dir/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
outputs = { self, flake1 }: { x = flake1.x; };
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
git -C $flake2Dir add flake.nix
|
||||||
|
|
||||||
|
[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 123 ]]
|
||||||
|
|
||||||
|
echo 456 > $flake1Dir/x.nix
|
||||||
|
|
||||||
|
[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 456 ]]
|
|
@ -11,7 +11,7 @@ expect_trace() {
|
||||||
--expr "$expr" 2>&1 \
|
--expr "$expr" 2>&1 \
|
||||||
| grep "function-trace" \
|
| grep "function-trace" \
|
||||||
| sed -e 's/ [0-9]*$//'
|
| sed -e 's/ [0-9]*$//'
|
||||||
);
|
)
|
||||||
|
|
||||||
echo -n "Tracing expression '$expr'"
|
echo -n "Tracing expression '$expr'"
|
||||||
set +e
|
set +e
|
||||||
|
|
|
@ -7,6 +7,8 @@ nix_tests = \
|
||||||
flakes/follow-paths.sh \
|
flakes/follow-paths.sh \
|
||||||
flakes/bundle.sh \
|
flakes/bundle.sh \
|
||||||
flakes/check.sh \
|
flakes/check.sh \
|
||||||
|
flakes/unlocked-override.sh \
|
||||||
|
flakes/absolute-paths.sh \
|
||||||
ca/gc.sh \
|
ca/gc.sh \
|
||||||
gc.sh \
|
gc.sh \
|
||||||
remote-store.sh \
|
remote-store.sh \
|
||||||
|
@ -110,7 +112,8 @@ nix_tests = \
|
||||||
fetchClosure.sh \
|
fetchClosure.sh \
|
||||||
completions.sh \
|
completions.sh \
|
||||||
impure-derivations.sh \
|
impure-derivations.sh \
|
||||||
path-from-hash-part.sh
|
path-from-hash-part.sh \
|
||||||
|
toString-path.sh
|
||||||
|
|
||||||
ifeq ($(HAVE_LIBCPUID), 1)
|
ifeq ($(HAVE_LIBCPUID), 1)
|
||||||
nix_tests += compute-levels.sh
|
nix_tests += compute-levels.sh
|
||||||
|
|
|
@ -9,3 +9,6 @@ nix-instantiate --eval -E '<by-relative-path/simple.nix>' --restrict-eval
|
||||||
|
|
||||||
# Should ideally also test this, but there’s no pure way to do it, so just trust me that it works
|
# Should ideally also test this, but there’s no pure way to do it, so just trust me that it works
|
||||||
# nix-instantiate --eval -E '<nixpkgs>' -I nixpkgs=channel:nixos-unstable --restrict-eval
|
# nix-instantiate --eval -E '<nixpkgs>' -I nixpkgs=channel:nixos-unstable --restrict-eval
|
||||||
|
|
||||||
|
[[ $(nix-instantiate --find-file by-absolute-path/simple.nix) = $PWD/simple.nix ]]
|
||||||
|
[[ $(nix-instantiate --find-file by-relative-path/simple.nix) = $PWD/simple.nix ]]
|
||||||
|
|
|
@ -3,7 +3,7 @@ source common.sh
|
||||||
clearStore
|
clearStore
|
||||||
|
|
||||||
nix-instantiate --restrict-eval --eval -E '1 + 2'
|
nix-instantiate --restrict-eval --eval -E '1 + 2'
|
||||||
(! nix-instantiate --restrict-eval ./restricted.nix)
|
(! nix-instantiate --eval --restrict-eval ./restricted.nix)
|
||||||
(! nix-instantiate --eval --restrict-eval <(echo '1 + 2'))
|
(! nix-instantiate --eval --restrict-eval <(echo '1 + 2'))
|
||||||
nix-instantiate --restrict-eval ./simple.nix -I src=.
|
nix-instantiate --restrict-eval ./simple.nix -I src=.
|
||||||
nix-instantiate --restrict-eval ./simple.nix -I src1=simple.nix -I src2=config.nix -I src3=./simple.builder.sh
|
nix-instantiate --restrict-eval ./simple.nix -I src1=simple.nix -I src2=config.nix -I src3=./simple.builder.sh
|
||||||
|
|
8
tests/toString-path.sh
Normal file
8
tests/toString-path.sh
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
source common.sh
|
||||||
|
|
||||||
|
mkdir -p $TEST_ROOT/foo
|
||||||
|
echo bla > $TEST_ROOT/foo/bar
|
||||||
|
|
||||||
|
[[ $(nix eval --raw --impure --expr "builtins.readFile (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"/bar\"))") = bla ]]
|
||||||
|
|
||||||
|
[[ $(nix eval --json --impure --expr "builtins.readDir (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; }))") = '{"bar":"regular"}' ]]
|
Loading…
Reference in a new issue