mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 07:16:17 +02:00
Merge remote-tracking branch 'nixos/master'
This commit is contained in:
commit
9080d4c520
46 changed files with 670 additions and 153 deletions
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
name: Missing or incorrect documentation
|
name: Missing or incorrect documentation
|
||||||
about:
|
about: Help us improve the reference manual
|
||||||
title: ''
|
title: ''
|
||||||
labels: 'documentation'
|
labels: documentation
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,97 +1,114 @@
|
||||||
{ command }:
|
{ toplevel }:
|
||||||
|
|
||||||
with builtins;
|
with builtins;
|
||||||
with import ./utils.nix;
|
with import ./utils.nix;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
showCommand =
|
showCommand = { command, details, filename, toplevel }:
|
||||||
{ command, def, filename }:
|
|
||||||
''
|
|
||||||
**Warning**: This program is **experimental** and its interface is subject to change.
|
|
||||||
''
|
|
||||||
+ "# Name\n\n"
|
|
||||||
+ "`${command}` - ${def.description}\n\n"
|
|
||||||
+ "# Synopsis\n\n"
|
|
||||||
+ showSynopsis { inherit command; args = def.args; }
|
|
||||||
+ (if def.commands or {} != {}
|
|
||||||
then
|
|
||||||
let
|
let
|
||||||
categories = sort (x: y: x.id < y.id) (unique (map (cmd: cmd.category) (attrValues def.commands)));
|
result = ''
|
||||||
listCommands = cmds:
|
> **Warning** \
|
||||||
concatStrings (map (name:
|
> This program is **experimental** and its interface is subject to change.
|
||||||
"* "
|
|
||||||
+ "[`${command} ${name}`](./${appendName filename name}.md)"
|
# Name
|
||||||
+ " - ${cmds.${name}.description}\n")
|
|
||||||
(attrNames cmds));
|
`${command}` - ${details.description}
|
||||||
in
|
|
||||||
"where *subcommand* is one of the following:\n\n"
|
# Synopsis
|
||||||
# FIXME: group by category
|
|
||||||
+ (if length categories > 1
|
${showSynopsis command details.args}
|
||||||
then
|
|
||||||
concatStrings (map
|
${maybeSubcommands}
|
||||||
(cat:
|
|
||||||
"**${toString cat.description}:**\n\n"
|
${maybeDocumentation}
|
||||||
+ listCommands (filterAttrs (n: v: v.category == cat) def.commands)
|
|
||||||
+ "\n"
|
${maybeOptions}
|
||||||
) categories)
|
'';
|
||||||
+ "\n"
|
showSynopsis = command: args:
|
||||||
else
|
let
|
||||||
listCommands def.commands
|
showArgument = arg: "*${arg.label}*" + (if arg ? arity then "" else "...");
|
||||||
+ "\n")
|
arguments = concatStringsSep " " (map showArgument args);
|
||||||
else "")
|
in ''
|
||||||
+ (if def ? doc
|
`${command}` [*option*...] ${arguments}
|
||||||
then def.doc + "\n\n"
|
'';
|
||||||
else "")
|
maybeSubcommands = if details ? commands && details.commands != {}
|
||||||
+ (let s = showOptions def.flags; in
|
then ''
|
||||||
if s != ""
|
where *subcommand* is one of the following:
|
||||||
then "# Options\n\n${s}"
|
|
||||||
else "")
|
${subcommands}
|
||||||
;
|
''
|
||||||
|
else "";
|
||||||
|
subcommands = if length categories > 1
|
||||||
|
then listCategories
|
||||||
|
else listSubcommands details.commands;
|
||||||
|
categories = sort (x: y: x.id < y.id) (unique (map (cmd: cmd.category) (attrValues details.commands)));
|
||||||
|
listCategories = concatStrings (map showCategory categories);
|
||||||
|
showCategory = cat: ''
|
||||||
|
**${toString cat.description}:**
|
||||||
|
|
||||||
|
${listSubcommands (filterAttrs (n: v: v.category == cat) details.commands)}
|
||||||
|
'';
|
||||||
|
listSubcommands = cmds: concatStrings (attrValues (mapAttrs showSubcommand cmds));
|
||||||
|
showSubcommand = name: subcmd: ''
|
||||||
|
* [`${command} ${name}`](./${appendName filename name}.md) - ${subcmd.description}
|
||||||
|
'';
|
||||||
|
maybeDocumentation = if details ? doc then details.doc else "";
|
||||||
|
maybeOptions = if details.flags == {} then "" else ''
|
||||||
|
# Options
|
||||||
|
|
||||||
|
${showOptions details.flags toplevel.flags}
|
||||||
|
'';
|
||||||
|
showOptions = options: commonOptions:
|
||||||
|
let
|
||||||
|
allOptions = options // commonOptions;
|
||||||
|
showCategory = cat: ''
|
||||||
|
${if cat != "" then "**${cat}:**" else ""}
|
||||||
|
|
||||||
|
${listOptions (filterAttrs (n: v: v.category == cat) allOptions)}
|
||||||
|
'';
|
||||||
|
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
|
||||||
|
showOption = name: option:
|
||||||
|
let
|
||||||
|
shortName = if option ? shortName then "/ `-${option.shortName}`" else "";
|
||||||
|
labels = if option ? labels then (concatStringsSep " " (map (s: "*${s}*") option.labels)) else "";
|
||||||
|
in trim ''
|
||||||
|
- `--${name}` ${shortName} ${labels}
|
||||||
|
|
||||||
|
${option.description}
|
||||||
|
'';
|
||||||
|
categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues allOptions)));
|
||||||
|
in concatStrings (map showCategory categories);
|
||||||
|
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;
|
||||||
|
|
||||||
showOptions = flags:
|
processCommand = { command, details, filename, toplevel }:
|
||||||
let
|
let
|
||||||
categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues flags)));
|
cmd = {
|
||||||
in
|
inherit command;
|
||||||
concatStrings (map
|
name = filename + ".md";
|
||||||
(cat:
|
value = showCommand { inherit command details filename toplevel; };
|
||||||
(if cat != ""
|
};
|
||||||
then "**${cat}:**\n\n"
|
subcommand = subCmd: processCommand {
|
||||||
else "")
|
command = command + " " + subCmd;
|
||||||
+ concatStrings
|
details = details.commands.${subCmd};
|
||||||
(map (longName:
|
filename = appendName filename subCmd;
|
||||||
let
|
inherit toplevel;
|
||||||
flag = flags.${longName};
|
};
|
||||||
in
|
in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {});
|
||||||
" - `--${longName}`"
|
|
||||||
+ (if flag ? shortName then " / `-${flag.shortName}`" else "")
|
|
||||||
+ (if flag ? labels then " " + (concatStringsSep " " (map (s: "*${s}*") flag.labels)) else "")
|
|
||||||
+ " \n"
|
|
||||||
+ " " + flag.description + "\n\n"
|
|
||||||
) (attrNames (filterAttrs (n: v: v.category == cat) flags))))
|
|
||||||
categories);
|
|
||||||
|
|
||||||
showSynopsis =
|
parsedToplevel = builtins.fromJSON toplevel;
|
||||||
{ command, args }:
|
manpages = processCommand {
|
||||||
"`${command}` [*option*...] ${concatStringsSep " "
|
command = "nix";
|
||||||
(map (arg: "*${arg.label}*" + (if arg ? arity then "" else "...")) args)}\n\n";
|
details = parsedToplevel;
|
||||||
|
filename = "nix";
|
||||||
|
toplevel = parsedToplevel;
|
||||||
|
};
|
||||||
|
|
||||||
processCommand = { command, def, filename }:
|
tableOfContents = let
|
||||||
[ { name = filename + ".md"; value = showCommand { inherit command def filename; }; inherit command; } ]
|
showEntry = page:
|
||||||
++ concatMap
|
" - [${page.command}](command-ref/new-cli/${page.name})";
|
||||||
(name: processCommand {
|
in concatStringsSep "\n" (map showEntry manpages) + "\n";
|
||||||
filename = appendName filename name;
|
|
||||||
command = command + " " + name;
|
|
||||||
def = def.commands.${name};
|
|
||||||
})
|
|
||||||
(attrNames def.commands or {});
|
|
||||||
|
|
||||||
in
|
in (listToAttrs manpages) // { "SUMMARY.md" = tableOfContents; }
|
||||||
|
|
||||||
let
|
|
||||||
manpages = processCommand { filename = "nix"; command = "nix"; def = builtins.fromJSON command; };
|
|
||||||
summary = concatStrings (map (manpage: " - [${manpage.command}](command-ref/new-cli/${manpage.name})\n") manpages);
|
|
||||||
in
|
|
||||||
(listToAttrs manpages) // { "SUMMARY.md" = summary; }
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -30,8 +30,8 @@ Since `nix-copy-closure` calls `ssh`, you may be asked to type in the
|
||||||
appropriate password or passphrase. In fact, you may be asked _twice_
|
appropriate password or passphrase. In fact, you may be asked _twice_
|
||||||
because `nix-copy-closure` currently connects twice to the remote
|
because `nix-copy-closure` currently connects twice to the remote
|
||||||
machine, first to get the set of paths missing on the target machine,
|
machine, first to get the set of paths missing on the target machine,
|
||||||
and second to send the dump of those paths. If this bothers you, use
|
and second to send the dump of those paths. When using public key
|
||||||
`ssh-agent`.
|
authentication, you can avoid typing the passphrase with `ssh-agent`.
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ $ nix develop
|
||||||
```
|
```
|
||||||
|
|
||||||
To get a shell with a different compilation environment (e.g. stdenv,
|
To get a shell with a different compilation environment (e.g. stdenv,
|
||||||
gccStdenv, clangStdenv, clang11Stdenv):
|
gccStdenv, clangStdenv, clang11Stdenv, ccacheStdenv):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -A devShells.x86_64-linux.clang11StdenvPackages
|
$ nix-shell -A devShells.x86_64-linux.clang11StdenvPackages
|
||||||
|
@ -54,6 +54,9 @@ or if you have a flake-enabled nix:
|
||||||
$ nix develop .#clang11StdenvPackages
|
$ nix develop .#clang11StdenvPackages
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: you can use `ccacheStdenv` to drastically improve rebuild
|
||||||
|
time. By default, ccache keeps artifacts in `~/.cache/ccache/`.
|
||||||
|
|
||||||
To build Nix itself in this shell:
|
To build Nix itself in this shell:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
@ -83,9 +86,7 @@ by:
|
||||||
$ nix develop
|
$ nix develop
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## Running tests
|
||||||
|
|
||||||
Nix comes with three different flavors of tests: unit, functional and integration.
|
|
||||||
|
|
||||||
### Unit-tests
|
### Unit-tests
|
||||||
|
|
||||||
|
@ -108,3 +109,72 @@ These tests include everything that needs to interact with external services or
|
||||||
Because these tests are expensive and require more than what the standard github-actions setup provides, they only run on the master branch (on <https://hydra.nixos.org/jobset/nix/master>).
|
Because these tests are expensive and require more than what the standard github-actions setup provides, they only run on the master branch (on <https://hydra.nixos.org/jobset/nix/master>).
|
||||||
|
|
||||||
You can run them manually with `nix build .#hydraJobs.tests.{testName}` or `nix-build -A hydraJobs.tests.{testName}`
|
You can run them manually with `nix build .#hydraJobs.tests.{testName}` or `nix-build -A hydraJobs.tests.{testName}`
|
||||||
|
|
||||||
|
### Installer tests
|
||||||
|
|
||||||
|
After a one-time setup, the Nix repository's GitHub Actions continuous integration (CI) workflow can test the installer each time you push to a branch.
|
||||||
|
|
||||||
|
Creating a Cachix cache for your installer tests and adding its authorization token to GitHub enables [two installer-specific jobs in the CI workflow](https://github.com/NixOS/nix/blob/88a45d6149c0e304f6eb2efcc2d7a4d0d569f8af/.github/workflows/ci.yml#L50-L91):
|
||||||
|
|
||||||
|
- The `installer` job generates installers for the platforms below and uploads them to your Cachix cache:
|
||||||
|
- `x86_64-linux`
|
||||||
|
- `armv6l-linux`
|
||||||
|
- `armv7l-linux`
|
||||||
|
- `x86_64-darwin`
|
||||||
|
|
||||||
|
- The `installer_test` job (which runs on `ubuntu-latest` and `macos-latest`) will try to install Nix with the cached installer and run a trivial Nix command.
|
||||||
|
|
||||||
|
#### One-time setup
|
||||||
|
|
||||||
|
1. Have a GitHub account with a fork of the [Nix repository](https://github.com/NixOS/nix).
|
||||||
|
2. At cachix.org:
|
||||||
|
- Create or log in to an account.
|
||||||
|
- Create a Cachix cache using the format `<github-username>-nix-install-tests`.
|
||||||
|
- Navigate to the new cache > Settings > Auth Tokens.
|
||||||
|
- Generate a new Cachix auth token and copy the generated value.
|
||||||
|
3. At github.com:
|
||||||
|
- Navigate to your Nix fork > Settings > Secrets > Actions > New repository secret.
|
||||||
|
- Name the secret `CACHIX_AUTH_TOKEN`.
|
||||||
|
- Paste the copied value of the Cachix cache auth token.
|
||||||
|
|
||||||
|
#### Using the CI-generated installer for manual testing
|
||||||
|
|
||||||
|
After the CI run completes, you can check the output to extract the installer URL:
|
||||||
|
1. Click into the detailed view of the CI run.
|
||||||
|
2. Click into any `installer_test` run (the URL you're here to extract will be the same in all of them).
|
||||||
|
3. Click into the `Run cachix/install-nix-action@v...` step and click the detail triangle next to the first log line (it will also be `Run cachix/install-nix-action@v...`)
|
||||||
|
4. Copy the value of `install_url`
|
||||||
|
5. To generate an install command, plug this `install_url` and your GitHub username into this template:
|
||||||
|
|
||||||
|
```console
|
||||||
|
sh <(curl -L <install_url>) --tarball-url-prefix https://<github-username>-nix-install-tests.cachix.org/serve
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- #### Manually generating test installers
|
||||||
|
|
||||||
|
There's obviously a manual way to do this, and it's still the only way for
|
||||||
|
platforms that lack GA runners.
|
||||||
|
|
||||||
|
I did do this back in Fall 2020 (before the GA approach encouraged here). I'll
|
||||||
|
sketch what I recall in case it encourages someone to fill in detail, but: I
|
||||||
|
didn't know what I was doing at the time and had to fumble/ask around a lot--
|
||||||
|
so I don't want to uphold any of it as "right". It may have been dumb or
|
||||||
|
the _hard_ way from the getgo. Fundamentals may have changed since.
|
||||||
|
|
||||||
|
Here's the build command I used to do this on and for x86_64-darwin:
|
||||||
|
nix build --out-link /tmp/foo ".#checks.x86_64-darwin.binaryTarball"
|
||||||
|
|
||||||
|
I used the stable out-link to make it easier to script the next steps:
|
||||||
|
link=$(readlink /tmp/foo)
|
||||||
|
cp $link/*-darwin.tar.xz ~/somewheres
|
||||||
|
|
||||||
|
I've lost the last steps and am just going from memory:
|
||||||
|
|
||||||
|
From here, I think I had to extract and modify the `install` script to point
|
||||||
|
it at this tarball (which I scped to my own site, but it might make more sense
|
||||||
|
to just share them locally). I extracted this script once and then just
|
||||||
|
search/replaced in it for each new build.
|
||||||
|
|
||||||
|
The installer now supports a `--tarball-url-prefix` flag which _may_ have
|
||||||
|
solved this need?
|
||||||
|
-->
|
||||||
|
|
|
@ -7,10 +7,44 @@
|
||||||
translated into low-level *store derivations* (implicitly by
|
translated into low-level *store derivations* (implicitly by
|
||||||
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
||||||
|
|
||||||
|
- [content-addressed derivation]{#gloss-content-addressed-derivation}\
|
||||||
|
A derivation which has the
|
||||||
|
[`__contentAddressed`](language/advanced-attributes.md#adv-attr-__contentAddressed)
|
||||||
|
attribute set to `true`.
|
||||||
|
|
||||||
|
- [fixed-output derivation]{#gloss-fixed-output-derivation}\
|
||||||
|
A derivation which includes the
|
||||||
|
[`outputHash`](language/advanced-attributes.md#adv-attr-outputHash) attribute.
|
||||||
|
|
||||||
- [store]{#gloss-store}\
|
- [store]{#gloss-store}\
|
||||||
The location in the file system where store objects live. Typically
|
The location in the file system where store objects live. Typically
|
||||||
`/nix/store`.
|
`/nix/store`.
|
||||||
|
|
||||||
|
From the perspective of the location where Nix is
|
||||||
|
invoked, the Nix store can be referred to
|
||||||
|
as a "_local_" or a "_remote_" one:
|
||||||
|
|
||||||
|
+ A *local store* exists on the filesystem of
|
||||||
|
the machine where Nix is invoked. You can use other
|
||||||
|
local stores by passing the `--store` flag to the
|
||||||
|
`nix` command. Local stores can be used for building derivations.
|
||||||
|
|
||||||
|
+ A *remote store* exists anywhere other than the
|
||||||
|
local filesystem. One example is the `/nix/store`
|
||||||
|
directory on another machine, accessed via `ssh` or
|
||||||
|
served by the `nix-serve` Perl script.
|
||||||
|
|
||||||
|
- [chroot store]{#gloss-chroot-store}\
|
||||||
|
A local store whose canonical path is anything other than `/nix/store`.
|
||||||
|
|
||||||
|
- [binary cache]{#gloss-binary-cache}\
|
||||||
|
A *binary cache* is a Nix store which uses a different format: its
|
||||||
|
metadata and signatures are kept in `.narinfo` files rather than in a
|
||||||
|
Nix database. This different format simplifies serving store objects
|
||||||
|
over the network, but cannot host builds. Examples of binary caches
|
||||||
|
include S3 buckets and the [NixOS binary
|
||||||
|
cache](https://cache.nixos.org).
|
||||||
|
|
||||||
- [store path]{#gloss-store-path}\
|
- [store path]{#gloss-store-path}\
|
||||||
The location in the file system of a store object, i.e., an
|
The location in the file system of a store object, i.e., an
|
||||||
immediate child of the Nix store directory.
|
immediate child of the Nix store directory.
|
||||||
|
@ -22,6 +56,19 @@
|
||||||
derivation outputs (objects produced by running a build action), or
|
derivation outputs (objects produced by running a build action), or
|
||||||
derivations (files describing a build action).
|
derivations (files describing a build action).
|
||||||
|
|
||||||
|
- [input-addressed store object]{#gloss-input-addressed-store-object}\
|
||||||
|
A store object produced by building a
|
||||||
|
non-[content-addressed](#gloss-content-addressed-derivation),
|
||||||
|
non-[fixed-output](#gloss-fixed-output-derivation)
|
||||||
|
derivation.
|
||||||
|
|
||||||
|
- [output-addressed store object]{#gloss-output-addressed-store-object}\
|
||||||
|
A store object whose store path hashes its content. This
|
||||||
|
includes derivations, the outputs of
|
||||||
|
[content-addressed derivations](#gloss-content-addressed-derivation),
|
||||||
|
and the outputs of
|
||||||
|
[fixed-output derivations](#gloss-fixed-output-derivation).
|
||||||
|
|
||||||
- [substitute]{#gloss-substitute}\
|
- [substitute]{#gloss-substitute}\
|
||||||
A substitute is a command invocation stored in the Nix database that
|
A substitute is a command invocation stored in the Nix database that
|
||||||
describes how to build a store object, bypassing the normal build
|
describes how to build a store object, bypassing the normal build
|
||||||
|
@ -29,6 +76,11 @@
|
||||||
store object by downloading a pre-built version of the store object
|
store object by downloading a pre-built version of the store object
|
||||||
from some server.
|
from some server.
|
||||||
|
|
||||||
|
- [substituter]{#gloss-substituter}\
|
||||||
|
A *substituter* is an additional store from which Nix will
|
||||||
|
copy store objects it doesn't have. For details, see the
|
||||||
|
[`substituters` option](command-ref/conf-file.html#conf-substituters).
|
||||||
|
|
||||||
- [purity]{#gloss-purity}\
|
- [purity]{#gloss-purity}\
|
||||||
The assumption that equal Nix derivations when run always produce
|
The assumption that equal Nix derivations when run always produce
|
||||||
the same output. This cannot be guaranteed in general (e.g., a
|
the same output. This cannot be guaranteed in general (e.g., a
|
||||||
|
|
|
@ -5,6 +5,32 @@ rec {
|
||||||
|
|
||||||
concatStrings = concatStringsSep "";
|
concatStrings = concatStringsSep "";
|
||||||
|
|
||||||
|
replaceStringsRec = from: to: string:
|
||||||
|
# recursively replace occurrences of `from` with `to` within `string`
|
||||||
|
# example:
|
||||||
|
# replaceStringRec "--" "-" "hello-----world"
|
||||||
|
# => "hello-world"
|
||||||
|
let
|
||||||
|
replaced = replaceStrings [ from ] [ to ] string;
|
||||||
|
in
|
||||||
|
if replaced == string then string else replaceStringsRec from to replaced;
|
||||||
|
|
||||||
|
squash = replaceStringsRec "\n\n\n" "\n\n";
|
||||||
|
|
||||||
|
trim = string:
|
||||||
|
# trim trailing spaces and squash non-leading spaces
|
||||||
|
let
|
||||||
|
trimLine = line:
|
||||||
|
let
|
||||||
|
# separate leading spaces from the rest
|
||||||
|
parts = split "(^ *)" line;
|
||||||
|
spaces = head (elemAt parts 1);
|
||||||
|
rest = elemAt parts 2;
|
||||||
|
# drop trailing spaces
|
||||||
|
body = head (split " *$" rest);
|
||||||
|
in spaces + replaceStringsRec " " " " body;
|
||||||
|
in concatStringsSep "\n" (map trimLine (splitLines string));
|
||||||
|
|
||||||
# FIXME: O(n^2)
|
# FIXME: O(n^2)
|
||||||
unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [];
|
unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [];
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ let
|
||||||
|
|
||||||
root = {
|
root = {
|
||||||
uid = 0;
|
uid = 0;
|
||||||
shell = "/bin/bash";
|
shell = "${pkgs.bashInteractive}/bin/bash";
|
||||||
home = "/root";
|
home = "/root";
|
||||||
gid = 0;
|
gid = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
crossSystems = [ "armv6l-linux" "armv7l-linux" ];
|
crossSystems = [ "armv6l-linux" "armv7l-linux" ];
|
||||||
|
|
||||||
stdenvs = [ "gccStdenv" "gcc10Stdenv" "clangStdenv" "clang11Stdenv" "stdenv" "libcxxStdenv" ];
|
stdenvs = [ "gccStdenv" "clangStdenv" "clang11Stdenv" "stdenv" "libcxxStdenv" "ccacheStdenv" ];
|
||||||
|
|
||||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
||||||
forAllSystemsAndStdenvs = f: forAllSystems (system:
|
forAllSystemsAndStdenvs = f: forAllSystems (system:
|
||||||
|
@ -546,6 +546,11 @@
|
||||||
# againstLatestStable = testNixVersions pkgs pkgs.nix pkgs.nixStable;
|
# againstLatestStable = testNixVersions pkgs pkgs.nix pkgs.nixStable;
|
||||||
} "touch $out");
|
} "touch $out");
|
||||||
|
|
||||||
|
installerTests = import ./tests/installer {
|
||||||
|
binaryTarballs = self.hydraJobs.binaryTarball;
|
||||||
|
inherit nixpkgsFor;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
checks = forAllSystems (system: {
|
checks = forAllSystems (system: {
|
||||||
|
|
|
@ -40,12 +40,12 @@ case "$(uname -s).$(uname -m)" in
|
||||||
path=@tarballPath_aarch64-linux@
|
path=@tarballPath_aarch64-linux@
|
||||||
system=aarch64-linux
|
system=aarch64-linux
|
||||||
;;
|
;;
|
||||||
Linux.armv6l_linux)
|
Linux.armv6l)
|
||||||
hash=@tarballHash_armv6l-linux@
|
hash=@tarballHash_armv6l-linux@
|
||||||
path=@tarballPath_armv6l-linux@
|
path=@tarballPath_armv6l-linux@
|
||||||
system=armv6l-linux
|
system=armv6l-linux
|
||||||
;;
|
;;
|
||||||
Linux.armv7l_linux)
|
Linux.armv7l)
|
||||||
hash=@tarballHash_armv7l-linux@
|
hash=@tarballHash_armv7l-linux@
|
||||||
path=@tarballPath_armv7l-linux@
|
path=@tarballPath_armv7l-linux@
|
||||||
system=armv7l-linux
|
system=armv7l-linux
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Only execute this file once per shell.
|
# Only execute this file once per shell.
|
||||||
if test -n "$__ETC_PROFILE_NIX_SOURCED"
|
if test -n "$__ETC_PROFILE_NIX_SOURCED"
|
||||||
return
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
set __ETC_PROFILE_NIX_SOURCED 1
|
set __ETC_PROFILE_NIX_SOURCED 1
|
||||||
|
|
|
@ -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},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,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.",
|
||||||
|
|
|
@ -10,6 +10,8 @@ class Bindings;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -242,7 +242,11 @@ void NixRepl::mainLoop()
|
||||||
|
|
||||||
// Allow nix-repl specific settings in .inputrc
|
// Allow nix-repl specific settings in .inputrc
|
||||||
rl_readline_name = "nix-repl";
|
rl_readline_name = "nix-repl";
|
||||||
|
try {
|
||||||
createDirs(dirOf(historyFile));
|
createDirs(dirOf(historyFile));
|
||||||
|
} catch (SysError & e) {
|
||||||
|
logWarning(e.info());
|
||||||
|
}
|
||||||
#ifndef READLINE
|
#ifndef READLINE
|
||||||
el_hist_size = 1000;
|
el_hist_size = 1000;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1046,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");
|
||||||
|
|
|
@ -68,7 +68,7 @@ void ConfigFile::apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!trusted) {
|
if (!trusted) {
|
||||||
warn("ignoring untrusted flake configuration setting '%s'", name);
|
warn("ignoring untrusted flake configuration setting '%s'.\nPass '%s' to trust it", name, "--accept-flake-config");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,12 +483,12 @@ LockedFlake lockFlake(
|
||||||
} 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 lockfile 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);
|
||||||
overridePath.push_back(i.first);
|
overridePath.push_back(i.first);
|
||||||
auto o = overrides.find(overridePath);
|
auto o = overrides.find(overridePath);
|
||||||
// If the override disappeared, we have to refetch the flake,
|
// If the override disappeared, we have to refetch the flake,
|
||||||
// since some of the inputs may not be present in the lockfile.
|
// since some of the inputs may not be present in the lock file.
|
||||||
if (o == overrides.end()) {
|
if (o == overrides.end()) {
|
||||||
mustRefetch = true;
|
mustRefetch = true;
|
||||||
// There's no point populating the rest of the fake inputs,
|
// There's no point populating the rest of the fake inputs,
|
||||||
|
|
|
@ -36,7 +36,7 @@ LockedNode::LockedNode(const nlohmann::json & json)
|
||||||
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
||||||
{
|
{
|
||||||
if (!lockedRef.input.isLocked())
|
if (!lockedRef.input.isLocked())
|
||||||
throw Error("lockfile contains mutable lock '%s'",
|
throw Error("lock file contains mutable lock '%s'",
|
||||||
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
|
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2454,8 +2454,8 @@ static RegisterPrimOp primop_intersectAttrs({
|
||||||
.name = "__intersectAttrs",
|
.name = "__intersectAttrs",
|
||||||
.args = {"e1", "e2"},
|
.args = {"e1", "e2"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Return a set consisting of the attributes in the set *e2* that also
|
Return a set consisting of the attributes in the set *e2* which have the
|
||||||
exist in the set *e1*.
|
same name as some attribute in *e1*.
|
||||||
)",
|
)",
|
||||||
.fun = prim_intersectAttrs,
|
.fun = prim_intersectAttrs,
|
||||||
});
|
});
|
||||||
|
@ -3821,8 +3821,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?
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,8 @@ struct ClientSettings
|
||||||
else if (trusted
|
else if (trusted
|
||||||
|| name == settings.buildTimeout.name
|
|| name == settings.buildTimeout.name
|
||||||
|| name == settings.buildRepeat.name
|
|| name == settings.buildRepeat.name
|
||||||
|
|| name == settings.maxSilentTime.name
|
||||||
|
|| name == settings.pollInterval.name
|
||||||
|| name == "connect-timeout"
|
|| name == "connect-timeout"
|
||||||
|| (name == "builders" && value == ""))
|
|| (name == "builders" && value == ""))
|
||||||
settings.set(name, value);
|
settings.set(name, value);
|
||||||
|
|
|
@ -322,7 +322,6 @@ struct curlFileTransfer : public FileTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.verifyTLS) {
|
if (request.verifyTLS) {
|
||||||
debug("verify TLS: Nix CA file = '%s'", settings.caFile);
|
|
||||||
if (settings.caFile != "")
|
if (settings.caFile != "")
|
||||||
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
|
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -560,9 +560,15 @@ public:
|
||||||
R"(
|
R"(
|
||||||
If set to `true` (the default), any non-content-addressed path added
|
If set to `true` (the default), any non-content-addressed path added
|
||||||
or copied to the Nix store (e.g. when substituting from a binary
|
or copied to the Nix store (e.g. when substituting from a binary
|
||||||
cache) must have a valid signature, that is, be signed using one of
|
cache) must have a signature by a trusted key. A trusted key is one
|
||||||
the keys listed in `trusted-public-keys` or `secret-key-files`. Set
|
listed in `trusted-public-keys`, or a public key counterpart to a
|
||||||
to `false` to disable signature checking.
|
private key stored in a file listed in `secret-key-files`.
|
||||||
|
|
||||||
|
Set to `false` to disable signature checking and trust all
|
||||||
|
non-content-addressed paths unconditionally.
|
||||||
|
|
||||||
|
(Content-addressed paths are inherently trustworthy and thus
|
||||||
|
unaffected by this configuration option.)
|
||||||
)"};
|
)"};
|
||||||
|
|
||||||
Setting<StringSet> extraPlatforms{
|
Setting<StringSet> extraPlatforms{
|
||||||
|
@ -613,6 +619,14 @@ public:
|
||||||
are tried based on their Priority value, which each substituter can set
|
are tried based on their Priority value, which each substituter can set
|
||||||
independently. Lower value means higher priority.
|
independently. Lower value means higher priority.
|
||||||
The default is `https://cache.nixos.org`, with a Priority of 40.
|
The default is `https://cache.nixos.org`, with a Priority of 40.
|
||||||
|
|
||||||
|
Nix will copy a store path from a remote store only if one
|
||||||
|
of the following is true:
|
||||||
|
|
||||||
|
- the store object is signed by one of the [`trusted-public-keys`](#conf-trusted-public-keys)
|
||||||
|
- the substituter is in the [`trusted-substituters`](#conf-trusted-substituters) list
|
||||||
|
- the [`require-sigs`](#conf-require-sigs) option has been set to `false`
|
||||||
|
- the store object is [output-addressed](glossary.md#gloss-output-addressed-store-object)
|
||||||
)",
|
)",
|
||||||
{"binary-caches"}};
|
{"binary-caches"}};
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
|
writeFile(schemaPath, fmt("%d", nixCASchemaVersion), 0666, true);
|
||||||
lockFile(lockFd.get(), ltRead, true);
|
lockFile(lockFd.get(), ltRead, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ LocalStore::LocalStore(const Params & params)
|
||||||
else if (curSchema == 0) { /* new store */
|
else if (curSchema == 0) { /* new store */
|
||||||
curSchema = nixSchemaVersion;
|
curSchema = nixSchemaVersion;
|
||||||
openDB(*state, true);
|
openDB(*state, true);
|
||||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (curSchema < nixSchemaVersion) {
|
else if (curSchema < nixSchemaVersion) {
|
||||||
|
@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||||
|
|
||||||
lockFile(globalLock.get(), ltRead, true);
|
lockFile(globalLock.get(), ltRead, true);
|
||||||
}
|
}
|
||||||
|
@ -751,7 +751,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
|
||||||
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
|
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
|
||||||
registerDrvOutput(info);
|
registerDrvOutput(info);
|
||||||
else
|
else
|
||||||
throw Error("cannot register realisation '%s' because it lacks a valid signature", info.outPath.to_string());
|
throw Error("cannot register realisation '%s' because it lacks a signature by a trusted key", info.outPath.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStore::registerDrvOutput(const Realisation & info)
|
void LocalStore::registerDrvOutput(const Realisation & info)
|
||||||
|
@ -1266,7 +1266,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs)
|
RepairFlag repair, CheckSigsFlag checkSigs)
|
||||||
{
|
{
|
||||||
if (checkSigs && pathInfoIsUntrusted(info))
|
if (checkSigs && pathInfoIsUntrusted(info))
|
||||||
throw Error("cannot add path '%s' because it lacks a valid signature", printStorePath(info.path));
|
throw Error("cannot add path '%s' because it lacks a signature by a trusted key", printStorePath(info.path));
|
||||||
|
|
||||||
addTempRoot(info.path);
|
addTempRoot(info.path);
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ struct NarAccessor : public FSAccessor
|
||||||
createMember(path, {FSAccessor::Type::tRegular, false, 0, 0});
|
createMember(path, {FSAccessor::Type::tRegular, false, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void closeRegularFile() override
|
||||||
|
{ }
|
||||||
|
|
||||||
void isExecutable() override
|
void isExecutable() override
|
||||||
{
|
{
|
||||||
parents.top()->isExecutable = true;
|
parents.top()->isExecutable = true;
|
||||||
|
|
|
@ -1363,9 +1363,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);
|
||||||
|
|
|
@ -234,6 +234,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
||||||
|
|
||||||
else if (s == "contents" && type == tpRegular) {
|
else if (s == "contents" && type == tpRegular) {
|
||||||
parseContents(sink, source, path);
|
parseContents(sink, source, path);
|
||||||
|
sink.closeRegularFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (s == "executable" && type == tpRegular) {
|
else if (s == "executable" && type == tpRegular) {
|
||||||
|
@ -324,6 +325,12 @@ struct RestoreSink : ParseSink
|
||||||
if (!fd) throw SysError("creating file '%1%'", p);
|
if (!fd) throw SysError("creating file '%1%'", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void closeRegularFile() override
|
||||||
|
{
|
||||||
|
/* Call close explicitly to make sure the error is checked */
|
||||||
|
fd.close();
|
||||||
|
}
|
||||||
|
|
||||||
void isExecutable() override
|
void isExecutable() override
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct ParseSink
|
||||||
virtual void createDirectory(const Path & path) { };
|
virtual void createDirectory(const Path & path) { };
|
||||||
|
|
||||||
virtual void createRegularFile(const Path & path) { };
|
virtual void createRegularFile(const Path & path) { };
|
||||||
|
virtual void closeRegularFile() { };
|
||||||
virtual void isExecutable() { };
|
virtual void isExecutable() { };
|
||||||
virtual void preallocateContents(uint64_t size) { };
|
virtual void preallocateContents(uint64_t size) { };
|
||||||
virtual void receiveContents(std::string_view data) { };
|
virtual void receiveContents(std::string_view data) { };
|
||||||
|
|
|
@ -353,7 +353,7 @@ void readFile(const Path & path, Sink & sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeFile(const Path & path, std::string_view s, mode_t mode)
|
void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
|
||||||
{
|
{
|
||||||
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||||
if (!fd)
|
if (!fd)
|
||||||
|
@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
|
||||||
e.addTrace({}, "writing file '%1%'", path);
|
e.addTrace({}, "writing file '%1%'", path);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
if (sync)
|
||||||
|
fd.fsync();
|
||||||
|
// Explicitly close to make sure exceptions are propagated.
|
||||||
|
fd.close();
|
||||||
|
if (sync)
|
||||||
|
syncParent(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeFile(const Path & path, Source & source, mode_t mode)
|
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
|
||||||
{
|
{
|
||||||
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||||
if (!fd)
|
if (!fd)
|
||||||
|
@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
|
||||||
e.addTrace({}, "writing file '%1%'", path);
|
e.addTrace({}, "writing file '%1%'", path);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
if (sync)
|
||||||
|
fd.fsync();
|
||||||
|
// Explicitly close to make sure exceptions are propagated.
|
||||||
|
fd.close();
|
||||||
|
if (sync)
|
||||||
|
syncParent(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncParent(const Path & path)
|
||||||
|
{
|
||||||
|
AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
|
||||||
|
if (!fd)
|
||||||
|
throw SysError("opening file '%1%'", path);
|
||||||
|
fd.fsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readLine(int fd)
|
std::string readLine(int fd)
|
||||||
|
@ -841,6 +861,20 @@ void AutoCloseFD::close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoCloseFD::fsync()
|
||||||
|
{
|
||||||
|
if (fd != -1) {
|
||||||
|
int result;
|
||||||
|
#if __APPLE__
|
||||||
|
result = ::fcntl(fd, F_FULLFSYNC);
|
||||||
|
#else
|
||||||
|
result = ::fsync(fd);
|
||||||
|
#endif
|
||||||
|
if (result == -1)
|
||||||
|
throw SysError("fsync file descriptor %1%", fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::operator bool() const
|
AutoCloseFD::operator bool() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,9 +115,12 @@ std::string readFile(const Path & path);
|
||||||
void readFile(const Path & path, Sink & sink);
|
void readFile(const Path & path, Sink & sink);
|
||||||
|
|
||||||
/* Write a string to a file. */
|
/* Write a string to a file. */
|
||||||
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
|
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
|
||||||
|
|
||||||
void writeFile(const Path & path, Source & source, mode_t mode = 0666);
|
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
|
||||||
|
|
||||||
|
/* Flush a file's parent directory to disk */
|
||||||
|
void syncParent(const Path & path);
|
||||||
|
|
||||||
/* Read a line from a file descriptor. */
|
/* Read a line from a file descriptor. */
|
||||||
std::string readLine(int fd);
|
std::string readLine(int fd);
|
||||||
|
@ -231,6 +234,7 @@ public:
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
int release();
|
int release();
|
||||||
void close();
|
void close();
|
||||||
|
void fsync();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
Strings attrPaths;
|
Strings attrPaths;
|
||||||
Strings left;
|
Strings left;
|
||||||
RepairFlag repair = NoRepair;
|
RepairFlag repair = NoRepair;
|
||||||
Path gcRoot;
|
|
||||||
BuildMode buildMode = bmNormal;
|
BuildMode buildMode = bmNormal;
|
||||||
bool readStdin = false;
|
bool readStdin = false;
|
||||||
|
|
||||||
|
@ -167,9 +166,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
else if (*arg == "--out-link" || *arg == "-o")
|
else if (*arg == "--out-link" || *arg == "-o")
|
||||||
outLink = getArg(*arg, arg, end);
|
outLink = getArg(*arg, arg, end);
|
||||||
|
|
||||||
else if (*arg == "--add-root")
|
|
||||||
gcRoot = getArg(*arg, arg, end);
|
|
||||||
|
|
||||||
else if (*arg == "--dry-run")
|
else if (*arg == "--dry-run")
|
||||||
dryRun = true;
|
dryRun = true;
|
||||||
|
|
||||||
|
|
|
@ -246,6 +246,7 @@ struct Common : InstallableCommand, MixProfile
|
||||||
"NIX_LOG_FD",
|
"NIX_LOG_FD",
|
||||||
"NIX_REMOTE",
|
"NIX_REMOTE",
|
||||||
"PPID",
|
"PPID",
|
||||||
|
"SHELL",
|
||||||
"SHELLOPTS",
|
"SHELLOPTS",
|
||||||
"SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt
|
"SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt
|
||||||
"TEMP",
|
"TEMP",
|
||||||
|
|
|
@ -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; }},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -187,7 +191,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
|
||||||
*vUtils);
|
*vUtils);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -22,7 +22,7 @@ R""(
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello
|
# nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello
|
||||||
cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a valid signature
|
cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a signature by a trusted key
|
||||||
```
|
```
|
||||||
|
|
||||||
* Create a content-addressed representation of the current NixOS
|
* Create a content-addressed representation of the current NixOS
|
||||||
|
|
|
@ -41,7 +41,7 @@ struct CmdVerify : StorePathsCommand
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "sigs-needed",
|
.longName = "sigs-needed",
|
||||||
.shortName = 'n',
|
.shortName = 'n',
|
||||||
.description = "Require that each path has at least *n* valid signatures.",
|
.description = "Require that each path is signed by at least *n* different keys.",
|
||||||
.labels = {"n"},
|
.labels = {"n"},
|
||||||
.handler = {&sigsNeeded}
|
.handler = {&sigsNeeded}
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,9 +18,6 @@ nix-build --no-out-link dependencies.nix --dry-run 2>&1 | grep "will be built"
|
||||||
# Now new command:
|
# Now new command:
|
||||||
nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"
|
nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"
|
||||||
|
|
||||||
# TODO: XXX: FIXME: #1793
|
|
||||||
# Disable this part of the test until the problem is resolved:
|
|
||||||
if [ -n "$ISSUE_1795_IS_FIXED" ]; then
|
|
||||||
clearStore
|
clearStore
|
||||||
clearCache
|
clearCache
|
||||||
|
|
||||||
|
@ -28,7 +25,6 @@ clearCache
|
||||||
nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"
|
nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"
|
||||||
# Now old command:
|
# Now old command:
|
||||||
nix-build --no-out-link dependencies.nix --dry-run 2>&1 | grep "will be built"
|
nix-build --no-out-link dependencies.nix --dry-run 2>&1 | grep "will be built"
|
||||||
fi
|
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# Check --dry-run doesn't create links with --dry-run
|
# Check --dry-run doesn't create links with --dry-run
|
||||||
|
|
220
tests/installer/default.nix
Normal file
220
tests/installer/default.nix
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
{ binaryTarballs
|
||||||
|
, nixpkgsFor
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
installScripts = {
|
||||||
|
install-default = {
|
||||||
|
script = ''
|
||||||
|
tar -xf ./nix.tar.xz
|
||||||
|
mv ./nix-* nix
|
||||||
|
./nix/install --no-channel-add
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
install-force-no-daemon = {
|
||||||
|
script = ''
|
||||||
|
tar -xf ./nix.tar.xz
|
||||||
|
mv ./nix-* nix
|
||||||
|
./nix/install --no-daemon
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
install-force-daemon = {
|
||||||
|
script = ''
|
||||||
|
tar -xf ./nix.tar.xz
|
||||||
|
mv ./nix-* nix
|
||||||
|
./nix/install --daemon --no-channel-add
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
disableSELinux = "sudo setenforce 0";
|
||||||
|
|
||||||
|
images = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
"ubuntu-14-04" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/ubuntu/boxes/trusty64/versions/20190514.0.0/providers/virtualbox.box";
|
||||||
|
hash = "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=";
|
||||||
|
};
|
||||||
|
rootDisk = "box-disk1.vmdk";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
"ubuntu-16-04" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/ubuntu1604/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-lO4oYQR2tCh5auxAYe6bPOgEqOgv3Y3GC1QM1tEEEU8=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
|
||||||
|
"ubuntu-22-04" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/ubuntu2204/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-HNll0Qikw/xGIcogni5lz01vUv+R3o8xowP2EtqjuUQ=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
|
||||||
|
"fedora-36" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/fedora36/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-rxPgnDnFkTDwvdqn2CV3ZUo3re9AdPtSZ9SvOHNvaks=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
postBoot = disableSELinux;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Currently fails with 'error while loading shared libraries:
|
||||||
|
# libsodium.so.23: cannot stat shared object: Invalid argument'.
|
||||||
|
/*
|
||||||
|
"rhel-6" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/rhel6/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-QwzbvRoRRGqUCQptM7X/InRWFSP2sqwRt2HaaO6zBGM=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
"rhel-7" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/rhel7/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
|
||||||
|
"rhel-8" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/rhel8/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-zFOPjSputy1dPgrQRixBXmlyN88cAKjJ21VvjSWUCUY=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
postBoot = disableSELinux;
|
||||||
|
};
|
||||||
|
|
||||||
|
"rhel-9" = {
|
||||||
|
image = import <nix/fetchurl.nix> {
|
||||||
|
url = "https://app.vagrantup.com/generic/boxes/rhel9/versions/4.1.12/providers/libvirt.box";
|
||||||
|
hash = "sha256-vL/FbB3kK1rcSaR627nWmScYGKGk4seSmAdq6N5diMg=";
|
||||||
|
};
|
||||||
|
rootDisk = "box.img";
|
||||||
|
system = "x86_64-linux";
|
||||||
|
postBoot = disableSELinux;
|
||||||
|
extraQemuOpts = "-cpu Westmere-v2";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
makeTest = imageName: testName:
|
||||||
|
let image = images.${imageName}; in
|
||||||
|
with nixpkgsFor.${image.system};
|
||||||
|
runCommand
|
||||||
|
"installer-test-${imageName}-${testName}"
|
||||||
|
{ buildInputs = [ qemu_kvm openssh ];
|
||||||
|
image = image.image;
|
||||||
|
postBoot = image.postBoot or "";
|
||||||
|
installScript = installScripts.${testName}.script;
|
||||||
|
binaryTarball = binaryTarballs.${system};
|
||||||
|
}
|
||||||
|
''
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
echo "Unpacking Vagrant box $image..."
|
||||||
|
tar xvf $image
|
||||||
|
|
||||||
|
image_type=$(qemu-img info ${image.rootDisk} | sed 's/file format: \(.*\)/\1/; t; d')
|
||||||
|
|
||||||
|
qemu-img create -b ./${image.rootDisk} -F "$image_type" -f qcow2 ./disk.qcow2
|
||||||
|
|
||||||
|
extra_qemu_opts="${image.extraQemuOpts or ""}"
|
||||||
|
|
||||||
|
# Add the config disk, required by the Ubuntu images.
|
||||||
|
config_drive=$(echo *configdrive.vmdk || true)
|
||||||
|
if [[ -n $config_drive ]]; then
|
||||||
|
extra_qemu_opts+=" -drive id=disk2,file=$config_drive,if=virtio"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting qemu..."
|
||||||
|
qemu-kvm -m 4096 -nographic \
|
||||||
|
-drive id=disk1,file=./disk.qcow2,if=virtio \
|
||||||
|
-netdev user,id=net0,restrict=yes,hostfwd=tcp::20022-:22 -device virtio-net-pci,netdev=net0 \
|
||||||
|
$extra_qemu_opts &
|
||||||
|
qemu_pid=$!
|
||||||
|
trap "kill $qemu_pid" EXIT
|
||||||
|
|
||||||
|
if ! [ -e ./vagrant_insecure_key ]; then
|
||||||
|
cp ${./vagrant_insecure_key} vagrant_insecure_key
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0400 ./vagrant_insecure_key
|
||||||
|
|
||||||
|
ssh_opts="-o StrictHostKeyChecking=no -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -i ./vagrant_insecure_key"
|
||||||
|
ssh="ssh -p 20022 -q $ssh_opts vagrant@localhost"
|
||||||
|
|
||||||
|
echo "Waiting for SSH..."
|
||||||
|
for ((i = 0; i < 120; i++)); do
|
||||||
|
echo "[ssh] Trying to connect..."
|
||||||
|
if $ssh -- true; then
|
||||||
|
echo "[ssh] Connected!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if ! kill -0 $qemu_pid; then
|
||||||
|
echo "qemu died unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n $postBoot ]]; then
|
||||||
|
echo "Running post-boot commands..."
|
||||||
|
$ssh "set -ex; $postBoot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying installer..."
|
||||||
|
scp -P 20022 $ssh_opts $binaryTarball/nix-*.tar.xz vagrant@localhost:nix.tar.xz
|
||||||
|
|
||||||
|
echo "Running installer..."
|
||||||
|
$ssh "set -eux; $installScript"
|
||||||
|
|
||||||
|
echo "Testing Nix installation..."
|
||||||
|
$ssh <<EOF
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
# FIXME: get rid of this; ideally ssh should just work.
|
||||||
|
source ~/.bash_profile || true
|
||||||
|
source ~/.bash_login || true
|
||||||
|
source ~/.profile || true
|
||||||
|
source /etc/bashrc || true
|
||||||
|
|
||||||
|
nix-env --version
|
||||||
|
nix --extra-experimental-features nix-command store ping
|
||||||
|
|
||||||
|
out=\$(nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > \$out"]; }')
|
||||||
|
[[ \$(cat \$out) = foobar ]]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Done!"
|
||||||
|
touch $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
builtins.mapAttrs (imageName: image:
|
||||||
|
{ ${image.system} = builtins.mapAttrs (testName: test:
|
||||||
|
makeTest imageName testName
|
||||||
|
) installScripts;
|
||||||
|
}
|
||||||
|
) images
|
27
tests/installer/vagrant_insecure_key
Normal file
27
tests/installer/vagrant_insecure_key
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
|
||||||
|
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
|
||||||
|
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
|
||||||
|
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
|
||||||
|
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
|
||||||
|
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
|
||||||
|
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
|
||||||
|
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
|
||||||
|
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
|
||||||
|
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
|
||||||
|
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
|
||||||
|
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
|
||||||
|
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
|
||||||
|
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
|
||||||
|
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
|
||||||
|
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
|
||||||
|
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
|
||||||
|
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
|
||||||
|
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
|
||||||
|
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
|
||||||
|
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
|
||||||
|
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
|
||||||
|
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
|
||||||
|
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
|
||||||
|
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -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)
|
||||||
|
|
|
@ -81,7 +81,7 @@ info=$(nix path-info --store file://$cacheDir --json $outPath2)
|
||||||
[[ $info =~ 'cache1.example.org' ]]
|
[[ $info =~ 'cache1.example.org' ]]
|
||||||
[[ $info =~ 'cache2.example.org' ]]
|
[[ $info =~ 'cache2.example.org' ]]
|
||||||
|
|
||||||
# Copying to a diverted store should fail due to a lack of valid signatures.
|
# Copying to a diverted store should fail due to a lack of signatures by trusted keys.
|
||||||
chmod -R u+w $TEST_ROOT/store0 || true
|
chmod -R u+w $TEST_ROOT/store0 || true
|
||||||
rm -rf $TEST_ROOT/store0
|
rm -rf $TEST_ROOT/store0
|
||||||
(! nix copy --to $TEST_ROOT/store0 $outPath)
|
(! nix copy --to $TEST_ROOT/store0 $outPath)
|
||||||
|
|
Loading…
Reference in a new issue