Merge pull request #68897 from edolstra/master

Flake support
This commit is contained in:
Eelco Dolstra 2020-02-10 16:44:54 +01:00 committed by GitHub
commit 0e6ceb8758
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 313 additions and 43 deletions

50
flake.nix Normal file
View File

@ -0,0 +1,50 @@
# Experimental flake interface to Nixpkgs.
# See https://github.com/NixOS/rfcs/pull/49 for details.
{
edition = 201909;
description = "A collection of packages for the Nix package manager";
outputs = { self }:
let
jobs = import ./pkgs/top-level/release.nix {
nixpkgs = self;
};
lib = import ./lib;
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ];
forAllSystems = f: lib.genAttrs systems (system: f system);
in
{
lib = lib // {
nixosSystem = { modules, ... } @ args:
import ./nixos/lib/eval-config.nix (args // {
modules = modules ++
[ { system.nixos.versionSuffix =
".${lib.substring 0 8 self.lastModified}.${self.shortRev or "dirty"}";
system.nixos.revision = lib.mkIf (self ? rev) self.rev;
}
];
});
};
checks.x86_64-linux.tarball = jobs.tarball;
htmlDocs = {
nixpkgsManual = jobs.manual;
nixosManual = (import ./nixos/release-small.nix {
nixpkgs = self;
}).nixos.manual.x86_64-linux;
};
legacyPackages = forAllSystems (system: import ./. { inherit system; });
nixosModules = {
notDetected = import ./nixos/modules/installer/scan/not-detected.nix;
};
};
}

View File

@ -148,7 +148,7 @@ runTests {
"${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
in {
storePath = isStorePath goodPath;
storePathDerivation = isStorePath (import ../.. {}).hello;
storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
storePathAppendix = isStorePath
"${goodPath}/bin/python";
nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));

View File

@ -2,7 +2,7 @@
pkgs.runCommandNoCC "nixpkgs-lib-tests" {
buildInputs = [ pkgs.nix (import ./check-eval.nix) ];
NIX_PATH="nixpkgs=${pkgs.path}";
NIX_PATH = "nixpkgs=${toString pkgs.path}";
} ''
datadir="${pkgs.nix}/share"
export TEST_ROOT=$(pwd)/test-tmp

View File

@ -77,7 +77,14 @@
<option>--builders</option> <replaceable>builder-spec</replaceable>
</arg>
<sbr/>
<arg>
<option>--flake</option> <replaceable>flake-uri</replaceable>
</arg>
<sbr />
<arg>
<group choice='req'>
<arg choice='plain'>
@ -129,14 +136,17 @@
<title>Description</title>
<para>
This command updates the system so that it corresponds to the configuration
specified in <filename>/etc/nixos/configuration.nix</filename>. Thus, every
time you modify <filename>/etc/nixos/configuration.nix</filename> or any
NixOS module, you must run <command>nixos-rebuild</command> to make the
changes take effect. It builds the new system in
<filename>/nix/store</filename>, runs its activation script, and stop and
(re)starts any system services if needed. Please note that user services need
to be started manually as they aren't detected by the activation script at the moment.
This command updates the system so that it corresponds to the
configuration specified in
<filename>/etc/nixos/configuration.nix</filename> or
<filename>/etc/nixos/flake.nix</filename>. Thus, every time you
modify the configuration or any other NixOS module, you must run
<command>nixos-rebuild</command> to make the changes take
effect. It builds the new system in
<filename>/nix/store</filename>, runs its activation script, and
stop and (re)starts any system services if needed. Please note that
user services need to be started manually as they aren't detected
by the activation script at the moment.
</para>
<para>
@ -508,6 +518,24 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--flake</option> <replaceable>flake-uri</replaceable>[<replaceable>name</replaceable>]
</term>
<listitem>
<para>
Build the NixOS system from the specified flake. It defaults to
the directory containing the target of the symlink
<filename>/etc/nixos/flake.nix</filename>, if it exists. The
flake must contain an output named
<literal>nixosConfigurations.<replaceable>name</replaceable></literal>. If
<replaceable>name</replaceable> is omitted, it default to the
current host name.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
@ -554,6 +582,21 @@
<variablelist>
<varlistentry>
<term>
<filename>/etc/nixos/flake.nix</filename>
</term>
<listitem>
<para>
If this file exists, then <command>nixos-rebuild</command> will
use it as if the <option>--flake</option> option was given. This
file may be a symlink to a <filename>flake.nix</filename> in an
actual flake; thus <filename>/etc/nixos</filename> need not be a
flake.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<filename>/run/current-system</filename>

View File

@ -20,8 +20,14 @@
<arg>
<option>--revision</option>
</arg>
<arg>
<option>--json</option>
</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsection>
<title>Description</title>
<para>
@ -84,12 +90,16 @@
</variablelist>
</para>
</refsection>
<refsection>
<title>Options</title>
<para>
This command accepts the following options:
</para>
<variablelist>
<varlistentry>
<term>
<option>--hash</option>
@ -107,6 +117,21 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--json</option>
</term>
<listitem>
<para>
Print a JSON representation of the versions of NixOS and the
top-level configuration flake.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsection>
</refentry>

View File

@ -3,6 +3,9 @@
if [ -x "@shell@" ]; then export SHELL="@shell@"; fi;
set -e
set -o pipefail
export PATH=@path@:$PATH
showSyntax() {
exec man nixos-rebuild
@ -13,6 +16,7 @@ showSyntax() {
# Parse the command line.
origArgs=("$@")
extraBuildFlags=()
lockFlags=()
action=
buildNix=1
fast=
@ -58,7 +62,7 @@ while [ "$#" -gt 0 ]; do
j="$1"; shift 1
extraBuildFlags+=("$i" "$j")
;;
--show-trace|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*)
--show-trace|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*|-L|--refresh|--no-net)
extraBuildFlags+=("$i")
;;
--option)
@ -93,6 +97,22 @@ while [ "$#" -gt 0 ]; do
--use-remote-sudo)
maybeSudo=(sudo --)
;;
--flake)
flake="$1"
shift 1
;;
--recreate-lock-file|--no-update-lock-file|--no-write-lock-file|--no-registries|--commit-lock-file)
lockFlags+=("$i")
;;
--update-input)
j="$1"; shift 1
lockFlags+=("$i" "$j")
;;
--override-input)
j="$1"; shift 1
k="$1"; shift 1
lockFlags+=("$i" "$j" "$k")
;;
*)
echo "$0: unknown option \`$i'"
exit 1
@ -202,7 +222,7 @@ fi
# If --upgrade is given, run nix-channel --update nixos.
if [ -n "$upgrade" -a -z "$_NIXOS_REBUILD_REEXEC" ]; then
if [[ -n $upgrade && -z $_NIXOS_REBUILD_REEXEC && -z $flake ]]; then
nix-channel --update nixos
# If there are other channels that contain a file called
@ -225,8 +245,15 @@ if [ -z "$_NIXOS_REBUILD_REEXEC" ]; then
export PATH=@nix@/bin:$PATH
fi
# Use /etc/nixos/flake.nix if it exists. It can be a symlink to the
# actual flake.
if [[ -z $flake && -e /etc/nixos/flake.nix ]]; then
flake="$(dirname "$(readlink -f /etc/nixos/flake.nix)")"
fi
# Re-execute nixos-rebuild from the Nixpkgs tree.
if [ -z "$_NIXOS_REBUILD_REEXEC" -a -n "$canRun" -a -z "$fast" ]; then
# FIXME: get nixos-rebuild from $flake.
if [[ -z $_NIXOS_REBUILD_REEXEC && -n $canRun && -z $fast && -z $flake ]]; then
if p=$(nix-build --no-out-link --expr 'with import <nixpkgs/nixos> {}; config.system.build.nixos-rebuild' "${extraBuildFlags[@]}"); then
export _NIXOS_REBUILD_REEXEC=1
exec $p/bin/nixos-rebuild "${origArgs[@]}"
@ -234,10 +261,37 @@ if [ -z "$_NIXOS_REBUILD_REEXEC" -a -n "$canRun" -a -z "$fast" ]; then
fi
fi
# For convenience, use the hostname as the default configuration to
# build from the flake.
if [[ -n $flake ]]; then
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
flake="${BASH_REMATCH[1]}"
flakeAttr="${BASH_REMATCH[2]}"
fi
if [[ -z $flakeAttr ]]; then
read -r hostname < /proc/sys/kernel/hostname
if [[ -z $hostname ]]; then
hostname=default
fi
flakeAttr="nixosConfigurations.\"$hostname\""
else
flakeAttr="nixosConfigurations.\"$flakeAttr\""
fi
fi
# Resolve the flake.
if [[ -n $flake ]]; then
flake=$(nix flake info --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url)
fi
# Find configuration.nix and open editor instead of building.
if [ "$action" = edit ]; then
if [[ -z $flake ]]; then
NIXOS_CONFIG=${NIXOS_CONFIG:-$(nix-instantiate --find-file nixos-config)}
exec "${EDITOR:-nano}" "$NIXOS_CONFIG"
else
exec nix edit "${lockFlags[@]}" -- "$flake#$flakeAttr"
fi
exit 1
fi
@ -296,7 +350,7 @@ prebuiltNix() {
remotePATH=
if [ -n "$buildNix" ]; then
if [[ -n $buildNix && -z $flake ]]; then
echo "building Nix..." >&2
nixDrv=
if ! nixDrv="$(nix-instantiate '<nixpkgs/nixos>' --add-root $tmpDir/nix.drv --indirect -A config.nix.package.out "${extraBuildFlags[@]}")"; then
@ -337,7 +391,7 @@ fi
# Update the version suffix if we're building from Git (so that
# nixos-version shows something useful).
if [ -n "$canRun" ]; then
if [[ -n $canRun && -z $flake ]]; then
if nixpkgs=$(nix-instantiate --find-file nixpkgs "${extraBuildFlags[@]}"); then
suffix=$($SHELL $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}" || true)
if [ -n "$suffix" ]; then
@ -358,15 +412,37 @@ fi
if [ -z "$rollback" ]; then
echo "building the system configuration..." >&2
if [ "$action" = switch -o "$action" = boot ]; then
if [[ -z $flake ]]; then
pathToConfig="$(nixBuild '<nixpkgs/nixos>' --no-out-link -A system "${extraBuildFlags[@]}")"
else
outLink=$tmpDir/result
nix build "$flake#$flakeAttr.config.system.build.toplevel" \
"${extraBuildFlags[@]}" "${lockFlags[@]}" --out-link $outLink
pathToConfig="$(readlink -f $outLink)"
fi
copyToTarget "$pathToConfig"
targetHostCmd nix-env -p "$profile" --set "$pathToConfig"
elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then
if [[ -z $flake ]]; then
pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}")"
else
nix build "$flake#$flakeAttr.config.system.build.toplevel" "${extraBuildFlags[@]}" "${lockFlags[@]}"
pathToConfig="$(readlink -f ./result)"
fi
elif [ "$action" = build-vm ]; then
if [[ -z $flake ]]; then
pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vm -k "${extraBuildFlags[@]}")"
else
echo "$0: 'build-vm' is not supported with '--flake'" >&2
exit 1
fi
elif [ "$action" = build-vm-with-bootloader ]; then
if [[ -z $flake ]]; then
pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vmWithBootLoader -k "${extraBuildFlags[@]}")"
else
echo "$0: 'build-vm-with-bootloader' is not supported with '--flake'" >&2
exit 1
fi
else
showSyntax
fi

View File

@ -6,8 +6,17 @@ case "$1" in
exit 1
;;
--hash|--revision)
if ! [[ @revision@ =~ ^[0-9a-f]+$ ]]; then
echo "$0: Nixpkgs commit hash is unknown"
exit 1
fi
echo "@revision@"
;;
--json)
cat <<EOF
@json@
EOF
;;
*)
echo "@version@ (@codeName@)"
;;

View File

@ -31,6 +31,7 @@ let
nix = config.nix.package.out;
nix_x86_64_linux = fallback.x86_64-linux;
nix_i686_linux = fallback.i686-linux;
path = makeBinPath [ pkgs.jq ];
};
nixos-generate-config = makeProg {
@ -47,6 +48,14 @@ let
name = "nixos-version";
src = ./nixos-version.sh;
inherit (config.system.nixos) version codeName revision;
inherit (config.system) configurationRevision;
json = builtins.toJSON ({
nixosVersion = config.system.nixos.version;
} // optionalAttrs (config.system.nixos.revision != null) {
nixpkgsRevision = config.system.nixos.revision;
} // optionalAttrs (config.system.configurationRevision != null) {
configurationRevision = config.system.configurationRevision;
});
};
nixos-enter = makeProg {

View File

@ -42,8 +42,8 @@ in
nixos.revision = mkOption {
internal = true;
type = types.str;
default = trivial.revisionWithDefault "master";
type = types.nullOr types.str;
default = trivial.revisionWithDefault null;
description = "The Git revision from which this NixOS configuration was built.";
};
@ -84,6 +84,12 @@ in
description = "Default NixOS channel to which the root user is subscribed.";
};
configurationRevision = mkOption {
type = types.nullOr types.str;
default = null;
description = "The Git revision of the top-level flake from which this configuration was built.";
};
};
config = {

View File

@ -22,13 +22,27 @@ $ENV{"NIXOS_CONFIG"} = "";
sub showHelp {
print <<EOF;
Usage: nixos-container list
nixos-container create <container-name> [--nixos-path <path>] [--system-path <path>] [--config-file <path>] [--config <string>] [--ensure-unique-name] [--auto-start] [--bridge <iface>] [--port <port>] [--host-address <string>] [--local-address <string>]
nixos-container create <container-name>
[--nixos-path <path>]
[--system-path <path>]
[--config <string>]
[--config-file <path>]
[--flake <flakeref>]
[--ensure-unique-name]
[--auto-start]
[--bridge <iface>]
[--port <port>]
[--host-address <string>]
[--local-address <string>]
nixos-container destroy <container-name>
nixos-container start <container-name>
nixos-container stop <container-name>
nixos-container terminate <container-name>
nixos-container status <container-name>
nixos-container update <container-name> [--config <string>] [--config-file <path>]
nixos-container update <container-name>
[--config <string>]
[--config-file <path>]
[--flake <flakeref>]
nixos-container login <container-name>
nixos-container root-login <container-name>
nixos-container run <container-name> -- args...
@ -49,6 +63,8 @@ my $signal;
my $configFile;
my $hostAddress;
my $localAddress;
my $flake;
my $flakeAttr = "container";
GetOptions(
"help" => sub { showHelp() },
@ -63,6 +79,7 @@ GetOptions(
"config-file=s" => \$configFile,
"host-address=s" => \$hostAddress,
"local-address=s" => \$localAddress,
"flake=s" => \$flake,
) or exit 1;
if (defined $hostAddress and !defined $localAddress or defined $localAddress and !defined $hostAddress) {
@ -76,6 +93,11 @@ if (defined $configFile and defined $extraConfig) {
"Please define on or the other, but not both";
}
if (defined $flake && $flake =~ /^(.*)#([^#"]+)$/) {
$flake = $1;
$flakeAttr = $2;
}
# Execute the selected action.
mkpath("/etc/containers", 0, 0755);
@ -97,8 +119,6 @@ sub writeNixOSConfig {
my $localExtraConfig = "";
if ($extraConfig) {
$localExtraConfig = $extraConfig
} elsif ($configFile) {
@ -121,6 +141,14 @@ EOF
write_file($nixosConfigFile, $nixosConfig);
}
sub buildFlake {
system("nix", "build", "-o", "$systemPath.tmp", "--",
"$flake#nixosConfigurations.\"$flakeAttr\".config.system.build.toplevel") == 0
or die "$0: failed to build container from flake '$flake'\n";
$systemPath = readlink("$systemPath.tmp") or die;
unlink("$systemPath.tmp");
}
if ($action eq "create") {
# Acquire an exclusive lock to prevent races with other
# invocations of nixos-container create.
@ -176,6 +204,7 @@ if ($action eq "create") {
push @conf, "HOST_BRIDGE=$bridge\n";
push @conf, "HOST_PORT=$port\n";
push @conf, "AUTO_START=$autoStart\n";
push @conf, "FLAKE=$flake\n" if defined $flake;
write_file($confFile, \@conf);
close($lock);
@ -191,6 +220,10 @@ if ($action eq "create") {
mkpath($profileDir, 0, 0755);
# Build/set the initial configuration.
if (defined $flake) {
buildFlake();
}
if (defined $systemPath) {
system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0
or die "$0: failed to set initial container configuration\n";
@ -326,6 +359,21 @@ elsif ($action eq "status") {
}
elsif ($action eq "update") {
# Unless overriden on the command line, rebuild the flake recorded
# in the container config file. FIXME: read the container config
# in a more sensible way.
if (!defined $flake && !defined $configFile && !defined $extraConfig) {
my $s = read_file($confFile);
$s =~ /^FLAKE=(.*)$/m;
$flake = $1;
}
if (defined $flake) {
buildFlake();
system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0
or die "$0: failed to set container configuration\n";
} else {
my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
# FIXME: may want to be more careful about clobbering the existing
@ -339,6 +387,7 @@ elsif ($action eq "update") {
"-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>",
"--set", "-A", "system") == 0
or die "$0: failed to build container configuration\n";
}
if (isContainerRunning) {
print STDERR "reloading container...\n";

View File

@ -17,7 +17,10 @@ releaseTools.sourceTarball {
inherit officialRelease;
version = pkgs.lib.fileContents ../../.version;
versionSuffix = "pre${toString nixpkgs.revCount}.${nixpkgs.shortRev}";
versionSuffix = "pre${
if nixpkgs ? lastModified
then builtins.substring 0 8 nixpkgs.lastModified
else toString nixpkgs.revCount}.${nixpkgs.shortRev or "dirty"}";
buildInputs = [ nix.out jq lib-tests ];
@ -25,7 +28,7 @@ releaseTools.sourceTarball {
eval "$preConfigure"
releaseName=nixpkgs-$VERSION$VERSION_SUFFIX
echo -n $VERSION_SUFFIX > .version-suffix
echo -n ${nixpkgs.rev or nixpkgs.shortRev} > .git-revision
echo -n ${nixpkgs.rev or nixpkgs.shortRev or "dirty"} > .git-revision
echo "release name is $releaseName"
echo "git-revision is $(cat .git-revision)"
'';