mirror of
https://github.com/NixOS/nix
synced 2025-06-29 23:13:14 +02:00
Merge remote-tracking branch 'origin/master' into lazy-trees
This commit is contained in:
commit
e2353b9b45
33 changed files with 196 additions and 55 deletions
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
@ -19,9 +19,9 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v17
|
- uses: cachix/install-nix-action@v18
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/cachix-action@v10
|
- uses: cachix/cachix-action@v11
|
||||||
if: needs.check_secrets.outputs.cachix == 'true'
|
if: needs.check_secrets.outputs.cachix == 'true'
|
||||||
with:
|
with:
|
||||||
name: '${{ env.CACHIX_NAME }}'
|
name: '${{ env.CACHIX_NAME }}'
|
||||||
|
@ -58,8 +58,8 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v17
|
- uses: cachix/install-nix-action@v18
|
||||||
- uses: cachix/cachix-action@v10
|
- uses: cachix/cachix-action@v11
|
||||||
with:
|
with:
|
||||||
name: '${{ env.CACHIX_NAME }}'
|
name: '${{ env.CACHIX_NAME }}'
|
||||||
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||||
|
@ -77,7 +77,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v17
|
- uses: cachix/install-nix-action@v18
|
||||||
with:
|
with:
|
||||||
install_url: '${{needs.installer.outputs.installerURL}}'
|
install_url: '${{needs.installer.outputs.installerURL}}'
|
||||||
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
||||||
|
@ -102,10 +102,10 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v17
|
- uses: cachix/install-nix-action@v18
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV
|
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV
|
||||||
- uses: cachix/cachix-action@v10
|
- uses: cachix/cachix-action@v11
|
||||||
if: needs.check_secrets.outputs.cachix == 'true'
|
if: needs.check_secrets.outputs.cachix == 'true'
|
||||||
with:
|
with:
|
||||||
name: '${{ env.CACHIX_NAME }}'
|
name: '${{ env.CACHIX_NAME }}'
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{ command }:
|
{ toplevel }:
|
||||||
|
|
||||||
with builtins;
|
with builtins;
|
||||||
with import <nix/utils.nix>;
|
with import <nix/utils.nix>;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
showCommand = { command, details, filename }:
|
showCommand = { command, details, filename, toplevel }:
|
||||||
let
|
let
|
||||||
result = ''
|
result = ''
|
||||||
> **Warning** \
|
> **Warning** \
|
||||||
|
@ -57,14 +57,15 @@ let
|
||||||
maybeOptions = if details.flags == {} then "" else ''
|
maybeOptions = if details.flags == {} then "" else ''
|
||||||
# Options
|
# Options
|
||||||
|
|
||||||
${showOptions details.flags}
|
${showOptions details.flags toplevel.flags}
|
||||||
'';
|
'';
|
||||||
showOptions = options:
|
showOptions = options: commonOptions:
|
||||||
let
|
let
|
||||||
|
allOptions = options // commonOptions;
|
||||||
showCategory = cat: ''
|
showCategory = cat: ''
|
||||||
${if cat != "" then "**${cat}:**" else ""}
|
${if cat != "" then "**${cat}:**" else ""}
|
||||||
|
|
||||||
${listOptions (filterAttrs (n: v: v.category == cat) options)}
|
${listOptions (filterAttrs (n: v: v.category == cat) allOptions)}
|
||||||
'';
|
'';
|
||||||
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
|
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
|
||||||
showOption = name: option:
|
showOption = name: option:
|
||||||
|
@ -76,30 +77,33 @@ let
|
||||||
|
|
||||||
${option.description}
|
${option.description}
|
||||||
'';
|
'';
|
||||||
categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues options)));
|
categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues allOptions)));
|
||||||
in concatStrings (map showCategory categories);
|
in concatStrings (map showCategory categories);
|
||||||
in squash result;
|
in squash result;
|
||||||
|
|
||||||
appendName = filename: name: (if filename == "nix" then "nix3" else filename) + "-" + name;
|
appendName = filename: name: (if filename == "nix" then "nix3" else filename) + "-" + name;
|
||||||
|
|
||||||
processCommand = { command, details, filename }:
|
processCommand = { command, details, filename, toplevel }:
|
||||||
let
|
let
|
||||||
cmd = {
|
cmd = {
|
||||||
inherit command;
|
inherit command;
|
||||||
name = filename + ".md";
|
name = filename + ".md";
|
||||||
value = showCommand { inherit command details filename; };
|
value = showCommand { inherit command details filename toplevel; };
|
||||||
};
|
};
|
||||||
subcommand = subCmd: processCommand {
|
subcommand = subCmd: processCommand {
|
||||||
command = command + " " + subCmd;
|
command = command + " " + subCmd;
|
||||||
details = details.commands.${subCmd};
|
details = details.commands.${subCmd};
|
||||||
filename = appendName filename subCmd;
|
filename = appendName filename subCmd;
|
||||||
|
inherit toplevel;
|
||||||
};
|
};
|
||||||
in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {});
|
in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {});
|
||||||
|
|
||||||
|
parsedToplevel = builtins.fromJSON toplevel;
|
||||||
manpages = processCommand {
|
manpages = processCommand {
|
||||||
command = "nix";
|
command = "nix";
|
||||||
details = builtins.fromJSON command;
|
details = parsedToplevel;
|
||||||
filename = "nix";
|
filename = "nix";
|
||||||
|
toplevel = parsedToplevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
tableOfContents = let
|
tableOfContents = let
|
||||||
|
|
|
@ -11,16 +11,16 @@ concatStrings (map
|
||||||
+ concatStrings (map (s: " ${s}\n") (splitLines option.description)) + "\n\n"
|
+ concatStrings (map (s: " ${s}\n") (splitLines option.description)) + "\n\n"
|
||||||
+ (if option.documentDefault
|
+ (if option.documentDefault
|
||||||
then " **Default:** " + (
|
then " **Default:** " + (
|
||||||
if option.value == "" || option.value == []
|
if option.defaultValue == "" || option.defaultValue == []
|
||||||
then "*empty*"
|
then "*empty*"
|
||||||
else if isBool option.value
|
else if isBool option.defaultValue
|
||||||
then (if option.value then "`true`" else "`false`")
|
then (if option.defaultValue then "`true`" else "`false`")
|
||||||
else
|
else
|
||||||
# n.b. a StringMap value type is specified as a string, but
|
# n.b. a StringMap value type is specified as a string, but
|
||||||
# this shows the value type. The empty stringmap is "null" in
|
# this shows the value type. The empty stringmap is "null" in
|
||||||
# JSON, but that converts to "{ }" here.
|
# JSON, but that converts to "{ }" here.
|
||||||
(if isAttrs option.value then "`\"\"`"
|
(if isAttrs option.defaultValue then "`\"\"`"
|
||||||
else "`" + toString option.value + "`")) + "\n\n"
|
else "`" + toString option.defaultValue + "`")) + "\n\n"
|
||||||
else " **Default:** *machine-specific*\n")
|
else " **Default:** *machine-specific*\n")
|
||||||
+ (if option.aliases != []
|
+ (if option.aliases != []
|
||||||
then " **Deprecated alias:** " + (concatStringsSep ", " (map (s: "`${s}`") option.aliases)) + "\n\n"
|
then " **Deprecated alias:** " + (concatStringsSep ", " (map (s: "`${s}`") option.aliases)) + "\n\n"
|
||||||
|
|
|
@ -50,7 +50,7 @@ $(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli
|
||||||
|
|
||||||
$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix
|
$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix
|
||||||
@rm -rf $@
|
@rm -rf $@
|
||||||
$(trace-gen) $(nix-eval) --write-to $@ --expr 'import doc/manual/generate-manpage.nix { command = builtins.readFile $<; }'
|
$(trace-gen) $(nix-eval) --write-to $@ --expr 'import doc/manual/generate-manpage.nix { toplevel = builtins.readFile $<; }'
|
||||||
|
|
||||||
$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix
|
$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix
|
||||||
@cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp
|
@cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp
|
||||||
|
|
|
@ -150,6 +150,20 @@
|
||||||
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
||||||
operation. `./a.${foo}/b.${bar}` is a path.
|
operation. `./a.${foo}/b.${bar}` is a path.
|
||||||
|
|
||||||
|
When a path appears in an antiquotation, and is thus coerced into a string,
|
||||||
|
the path is first copied into the Nix store and the resulting string is
|
||||||
|
the Nix store path. For instance `"${./foo.txt}" will cause `foo.txt` in
|
||||||
|
the current directory to be copied into the Nix store and result in the
|
||||||
|
string `"/nix/store/<HASH>-foo.txt"`.
|
||||||
|
|
||||||
|
Note that the Nix language assumes that all input files will remain
|
||||||
|
_unchanged_ during the course of the Nix expression evaluation.
|
||||||
|
If you for example antiquote a file path during a `nix repl` session, and
|
||||||
|
then later in the same session, after having changed the file contents,
|
||||||
|
evaluate the antiquotation with the file path again, then Nix will still
|
||||||
|
return the first store path. It will _not_ reread the file contents to
|
||||||
|
produce a different Nix store path.
|
||||||
|
|
||||||
- <a id="type-boolean" href="#type-boolean">Boolean</a>
|
- <a id="type-boolean" href="#type-boolean">Boolean</a>
|
||||||
|
|
||||||
*Booleans* with values `true` and `false`.
|
*Booleans* with values `true` and `false`.
|
||||||
|
|
|
@ -28,7 +28,9 @@ if test -n "$HOME" && test -n "$USER"
|
||||||
# Only use MANPATH if it is already set. In general `man` will just simply
|
# Only use MANPATH if it is already set. In general `man` will just simply
|
||||||
# pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin`
|
# pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin`
|
||||||
# which is in the $PATH. For more info, run `manpath -d`.
|
# which is in the $PATH. For more info, run `manpath -d`.
|
||||||
|
if set --query MANPATH
|
||||||
set --export --prepend --path MANPATH "$NIX_LINK/share/man"
|
set --export --prepend --path MANPATH "$NIX_LINK/share/man"
|
||||||
|
end
|
||||||
|
|
||||||
fish_add_path --prepend --global "$NIX_LINK/bin"
|
fish_add_path --prepend --global "$NIX_LINK/bin"
|
||||||
set --erase NIX_LINK
|
set --erase NIX_LINK
|
||||||
|
|
|
@ -88,7 +88,8 @@ EvalCommand::EvalCommand()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "debugger",
|
.longName = "debugger",
|
||||||
.description = "start an interactive environment if evaluation fails",
|
.description = "Start an interactive environment if evaluation fails.",
|
||||||
|
.category = MixEvalArgs::category,
|
||||||
.handler = {&startReplOnEvalErrors, true},
|
.handler = {&startReplOnEvalErrors, true},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -228,7 +229,7 @@ MixProfile::MixProfile()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "profile",
|
.longName = "profile",
|
||||||
.description = "The profile to update.",
|
.description = "The profile to operate on.",
|
||||||
.labels = {"path"},
|
.labels = {"path"},
|
||||||
.handler = {&profile},
|
.handler = {&profile},
|
||||||
.completer = completePath
|
.completer = completePath
|
||||||
|
|
|
@ -15,8 +15,6 @@ namespace nix {
|
||||||
|
|
||||||
MixEvalArgs::MixEvalArgs()
|
MixEvalArgs::MixEvalArgs()
|
||||||
{
|
{
|
||||||
auto category = "Common evaluation options";
|
|
||||||
|
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "arg",
|
.longName = "arg",
|
||||||
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
|
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
|
||||||
|
|
|
@ -11,6 +11,8 @@ struct SourcePath;
|
||||||
|
|
||||||
struct MixEvalArgs : virtual Args
|
struct MixEvalArgs : virtual Args
|
||||||
{
|
{
|
||||||
|
static constexpr auto category = "Common evaluation options";
|
||||||
|
|
||||||
MixEvalArgs();
|
MixEvalArgs();
|
||||||
|
|
||||||
Bindings * getAutoArgs(EvalState & state);
|
Bindings * getAutoArgs(EvalState & state);
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ struct CmdRepl : InstallablesCommand
|
||||||
evalSettings.pureEval = false;
|
evalSettings.pureEval = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare()
|
void prepare() override
|
||||||
{
|
{
|
||||||
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
||||||
warn("future versions of Nix will require using `--file` to load a file");
|
warn("future versions of Nix will require using `--file` to load a file");
|
||||||
|
|
|
@ -64,7 +64,7 @@ let
|
||||||
|
|
||||||
outputs = flake.outputs (inputs // { self = result; });
|
outputs = flake.outputs (inputs // { self = result; });
|
||||||
|
|
||||||
result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; };
|
result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; _type = "flake"; };
|
||||||
in
|
in
|
||||||
if node.flake or true then
|
if node.flake or true then
|
||||||
assert builtins.isFunction flake.outputs;
|
assert builtins.isFunction flake.outputs;
|
||||||
|
|
|
@ -3845,8 +3845,8 @@ static RegisterPrimOp primop_parseDrvName({
|
||||||
.args = {"s"},
|
.args = {"s"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Split the string *s* into a package name and version. The package
|
Split the string *s* into a package name and version. The package
|
||||||
name is everything up to but not including the first dash followed
|
name is everything up to but not including the first dash not followed
|
||||||
by a digit, and the version is everything following that dash. The
|
by a letter, and the version is everything following that dash. The
|
||||||
result is returned in a set `{ name, version }`. Thus,
|
result is returned in a set `{ name, version }`. Thus,
|
||||||
`builtins.parseDrvName "nix-0.12pre12876"` returns `{ name =
|
`builtins.parseDrvName "nix-0.12pre12876"` returns `{ name =
|
||||||
"nix"; version = "0.12pre12876"; }`.
|
"nix"; version = "0.12pre12876"; }`.
|
||||||
|
|
|
@ -32,6 +32,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "option",
|
.longName = "option",
|
||||||
.description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).",
|
.description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).",
|
||||||
|
.category = miscCategory,
|
||||||
.labels = {"name", "value"},
|
.labels = {"name", "value"},
|
||||||
.handler = {[](std::string name, std::string value) {
|
.handler = {[](std::string name, std::string value) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace nix {
|
||||||
|
|
||||||
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
|
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
|
||||||
static constexpr auto loggingCategory = "Logging-related options";
|
static constexpr auto loggingCategory = "Logging-related options";
|
||||||
|
static constexpr auto miscCategory = "Miscellaneous global options";
|
||||||
|
|
||||||
class MixCommonArgs : public virtual Args
|
class MixCommonArgs : public virtual Args
|
||||||
{
|
{
|
||||||
|
|
|
@ -503,7 +503,7 @@ public:
|
||||||
return s[0];
|
return s[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setPrintBuildLogs(bool printBuildLogs)
|
void setPrintBuildLogs(bool printBuildLogs) override
|
||||||
{
|
{
|
||||||
this->printBuildLogs = printBuildLogs;
|
this->printBuildLogs = printBuildLogs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,5 +113,25 @@ struct PrintFreed
|
||||||
/* Install a SIGSEGV handler to detect stack overflows. */
|
/* Install a SIGSEGV handler to detect stack overflows. */
|
||||||
void detectStackOverflow();
|
void detectStackOverflow();
|
||||||
|
|
||||||
|
/* Pluggable behavior to run in case of a stack overflow.
|
||||||
|
|
||||||
|
Default value: defaultStackOverflowHandler.
|
||||||
|
|
||||||
|
This is called by the handler installed by detectStackOverflow().
|
||||||
|
|
||||||
|
This gives Nix library consumers a limit opportunity to report the error
|
||||||
|
condition. The handler should exit the process.
|
||||||
|
See defaultStackOverflowHandler() for a reference implementation.
|
||||||
|
|
||||||
|
NOTE: Use with diligence, because this runs in the signal handler, with very
|
||||||
|
limited stack space and a potentially a corrupted heap, all while the failed
|
||||||
|
thread is blocked indefinitely. All functions called must be reentrant. */
|
||||||
|
extern std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler;
|
||||||
|
|
||||||
|
/* The default, robust implementation of stackOverflowHandler.
|
||||||
|
|
||||||
|
Prints an error message directly to stderr using a syscall instead of the
|
||||||
|
logger. Exits the process immediately after. */
|
||||||
|
void defaultStackOverflowHandler(siginfo_t * info, void * ctx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -29,9 +30,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
|
||||||
ptrdiff_t diff = (char *) info->si_addr - sp;
|
ptrdiff_t diff = (char *) info->si_addr - sp;
|
||||||
if (diff < 0) diff = -diff;
|
if (diff < 0) diff = -diff;
|
||||||
if (diff < 4096) {
|
if (diff < 4096) {
|
||||||
char msg[] = "error: stack overflow (possible infinite recursion)\n";
|
nix::stackOverflowHandler(info, ctx);
|
||||||
[[gnu::unused]] auto res = write(2, msg, strlen(msg));
|
|
||||||
_exit(1); // maybe abort instead?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,5 +66,12 @@ void detectStackOverflow()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler(defaultStackOverflowHandler);
|
||||||
|
|
||||||
|
void defaultStackOverflowHandler(siginfo_t * info, void * ctx) {
|
||||||
|
char msg[] = "error: stack overflow (possible infinite recursion)\n";
|
||||||
|
[[gnu::unused]] auto res = write(2, msg, strlen(msg));
|
||||||
|
_exit(1); // maybe abort instead?
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,6 +331,17 @@ bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath)
|
||||||
return fileExists(narInfoFileFor(storePath));
|
return fileExists(narInfoFileFor(storePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<StorePath> BinaryCacheStore::queryPathFromHashPart(const std::string & hashPart)
|
||||||
|
{
|
||||||
|
auto pseudoPath = StorePath(hashPart + "-" + MissingName);
|
||||||
|
try {
|
||||||
|
auto info = queryPathInfo(pseudoPath);
|
||||||
|
return info->path;
|
||||||
|
} catch (InvalidPath &) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
|
void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
|
||||||
{
|
{
|
||||||
auto info = queryPathInfo(storePath).cast<const NarInfo>();
|
auto info = queryPathInfo(storePath).cast<const NarInfo>();
|
||||||
|
|
|
@ -95,8 +95,7 @@ public:
|
||||||
void queryPathInfoUncached(const StorePath & path,
|
void queryPathInfoUncached(const StorePath & path,
|
||||||
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
|
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
|
||||||
|
|
||||||
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
|
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
|
||||||
{ unsupported("queryPathFromHashPart"); }
|
|
||||||
|
|
||||||
void addToStore(const ValidPathInfo & info, Source & narSource,
|
void addToStore(const ValidPathInfo & info, Source & narSource,
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
||||||
|
|
|
@ -1594,6 +1594,8 @@ void LocalDerivationGoal::runChild()
|
||||||
/* Warning: in the child we should absolutely not make any SQLite
|
/* Warning: in the child we should absolutely not make any SQLite
|
||||||
calls! */
|
calls! */
|
||||||
|
|
||||||
|
bool sendException = true;
|
||||||
|
|
||||||
try { /* child */
|
try { /* child */
|
||||||
|
|
||||||
commonChildInit(builderOut);
|
commonChildInit(builderOut);
|
||||||
|
@ -2050,6 +2052,8 @@ void LocalDerivationGoal::runChild()
|
||||||
/* Indicate that we managed to set up the build environment. */
|
/* Indicate that we managed to set up the build environment. */
|
||||||
writeFull(STDERR_FILENO, std::string("\2\n"));
|
writeFull(STDERR_FILENO, std::string("\2\n"));
|
||||||
|
|
||||||
|
sendException = false;
|
||||||
|
|
||||||
/* Execute the program. This should not return. */
|
/* Execute the program. This should not return. */
|
||||||
if (drv->isBuiltin()) {
|
if (drv->isBuiltin()) {
|
||||||
try {
|
try {
|
||||||
|
@ -2103,10 +2107,13 @@ void LocalDerivationGoal::runChild()
|
||||||
throw SysError("executing '%1%'", drv->builder);
|
throw SysError("executing '%1%'", drv->builder);
|
||||||
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
if (sendException) {
|
||||||
writeFull(STDERR_FILENO, "\1\n");
|
writeFull(STDERR_FILENO, "\1\n");
|
||||||
FdSink sink(STDERR_FILENO);
|
FdSink sink(STDERR_FILENO);
|
||||||
sink << e;
|
sink << e;
|
||||||
sink.flush();
|
sink.flush();
|
||||||
|
} else
|
||||||
|
std::cerr << e.msg();
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,13 +154,9 @@ StringSet Settings::getDefaultExtraPlatforms()
|
||||||
// machines. Note that we can’t force processes from executing
|
// machines. Note that we can’t force processes from executing
|
||||||
// x86_64 in aarch64 environments or vice versa since they can
|
// x86_64 in aarch64 environments or vice versa since they can
|
||||||
// always exec with their own binary preferences.
|
// always exec with their own binary preferences.
|
||||||
if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist") ||
|
if (std::string{SYSTEM} == "aarch64-darwin" &&
|
||||||
pathExists("/System/Library/LaunchDaemons/com.apple.oahd.plist")) {
|
runProgram(RunOptions {.program = "arch", .args = {"-arch", "x86_64", "/usr/bin/true"}, .mergeStderrToStdout = true}).first == 0)
|
||||||
if (std::string{SYSTEM} == "x86_64-darwin")
|
|
||||||
extraPlatforms.insert("aarch64-darwin");
|
|
||||||
else if (std::string{SYSTEM} == "aarch64-darwin")
|
|
||||||
extraPlatforms.insert("x86_64-darwin");
|
extraPlatforms.insert("x86_64-darwin");
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return extraPlatforms;
|
return extraPlatforms;
|
||||||
|
|
|
@ -67,7 +67,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
|
||||||
if (fakeSSH) {
|
if (fakeSSH) {
|
||||||
args = { "bash", "-c" };
|
args = { "bash", "-c" };
|
||||||
} else {
|
} else {
|
||||||
args = { "ssh", host.c_str(), "-x", "-a" };
|
args = { "ssh", host.c_str(), "-x" };
|
||||||
addCommonSSHOpts(args);
|
addCommonSSHOpts(args);
|
||||||
if (socketPath != "")
|
if (socketPath != "")
|
||||||
args.insert(args.end(), {"-S", socketPath});
|
args.insert(args.end(), {"-S", socketPath});
|
||||||
|
|
|
@ -1367,9 +1367,9 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
return std::make_shared<LocalStore>(params);
|
return std::make_shared<LocalStore>(params);
|
||||||
}
|
}
|
||||||
warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
||||||
} else
|
} else
|
||||||
debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
||||||
Store::Params params2;
|
Store::Params params2;
|
||||||
params2["root"] = chrootStore;
|
params2["root"] = chrootStore;
|
||||||
return std::make_shared<LocalStore>(params2);
|
return std::make_shared<LocalStore>(params2);
|
||||||
|
|
|
@ -66,7 +66,9 @@ UnresolvedApp Installable::toApp(EvalState & state)
|
||||||
|
|
||||||
auto type = cursor->getAttr("type")->getString();
|
auto type = cursor->getAttr("type")->getString();
|
||||||
|
|
||||||
std::string expected = !attrPath.empty() && state.symbols[attrPath[0]] == "apps" ? "app" : "derivation";
|
std::string expected = !attrPath.empty() &&
|
||||||
|
(state.symbols[attrPath[0]] == "apps" || state.symbols[attrPath[0]] == "defaultApp")
|
||||||
|
? "app" : "derivation";
|
||||||
if (type != expected)
|
if (type != expected)
|
||||||
throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
|
throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "help",
|
.longName = "help",
|
||||||
.description = "Show usage information.",
|
.description = "Show usage information.",
|
||||||
|
.category = miscCategory,
|
||||||
.handler = {[&]() { throw HelpRequested(); }},
|
.handler = {[&]() { throw HelpRequested(); }},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "version",
|
.longName = "version",
|
||||||
.description = "Show version information.",
|
.description = "Show version information.",
|
||||||
|
.category = miscCategory,
|
||||||
.handler = {[&]() { showVersion = true; }},
|
.handler = {[&]() { showVersion = true; }},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,12 +97,14 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
.longName = "offline",
|
.longName = "offline",
|
||||||
.aliases = {"no-net"}, // FIXME: remove
|
.aliases = {"no-net"}, // FIXME: remove
|
||||||
.description = "Disable substituters and consider all previously downloaded files up-to-date.",
|
.description = "Disable substituters and consider all previously downloaded files up-to-date.",
|
||||||
|
.category = miscCategory,
|
||||||
.handler = {[&]() { useNet = false; }},
|
.handler = {[&]() { useNet = false; }},
|
||||||
});
|
});
|
||||||
|
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "refresh",
|
.longName = "refresh",
|
||||||
.description = "Consider all previously downloaded files out-of-date.",
|
.description = "Consider all previously downloaded files out-of-date.",
|
||||||
|
.category = miscCategory,
|
||||||
.handler = {[&]() { refresh = true; }},
|
.handler = {[&]() { refresh = true; }},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -184,7 +188,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
|
||||||
);
|
);
|
||||||
|
|
||||||
auto attrs = state.buildBindings(16);
|
auto attrs = state.buildBindings(16);
|
||||||
attrs.alloc("command").mkString(toplevel.toJSON().dump());
|
attrs.alloc("toplevel").mkString(toplevel.toJSON().dump());
|
||||||
|
|
||||||
auto vRes = state.allocValue();
|
auto vRes = state.allocValue();
|
||||||
state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
|
state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
|
||||||
|
|
39
src/nix/path-from-hash-part.cc
Normal file
39
src/nix/path-from-hash-part.cc
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "command.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
using namespace nix;
|
||||||
|
|
||||||
|
struct CmdPathFromHashPart : StoreCommand
|
||||||
|
{
|
||||||
|
std::string hashPart;
|
||||||
|
|
||||||
|
CmdPathFromHashPart()
|
||||||
|
{
|
||||||
|
expectArgs({
|
||||||
|
.label = "hash-part",
|
||||||
|
.handler = {&hashPart},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return "get a store path from its hash part";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string doc() override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#include "path-from-hash-part.md"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(ref<Store> store) override
|
||||||
|
{
|
||||||
|
if (auto storePath = store->queryPathFromHashPart(hashPart))
|
||||||
|
logger->cout(store->printStorePath(*storePath));
|
||||||
|
else
|
||||||
|
throw Error("there is no store path corresponding to '%s'", hashPart);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto rCmdPathFromHashPart = registerCommand2<CmdPathFromHashPart>({"store", "path-from-hash-part"});
|
20
src/nix/path-from-hash-part.md
Normal file
20
src/nix/path-from-hash-part.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
R""(
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
* Return the full store path with the given hash part:
|
||||||
|
|
||||||
|
```console
|
||||||
|
# nix store path-from-hash-part --store https://cache.nixos.org/ 0i2jd68mp5g6h2sa5k9c85rb80sn8hi9
|
||||||
|
/nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
|
||||||
|
```
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
Given the hash part of a store path (that is, the 32 characters
|
||||||
|
following `/nix/store/`), return the full store path. This is
|
||||||
|
primarily useful in the implementation of binary caches, where a
|
||||||
|
request for a `.narinfo` file only supplies the hash part
|
||||||
|
(e.g. `https://cache.nixos.org/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9.narinfo`).
|
||||||
|
|
||||||
|
)""
|
|
@ -36,7 +36,7 @@ R""(
|
||||||
Loading Installable ''...
|
Loading Installable ''...
|
||||||
Added 1 variables.
|
Added 1 variables.
|
||||||
|
|
||||||
# nix repl --extra_experimental_features 'flakes repl-flake' nixpkgs
|
# nix repl --extra-experimental-features 'flakes repl-flake' nixpkgs
|
||||||
Loading Installable 'flake:nixpkgs#'...
|
Loading Installable 'flake:nixpkgs#'...
|
||||||
Added 5 variables.
|
Added 5 variables.
|
||||||
|
|
||||||
|
|
1
tests/lang/eval-okay-eq.exp
Normal file
1
tests/lang/eval-okay-eq.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
true
|
|
@ -1 +0,0 @@
|
||||||
Bool(True)
|
|
|
@ -4,6 +4,7 @@ let
|
||||||
name2 = "hello";
|
name2 = "hello";
|
||||||
name3 = "915resolution-0.5.2";
|
name3 = "915resolution-0.5.2";
|
||||||
name4 = "xf86-video-i810-1.7.4";
|
name4 = "xf86-video-i810-1.7.4";
|
||||||
|
name5 = "name-that-ends-with-dash--1.0";
|
||||||
|
|
||||||
eq = 0;
|
eq = 0;
|
||||||
lt = builtins.sub 0 1;
|
lt = builtins.sub 0 1;
|
||||||
|
@ -23,6 +24,8 @@ let
|
||||||
((builtins.parseDrvName name3).version == "0.5.2")
|
((builtins.parseDrvName name3).version == "0.5.2")
|
||||||
((builtins.parseDrvName name4).name == "xf86-video-i810")
|
((builtins.parseDrvName name4).name == "xf86-video-i810")
|
||||||
((builtins.parseDrvName name4).version == "1.7.4")
|
((builtins.parseDrvName name4).version == "1.7.4")
|
||||||
|
((builtins.parseDrvName name5).name == "name-that-ends-with-dash")
|
||||||
|
((builtins.parseDrvName name5).version == "-1.0")
|
||||||
(versionTest "1.0" "2.3" lt)
|
(versionTest "1.0" "2.3" lt)
|
||||||
(versionTest "2.1" "2.3" lt)
|
(versionTest "2.1" "2.3" lt)
|
||||||
(versionTest "2.3" "2.3" eq)
|
(versionTest "2.3" "2.3" eq)
|
||||||
|
|
|
@ -111,6 +111,7 @@ nix_tests = \
|
||||||
fetchClosure.sh \
|
fetchClosure.sh \
|
||||||
completions.sh \
|
completions.sh \
|
||||||
impure-derivations.sh \
|
impure-derivations.sh \
|
||||||
|
path-from-hash-part.sh \
|
||||||
toString-path.sh
|
toString-path.sh
|
||||||
|
|
||||||
ifeq ($(HAVE_LIBCPUID), 1)
|
ifeq ($(HAVE_LIBCPUID), 1)
|
||||||
|
|
10
tests/path-from-hash-part.sh
Normal file
10
tests/path-from-hash-part.sh
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
source common.sh
|
||||||
|
|
||||||
|
path=$(nix build --no-link --print-out-paths -f simple.nix)
|
||||||
|
|
||||||
|
hash_part=$(basename $path)
|
||||||
|
hash_part=${hash_part:0:32}
|
||||||
|
|
||||||
|
path2=$(nix store path-from-hash-part $hash_part)
|
||||||
|
|
||||||
|
[[ $path = $path2 ]]
|
Loading…
Add table
Add a link
Reference in a new issue