+zYw`X3V>TCdnSD1ru8&`j=2DIPbCT@SnIgUw>$+lEYP}+x8(BMYnr=iT3*ndq)xzaV
+z>I+qjv}vC#8_9M+b1p#uNS0M0)q8!3p_LRQ0MA3M`!2foxzRUjbFY@}O~(ki=S
+zqscnq8cU*dY)D$$cqE}n)V0yIk>CNKHCrndOtSP*HbOb;nbwAHSb;R+gs^?^Dve%)
+zoW}t(*D}$>O3ab0TS^-;J|u&sb-PkZzo#kn*#xYt(;FGuwzSb^g&RDiGcOz9TB;Hu`nJh)$W=C=XCSm2AY=$w3G3P-V#Oo+N*;#2
+z4ijJ-pBZ=;T(RTgp_HYrD!uW-dTMfkuqY5jwOy)~gM;#=P^i{!l7`pXTS^s(&^{RU
+zydaw}OpS#^D1cXM8?FW+fh`t7D(g;yr6|}fdaNtZBx3hlK~IpkTu3!Qq%R+zAo#t}Bs8^3$vHD+-TGT@`F>H1Cc#WAVW;&$S6%fE2d6@kLS0g&ihIM{}0z
+z8#XhD>b>3{(BH|Px7}&lJ4%y1v(CihZJx@8MPoGdl*BJGD;usf*iS7%;{Joe;
+zNFuBa>*~o&qETDPo~u&~$FxE1xb^x&(CbE`Y3GfsibL2rl+L;>P6j&Y3U>K$mkp*6
+zd`Q{<^+^&;GskGjwD-%!boR&i-TCA9UOR|@=GYb5x#+dhd7fkaVIR^pol`Mv+rUbmZ43dVL6^S7g3{NsPiG$iy$5EDB%
+z6KIgnb$H(n&t3e4E6d4V7w^B?JS}JkG)PM6+X3Co`SQs($O*AA+MG~{S7RJ=cy-l&
+z>~%3y`tjfx2>uOutB_^s
+ziwG=e=ch|FQ0IkN91US7rhdQkXhwwt$gU0WEVDjo=IPb+?6PC=s8}J*ua(Ms))`UL
+fi$|vMHn?H_tSE3ettp-hLlsZCxaLX8(nU;bVRB;Ce6@s#eu2|WvLz>-
+zvy(&>Gyfp@+BtKnpqWkKi^+v{4jn_pNw_zeuxETifiGO|)w}OANj2n2D^K=o3j6P6uOL70#cbA{uzWXDlk1wr9GV1X(2W{RuTvjXV
+zCmd8u
+zH%V`94=q3)Dk)PHNrnFC(T1)Om6f{Usj;u1R->&XoCYVK2V3ZlgZuF?N}1+33OER*x
+z*9Z=L=zI8CN>A_^jYjt0F$psO$sL=38q5q|SG)qCN6{^>RFh5E&l5GZ$pEahnF&d+
+z5c>64t}uJPkf~_!VUj#&N%nC-gUMj%=@B=!V>&}xtj2%@-mOm#rQUSJ3(ccmc+fza
+znZ#uxF>N?QN5UrIEd!5RgHEfW#;(nKYF+D<*rdshJ$X-z2OZ2X;)nn@KSVdVhaA?}@3;6gZxb4v
+zozoWSr{{+!h}zGpumG3H`=AvWpm^9kW;J$Jp^Xl*?8ckr`fqN%c|Z;VC0|cM4vSrk
+zH_O8Yvh85nvJp^;``wo8=z0f`FWg?`>gO#y1hjX1{}rTlg9rwIKia8eyGexA3GnuR
+z`Rg~XZoW;0pA)vI8=p5!+6sIn#C^FCvR>ffv39h6SCNi9v);%WD;WZ`of_MgwyRWy
+z-yY%n*Y>X89W-v4`Ff%bx$Vkn}$!Ay}rnY6F$m-Kg*KD_+;Lx#g4|^&N
+I02NaX#p`nv=Kufz
+
+literal 0
+HcmV?d00001
+
+diff --git a/tests/resources/small.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b b/tests/resources/small.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
+new file mode 100644
+index 0000000000000000000000000000000000000000..822bc151862ec3763cf2d3fa2372b93bbd3a4b65
+GIT binary patch
+literal 30
+mcmb>0i}&W3IZ_@1U=^!a~EV1casc=c+{&un1qQN*i9hD|0|m(2n|iwp*q%W
+z%N;b$hu%cM`$TMo*~EnC1BFP&Pfj~;jZVKXQ96s_PhV<-XAROi+@-v8dBLUa`!;GB
+k^iXlEv8$>R)1G>9th&t3j;s7J{?^9n|7U^`%mXoWC24Q^m!3%@{
+
+literal 0
+HcmV?d00001
+
diff --git a/scripts/bigsur-nixbld-user-migration.sh b/scripts/bigsur-nixbld-user-migration.sh
index 57f65da72..bd9eeb920 100755
--- a/scripts/bigsur-nixbld-user-migration.sh
+++ b/scripts/bigsur-nixbld-user-migration.sh
@@ -2,7 +2,7 @@
((NEW_NIX_FIRST_BUILD_UID=351))
-id_available(){
+id_unavailable(){
dscl . list /Users UniqueID | grep -E '\b'"$1"'\b' >/dev/null
}
@@ -15,7 +15,7 @@ change_nixbld_names_and_ids(){
while read -r name uid; do
echo " Checking $name (uid: $uid)"
# iterate for a clean ID
- while id_available "$next_id"; do
+ while id_unavailable "$next_id"; do
((next_id++))
if ((next_id >= 400)); then
echo "We've hit UID 400 without placing all of your users :("
diff --git a/scripts/binary-tarball.nix b/scripts/binary-tarball.nix
index 104189b0c..580e3859f 100644
--- a/scripts/binary-tarball.nix
+++ b/scripts/binary-tarball.nix
@@ -1,14 +1,18 @@
-{ runCommand
-, system
-, buildPackages
-, cacert
-, nix
+{
+ runCommand,
+ system,
+ buildPackages,
+ cacert,
+ nix,
}:
let
installerClosureInfo = buildPackages.closureInfo {
- rootPaths = [ nix cacert ];
+ rootPaths = [
+ nix
+ cacert
+ ];
};
inherit (nix) version;
@@ -23,7 +27,7 @@ in
runCommand "nix-binary-tarball-${version}" env ''
cp ${installerClosureInfo}/registration $TMPDIR/reginfo
cp ${./create-darwin-volume.sh} $TMPDIR/create-darwin-volume.sh
- substitute ${./install-nix-from-closure.sh} $TMPDIR/install \
+ substitute ${./install-nix-from-tarball.sh} $TMPDIR/install \
--subst-var-by nix ${nix} \
--subst-var-by cacert ${cacert}
@@ -65,7 +69,7 @@ runCommand "nix-binary-tarball-${version}" env ''
fn=$out/$dir.tar.xz
mkdir -p $out/nix-support
echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
- tar cvfJ $fn \
+ tar cfJ $fn \
--owner=0 --group=0 --mode=u+rw,uga+r \
--mtime='1970-01-01' \
--absolute-names \
diff --git a/scripts/build-checks b/scripts/build-checks
new file mode 100755
index 000000000..e0ee70631
--- /dev/null
+++ b/scripts/build-checks
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+set -euo pipefail
+system=$(nix eval --raw --impure --expr builtins.currentSystem)
+nix eval --json ".#checks.$system" --apply builtins.attrNames | \
+ jq -r '.[]' | \
+ xargs -P0 -I '{}' sh -c "nix build -L .#checks.$system.{} || { echo 'FAILED: \033[0;31mnix build -L .#checks.$system.{}\\033[0m'; kill 0; }"
diff --git a/scripts/create-darwin-volume.sh b/scripts/create-darwin-volume.sh
index 103e1e391..7a61764d4 100755
--- a/scripts/create-darwin-volume.sh
+++ b/scripts/create-darwin-volume.sh
@@ -463,7 +463,7 @@ EOF
EDITOR="$SCRATCH/ex_cleanroom_wrapper" _sudo "to add nix to fstab" "$@" < "$SCRATCH/dscl.err"; do
+ local err=$?
+ if [[ $err -eq 140 ]] && grep -q "-14988 (eNotYetImplemented)" "$SCRATCH/dscl.err"; then
+ echo "dscl failed with eNotYetImplemented, retrying..."
+ sleep 1
+ continue
+ fi
+ cat "$SCRATCH/dscl.err"
+ return $err
+ done
+}
+
poly_user_hidden_get() {
dsclattr "/Users/$1" "IsHidden"
}
poly_user_hidden_set() {
- _sudo "in order to make $1 a hidden user" \
- /usr/bin/dscl . -create "/Users/$1" "IsHidden" "1"
+ dscl_create "in order to make $1 a hidden user" \
+ "/Users/$1" "IsHidden" "1"
}
poly_user_home_get() {
@@ -161,8 +176,8 @@ poly_user_home_get() {
poly_user_home_set() {
# This can trigger a permission prompt now:
# "Terminal" would like to administer your computer. Administration can include modifying passwords, networking, and system settings.
- _sudo "in order to give $1 a safe home directory" \
- /usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2"
+ dscl_create "in order to give $1 a safe home directory" \
+ "/Users/$1" "NFSHomeDirectory" "$2"
}
poly_user_note_get() {
@@ -170,8 +185,8 @@ poly_user_note_get() {
}
poly_user_note_set() {
- _sudo "in order to give $username a useful note" \
- /usr/bin/dscl . -create "/Users/$1" "RealName" "$2"
+ dscl_create "in order to give $1 a useful note" \
+ "/Users/$1" "RealName" "$2"
}
poly_user_shell_get() {
@@ -179,8 +194,8 @@ poly_user_shell_get() {
}
poly_user_shell_set() {
- _sudo "in order to give $1 a safe shell" \
- /usr/bin/dscl . -create "/Users/$1" "UserShell" "$2"
+ dscl_create "in order to give $1 a safe shell" \
+ "/Users/$1" "UserShell" "$2"
}
poly_user_in_group_check() {
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index a487d459f..f051ccc46 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -56,6 +56,9 @@ readonly NIX_INSTALLED_CACERT="@cacert@"
#readonly NIX_INSTALLED_CACERT="/nix/store/7dxhzymvy330i28ii676fl1pqwcahv2f-nss-cacert-3.49.2"
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
+# allow to override identity change command
+readonly NIX_BECOME=${NIX_BECOME:-sudo}
+
readonly ROOT_HOME=~root
if [ -t 0 ] && [ -z "${NIX_INSTALLER_YES:-}" ]; then
@@ -123,7 +126,7 @@ uninstall_directions() {
cat < "$SCRATCH/.nix-channels"
_sudo "to set up the default system channel (part 1)" \
- install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"
+ install -m 0644 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"
fi
}
@@ -964,7 +969,7 @@ $NIX_EXTRA_CONF
build-users-group = $NIX_BUILD_GROUP_NAME
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
- install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
+ install -m 0644 "$SCRATCH/nix.conf" /etc/nix/nix.conf
}
diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-tarball.sh
similarity index 95%
rename from scripts/install-nix-from-closure.sh
rename to scripts/install-nix-from-tarball.sh
index 794622530..8d127a9c5 100644
--- a/scripts/install-nix-from-closure.sh
+++ b/scripts/install-nix-from-tarball.sh
@@ -9,6 +9,8 @@ self="$(dirname "$0")"
nix="@nix@"
cacert="@cacert@"
+# allow to override identity change command
+readonly NIX_BECOME="${NIX_BECOME:-sudo}"
if ! [ -e "$self/.reginfo" ]; then
echo "$0: incomplete installer (.reginfo is missing)" >&2
@@ -48,15 +50,14 @@ case "$(uname -s)" in
INSTALL_MODE=no-daemon;;
esac
-# space-separated string
-ACTIONS=
+ACTION=
# handle the command line flags
while [ $# -gt 0 ]; do
case $1 in
--daemon)
INSTALL_MODE=daemon
- ACTIONS="${ACTIONS}install "
+ ACTION=install
;;
--no-daemon)
if [ "$(uname -s)" = "Darwin" ]; then
@@ -64,19 +65,14 @@ while [ $# -gt 0 ]; do
exit 1
fi
INSTALL_MODE=no-daemon
- # intentional tail space
- ACTIONS="${ACTIONS}install "
+ ACTION=install
;;
- # --uninstall)
- # # intentional tail space
- # ACTIONS="${ACTIONS}uninstall "
- # ;;
--yes)
export NIX_INSTALLER_YES=1;;
--no-channel-add)
export NIX_INSTALLER_NO_CHANNEL_ADD=1;;
--daemon-user-count)
- export NIX_USER_COUNT=$2
+ export NIX_USER_COUNT="$2"
shift;;
--no-modify-profile)
NIX_INSTALLER_NO_MODIFY_PROFILE=1;;
@@ -128,7 +124,7 @@ done
if [ "$INSTALL_MODE" = "daemon" ]; then
printf '\e[1;31mSwitching to the Multi-user Installer\e[0m\n'
- exec "$self/install-multi-user" $ACTIONS # let ACTIONS split
+ exec "$self/install-multi-user" $ACTION
exit 0
fi
@@ -140,8 +136,8 @@ echo "performing a single-user installation of Nix..." >&2
if ! [ -e "$dest" ]; then
cmd="mkdir -m 0755 $dest && chown $USER $dest"
- echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2
- if ! sudo sh -c "$cmd"; then
+ echo "directory $dest does not exist; creating it by running '$cmd' using $NIX_BECOME" >&2
+ if ! $NIX_BECOME sh -c "$cmd"; then
echo "$0: please manually run '$cmd' as root to create $dest" >&2
exit 1
fi
diff --git a/scripts/install-systemd-multi-user.sh b/scripts/install-systemd-multi-user.sh
index a79a69990..dc373f4db 100755
--- a/scripts/install-systemd-multi-user.sh
+++ b/scripts/install-systemd-multi-user.sh
@@ -96,6 +96,9 @@ poly_configure_nix_daemon_service() {
if [ -e /run/systemd/system ]; then
task "Setting up the nix-daemon systemd service"
+ _sudo "to create parent of the nix-daemon tmpfiles config" \
+ mkdir -p "$(dirname "$TMPFILES_DEST")"
+
_sudo "to create the nix-daemon tmpfiles config" \
ln -sfn "/nix/var/nix/profiles/default$TMPFILES_SRC" "$TMPFILES_DEST"
diff --git a/scripts/installer.nix b/scripts/installer.nix
index 3d51d4916..a8e344b49 100644
--- a/scripts/installer.nix
+++ b/scripts/installer.nix
@@ -1,36 +1,42 @@
-{ lib
-, runCommand
-, nix
-, tarballs
+{
+ lib,
+ runCommand,
+ nix,
+ tarballs,
}:
-runCommand "installer-script" {
- buildInputs = [ nix ];
-} ''
- mkdir -p $out/nix-support
-
- # Converts /nix/store/50p3qk8k...-nix-2.4pre20201102_550e11f/bin/nix to 50p3qk8k.../bin/nix.
- tarballPath() {
- # Remove the store prefix
- local path=''${1#${builtins.storeDir}/}
- # Get the path relative to the derivation root
- local rest=''${path#*/}
- # Get the derivation hash
- local drvHash=''${path%%-*}
- echo "$drvHash/$rest"
+runCommand "installer-script"
+ {
+ buildInputs = [ nix ];
}
+ ''
+ mkdir -p $out/nix-support
- substitute ${./install.in} $out/install \
- ${lib.concatMapStrings
- (tarball: let
- inherit (tarball.stdenv.hostPlatform) system;
- in '' \
- --replace '@tarballHash_${system}@' $(nix hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
- --replace '@tarballPath_${system}@' $(tarballPath ${tarball}/*.tar.xz) \
- ''
- )
- tarballs
- } --replace '@nixVersion@' ${nix.version}
+ # Converts /nix/store/50p3qk8k...-nix-2.4pre20201102_550e11f/bin/nix to 50p3qk8k.../bin/nix.
+ tarballPath() {
+ # Remove the store prefix
+ local path=''${1#${builtins.storeDir}/}
+ # Get the path relative to the derivation root
+ local rest=''${path#*/}
+ # Get the derivation hash
+ local drvHash=''${path%%-*}
+ echo "$drvHash/$rest"
+ }
- echo "file installer $out/install" >> $out/nix-support/hydra-build-products
-''
+ substitute ${./install.in} $out/install \
+ ${
+ lib.concatMapStrings (
+ tarball:
+ let
+ inherit (tarball.stdenv.hostPlatform) system;
+ in
+ ''
+ \
+ --replace '@tarballHash_${system}@' $(nix hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
+ --replace '@tarballPath_${system}@' $(tarballPath ${tarball}/*.tar.xz) \
+ ''
+ ) tarballs
+ } --replace '@nixVersion@' ${nix.version}
+
+ echo "file installer $out/install" >> $out/nix-support/hydra-build-products
+ ''
diff --git a/scripts/local.mk b/scripts/local.mk
deleted file mode 100644
index 46255e432..000000000
--- a/scripts/local.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-nix_noinst_scripts := \
- $(d)/nix-profile.sh
-
-noinst-scripts += $(nix_noinst_scripts)
-
-profiledir = $(sysconfdir)/profile.d
-
-$(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644))
-$(eval $(call install-file-as, $(d)/nix-profile.fish, $(profiledir)/nix.fish, 0644))
-$(eval $(call install-file-as, $(d)/nix-profile-daemon.sh, $(profiledir)/nix-daemon.sh, 0644))
-$(eval $(call install-file-as, $(d)/nix-profile-daemon.fish, $(profiledir)/nix-daemon.fish, 0644))
-
-clean-files += $(nix_noinst_scripts)
diff --git a/scripts/meson.build b/scripts/meson.build
new file mode 100644
index 000000000..777da42b1
--- /dev/null
+++ b/scripts/meson.build
@@ -0,0 +1,20 @@
+configure_file(
+ input : 'nix-profile.sh.in',
+ output : 'nix-profile.sh',
+ configuration : {
+ 'localstatedir': localstatedir,
+ }
+)
+
+foreach rc : [ '.sh', '.fish', '-daemon.sh', '-daemon.fish' ]
+ configure_file(
+ input : 'nix-profile' + rc + '.in',
+ output : 'nix' + rc,
+ install : true,
+ install_dir : get_option('profile-dir'),
+ install_mode : 'rw-r--r--',
+ configuration : {
+ 'localstatedir': localstatedir,
+ },
+ )
+endforeach
diff --git a/scripts/nix-profile-daemon.sh.in b/scripts/nix-profile-daemon.sh.in
index eb124c0b5..59c00d491 100644
--- a/scripts/nix-profile-daemon.sh.in
+++ b/scripts/nix-profile-daemon.sh.in
@@ -52,7 +52,7 @@ elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS
else
# Fall back to what is in the nix profiles, favouring whatever is defined last.
check_nix_profiles() {
- if [ -n "$ZSH_VERSION" ]; then
+ if [ -n "${ZSH_VERSION:-}" ]; then
# Zsh by default doesn't split words in unquoted parameter expansion.
# Set local_options for these options to be reverted at the end of the function
# and shwordsplit to force splitting words in $NIX_PROFILES below.
diff --git a/scripts/nix-profile.fish.in b/scripts/nix-profile.fish.in
index 619df52b8..3a8c234ad 100644
--- a/scripts/nix-profile.fish.in
+++ b/scripts/nix-profile.fish.in
@@ -29,7 +29,7 @@ if test -n "$HOME" && test -n "$USER"
end
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
- if test -n "$NIX_SSH_CERT_FILE"
+ if test -n "$NIX_SSL_CERT_FILE"
: # Allow users to override the NIX_SSL_CERT_FILE
else if test -e /etc/ssl/certs/ca-certificates.crt # NixOS, Ubuntu, Debian, Gentoo, Arch
set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt
diff --git a/scripts/nix-profile.sh.in b/scripts/nix-profile.sh.in
index e868399b1..2d6bf6e95 100644
--- a/scripts/nix-profile.sh.in
+++ b/scripts/nix-profile.sh.in
@@ -1,31 +1,35 @@
# This file is tested by tests/installer/default.nix.
-if [ -n "$HOME" ] && [ -n "$USER" ]; then
+if [ -n "${HOME-}" ] && [ -n "${USER-}" ]; then
# Set up the per-user profile.
- NIX_LINK="$HOME/.nix-profile"
- if [ -n "${XDG_STATE_HOME-}" ]; then
- NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile"
+ if [ -n "${NIX_STATE_HOME-}" ]; then
+ NIX_LINK="$NIX_STATE_HOME/profile"
else
- NIX_LINK_NEW="$HOME/.local/state/nix/profile"
- fi
- if [ -e "$NIX_LINK_NEW" ]; then
- if [ -t 2 ] && [ -e "$NIX_LINK" ]; then
- warning="\033[1;35mwarning:\033[0m"
- printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
- if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then
- printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
- else
- # This should be an exceptionally rare occasion: the only way to get it would be to
- # 1. Update to newer Nix;
- # 2. Remove .nix-profile;
- # 3. Set the $NIX_LINK_NEW to something other than the default user profile;
- # 4. Roll back to older Nix.
- # If someone did all that, they can probably figure out how to migrate the profile.
- printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
- fi
+ NIX_LINK="$HOME/.nix-profile"
+ if [ -n "${XDG_STATE_HOME-}" ]; then
+ NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile"
+ else
+ NIX_LINK_NEW="$HOME/.local/state/nix/profile"
+ fi
+ if [ -e "$NIX_LINK_NEW" ]; then
+ if [ -t 2 ] && [ -e "$NIX_LINK" ]; then
+ warning="\033[1;35mwarning:\033[0m"
+ printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
+ if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then
+ printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
+ else
+ # This should be an exceptionally rare occasion: the only way to get it would be to
+ # 1. Update to newer Nix;
+ # 2. Remove .nix-profile;
+ # 3. Set the $NIX_LINK_NEW to something other than the default user profile;
+ # 4. Roll back to older Nix.
+ # If someone did all that, they can probably figure out how to migrate the profile.
+ printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
+ fi
+ fi
+ NIX_LINK="$NIX_LINK_NEW"
fi
- NIX_LINK="$NIX_LINK_NEW"
fi
# Set up environment.
diff --git a/scripts/prepare-installer-for-github-actions b/scripts/prepare-installer-for-github-actions
index 4b994a753..0fbecf25c 100755
--- a/scripts/prepare-installer-for-github-actions
+++ b/scripts/prepare-installer-for-github-actions
@@ -1,10 +1,11 @@
#!/usr/bin/env bash
-set -e
+set -euo pipefail
-script=$(nix-build -A outputs.hydraJobs.installerScriptForGHA --no-out-link)
-installerHash=$(echo "$script" | cut -b12-43 -)
+nix build -L ".#installerScriptForGHA" ".#binaryTarball"
-installerURL=https://$CACHIX_NAME.cachix.org/serve/$installerHash/install
-
-echo "::set-output name=installerURL::$installerURL"
+mkdir -p out
+cp ./result/install "out/install"
+name="$(basename "$(realpath ./result-1)")"
+# everything before the first dash
+cp -r ./result-1 "out/${name%%-*}"
diff --git a/scripts/sequoia-nixbld-user-migration.sh b/scripts/sequoia-nixbld-user-migration.sh
new file mode 100755
index 000000000..58b5fea64
--- /dev/null
+++ b/scripts/sequoia-nixbld-user-migration.sh
@@ -0,0 +1,172 @@
+#!/usr/bin/env bash
+
+set -eo pipefail
+
+# stock path to avoid unexpected command versions
+PATH="$(/usr/bin/getconf PATH)"
+
+((NEW_NIX_FIRST_BUILD_UID=351))
+((TEMP_NIX_FIRST_BUILD_UID=31000))
+
+nix_user_n() {
+ printf "_nixbld%d" "$1"
+}
+
+id_unavailable(){
+ dscl . list /Users UniqueID | grep -E '\b'"$1"'\b' >/dev/null
+}
+
+any_nixbld(){
+ dscl . list /Users UniqueID | grep -E '\b_nixbld' >/dev/null
+}
+
+dsclattr() {
+ dscl . -read "$1" | awk "/$2/ { print \$2 }"
+}
+
+re_create_nixbld_user(){
+ local name uid
+
+ name="$1"
+ uid="$2"
+ gid="$3"
+
+ sudo /usr/bin/dscl . -create "/Users/$name" "UniqueID" "$uid"
+ sudo /usr/bin/dscl . -create "/Users/$name" "IsHidden" "1"
+ sudo /usr/bin/dscl . -create "/Users/$name" "NFSHomeDirectory" "/var/empty"
+ sudo /usr/bin/dscl . -create "/Users/$name" "RealName" "Nix build user $name"
+ sudo /usr/bin/dscl . -create "/Users/$name" "UserShell" "/sbin/nologin"
+ sudo /usr/bin/dscl . -create "/Users/$name" "PrimaryGroupID" "$gid"
+}
+
+hit_id_cap(){
+ echo "We've hit UID 400 without placing all of your users :("
+ echo "You should use the commands in this script as a starting"
+ echo "point to review your UID-space and manually move the"
+ echo "remaining users (or delete them, if you don't need them)."
+}
+
+# evacuate the role-uid space to simplify final placement logic
+temporarily_move_existing_nixbld_uids(){
+ local name uid next_id user_n
+
+ ((next_id=TEMP_NIX_FIRST_BUILD_UID))
+
+ echo ""
+ echo "Step 1: move existing _nixbld users out of the destination UID range."
+
+ while read -r name uid; do
+ # iterate for a clean ID
+ while id_unavailable "$next_id"; do
+ ((next_id++))
+ # We really want to get these all placed, but I guess there's
+ # some risk we iterate forever--so we'll give up after 9k uids.
+ if ((next_id >= 40000)); then
+ echo "We've hit UID 40000 without temporarily placing all of your users :("
+ echo "You should use the commands in this script as a starting"
+ echo "point to review your UID-space and manually move the"
+ echo "remaining users to any open UID over 1000."
+ exit 1
+ fi
+ done
+ sudo dscl . -create "/Users/$name" UniqueID "$next_id"
+ echo " Temporarily moved $name from uid $uid -> $next_id"
+
+ done < <(dscl . list /Users UniqueID | grep _nixbld | sort -n -k2)
+}
+
+change_nixbld_uids(){
+ local existing_gid name next_id user_n
+
+ ((next_id=NEW_NIX_FIRST_BUILD_UID))
+ ((user_n=1))
+ name="$(nix_user_n "$user_n")"
+ existing_gid="$(dsclattr "/Groups/nixbld" "PrimaryGroupID")"
+
+ # we know that we have *some* nixbld users, but macOS may have
+ # already clobbered the first few users if this system has been
+ # upgraded
+
+ echo ""
+ echo "Step 2: re-create missing early _nixbld# users."
+
+ until dscl . read "/Users/$name" &>/dev/null; do
+ # iterate for a clean ID
+ while id_unavailable "$next_id"; do
+ ((next_id++))
+ if ((next_id >= 400)); then
+ hit_id_cap
+ exit 1
+ fi
+ done
+
+ re_create_nixbld_user "$name" "$next_id" "$existing_gid"
+ echo " $name was missing; created with uid: $next_id"
+
+ ((user_n++))
+ name="$(nix_user_n "$user_n")"
+ done
+
+ echo ""
+ echo "Step 3: relocate remaining _nixbld# UIDs to $next_id+"
+
+ # start at first _nixbld# not re-created above and increment
+ # until _nixbld doesn't exist
+ while dscl . read "/Users/$name" &>/dev/null; do
+ # iterate for a clean ID
+ while id_unavailable "$next_id"; do
+ ((next_id++))
+ if ((next_id >= 400)); then
+ hit_id_cap
+ exit 1
+ fi
+ done
+
+ sudo dscl . -create "/Users/$name" UniqueID "$next_id"
+ echo " $name migrated to uid: $next_id"
+
+ ((user_n++))
+ name="$(nix_user_n "$user_n")"
+ done
+
+ if ((user_n == 1)); then
+ echo "Didn't find _nixbld1. Perhaps you have single-user Nix?"
+ exit 1
+ else
+ echo "Migrated $((user_n - 1)) users. If you want to double-check, try:"
+ echo "dscl . list /Users UniqueID | grep _nixbld | sort -n -k2"
+ fi
+}
+needs_migration(){
+ local name uid next_id user_n
+
+ ((next_id=NEW_NIX_FIRST_BUILD_UID))
+ ((user_n=1))
+
+ while read -r name uid; do
+ expected_name="$(nix_user_n "$user_n")"
+ if [[ "$expected_name" != "$name" ]]; then
+ return 0
+ fi
+ if [[ "$next_id" != "$uid" ]]; then
+ return 0
+ fi
+ ((next_id++))
+ ((user_n++))
+ done < <(dscl . list /Users UniqueID | grep _nixbld | sort -n -k2)
+ return 1
+}
+
+
+if any_nixbld; then
+ if needs_migration; then
+ echo "Attempting to migrate _nixbld users."
+ temporarily_move_existing_nixbld_uids
+ change_nixbld_uids
+ else
+ echo "_nixbld users already appear to be migrated."
+ fi
+else
+ echo "Didn't find any _nixbld users. Perhaps you have single-user Nix?"
+ exit 1
+fi
diff --git a/scripts/serve-installer-for-github-actions b/scripts/serve-installer-for-github-actions
new file mode 100755
index 000000000..2efd2aa32
--- /dev/null
+++ b/scripts/serve-installer-for-github-actions
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+if [[ ! -d out ]]; then
+ echo "run prepare-installer-for-github-actions first"
+ exit 1
+fi
+cd out
+PORT=${PORT:-8126}
+nohup python -m http.server "$PORT" >/dev/null 2>&1 &
+pid=$!
+
+while ! curl -s "http://localhost:$PORT"; do
+ sleep 1
+ if ! kill -0 $pid; then
+ echo "Failed to start http server"
+ exit 1
+ fi
+done
+
+echo 'To install nix, run the following command:'
+echo "sh <(curl http://localhost:$PORT/install) --tarball-url-prefix http://localhost:$PORT"
diff --git a/src/external-api-docs/doxygen.cfg.in b/src/external-api-docs/doxygen.cfg.in
index 1be71d895..3af2f5b81 100644
--- a/src/external-api-docs/doxygen.cfg.in
+++ b/src/external-api-docs/doxygen.cfg.in
@@ -40,8 +40,9 @@ GENERATE_LATEX = NO
INPUT = \
@src@/src/libutil-c \
@src@/src/libexpr-c \
+ @src@/src/libflake-c \
@src@/src/libstore-c \
- @src@/doc/external-api/README.md
+ @src@/src/external-api-docs/README.md
FILE_PATTERNS = nix_api_*.h *.md
@@ -55,4 +56,8 @@ EXCLUDE_PATTERNS = *_internal.h
GENERATE_TREEVIEW = YES
OPTIMIZE_OUTPUT_FOR_C = YES
-USE_MDFILE_AS_MAINPAGE = doc/external-api/README.md
+USE_MDFILE_AS_MAINPAGE = @src@/src/external-api-docs/README.md
+
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_INCOMPLETE_DOC = NO
+QUIET = YES
diff --git a/src/external-api-docs/package.nix b/src/external-api-docs/package.nix
index 743b3e9b7..b194e16d4 100644
--- a/src/external-api-docs/package.nix
+++ b/src/external-api-docs/package.nix
@@ -1,13 +1,12 @@
-{ lib
-, mkMesonDerivation
+{
+ lib,
+ mkMesonDerivation,
-, meson
-, ninja
-, doxygen
+ doxygen,
-# Configuration Options
+ # Configuration Options
-, version
+ version,
}:
let
@@ -32,21 +31,19 @@ mkMesonDerivation (finalAttrs: {
# Source is not compiled, but still must be available for Doxygen
# to gather comments.
(cpp ../libexpr-c)
+ (cpp ../libflake-c)
(cpp ../libstore-c)
(cpp ../libutil-c)
];
nativeBuildInputs = [
- meson
- ninja
doxygen
];
- preConfigure =
- ''
- chmod u+w ./.version
- echo ${finalAttrs.version} > ./.version
- '';
+ preConfigure = ''
+ chmod u+w ./.version
+ echo ${finalAttrs.version} > ./.version
+ '';
postInstall = ''
mkdir -p ''${!outputDoc}/nix-support
diff --git a/src/internal-api-docs/doxygen.cfg.in b/src/internal-api-docs/doxygen.cfg.in
index f1ef75b38..950497ca3 100644
--- a/src/internal-api-docs/doxygen.cfg.in
+++ b/src/internal-api-docs/doxygen.cfg.in
@@ -41,21 +41,22 @@ INPUT = \
@src@/libcmd \
@src@/libexpr \
@src@/libexpr/flake \
- @src@/nix-expr-tests \
- @src@/nix-expr-tests/value \
- @src@/nix-expr-test-support/test \
- @src@/nix-expr-test-support/test/value \
+ @src@/libexpr-tests \
+ @src@/libexpr-tests/value \
+ @src@/libexpr-test-support/tests \
+ @src@/libexpr-test-support/tests/value \
@src@/libexpr/value \
@src@/libfetchers \
@src@/libmain \
@src@/libstore \
@src@/libstore/build \
@src@/libstore/builtins \
- @src@/nix-store-tests \
- @src@/nix-store-test-support/test \
+ @src@/libstore-tests \
+ @src@/libstore-test-support/tests \
@src@/libutil \
- @src@/nix-util-tests \
- @src@/nix-util-test-support/test \
+ @src@/libutil/args \
+ @src@/libutil-tests \
+ @src@/libutil-test-support/tests \
@src@/nix \
@src@/nix-env \
@src@/nix-store
@@ -83,7 +84,9 @@ EXPAND_ONLY_PREDEF = YES
# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-INCLUDE_PATH =
+INCLUDE_PATH = \
+ @BUILD_ROOT@/src/libexpr/libnixexpr.so.p \
+ @BUILD_ROOT@/src/nix/nix.p \
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@@ -96,4 +99,18 @@ EXPAND_AS_DEFINED = \
DECLARE_COMMON_SERIALISER \
DECLARE_WORKER_SERIALISER \
DECLARE_SERVE_SERIALISER \
- LENGTH_PREFIXED_PROTO_HELPER
+ LENGTH_PREFIXED_PROTO_HELPER \
+ LENGTH_PREFIXED_PROTO_HELPER_X \
+ WORKER_USE_LENGTH_PREFIX_SERIALISER \
+ WORKER_USE_LENGTH_PREFIX_SERIALISER_COMMA \
+ SERVE_USE_LENGTH_PREFIX_SERIALISER \
+ SERVE_USE_LENGTH_PREFIX_SERIALISER_COMMA \
+ COMMON_METHODS \
+ JSON_IMPL \
+ MakeBinOp
+
+PREDEFINED = DOXYGEN_SKIP
+
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_INCOMPLETE_DOC = NO
+QUIET = YES
diff --git a/src/internal-api-docs/meson.build b/src/internal-api-docs/meson.build
index 54eb7e5dd..c0426621e 100644
--- a/src/internal-api-docs/meson.build
+++ b/src/internal-api-docs/meson.build
@@ -12,6 +12,7 @@ doxygen_cfg = configure_file(
configuration : {
'PROJECT_NUMBER': meson.project_version(),
'OUTPUT_DIRECTORY' : meson.current_build_dir(),
+ 'BUILD_ROOT' : meson.build_root(),
'src' : fs.parent(fs.parent(meson.project_source_root())) / 'src',
},
)
diff --git a/src/internal-api-docs/package.nix b/src/internal-api-docs/package.nix
index 07ca6d4d9..6c4f354ae 100644
--- a/src/internal-api-docs/package.nix
+++ b/src/internal-api-docs/package.nix
@@ -1,13 +1,12 @@
-{ lib
-, mkMesonDerivation
+{
+ lib,
+ mkMesonDerivation,
-, meson
-, ninja
-, doxygen
+ doxygen,
-# Configuration Options
+ # Configuration Options
-, version
+ version,
}:
let
@@ -19,29 +18,28 @@ mkMesonDerivation (finalAttrs: {
inherit version;
workDir = ./.;
- fileset = let
- cpp = fileset.fileFilter (file: file.hasExt "cc" || file.hasExt "hh");
- in fileset.unions [
- ./.version
- ../../.version
- ./meson.build
- ./doxygen.cfg.in
- # Source is not compiled, but still must be available for Doxygen
- # to gather comments.
- (cpp ../.)
- ];
+ fileset =
+ let
+ cpp = fileset.fileFilter (file: file.hasExt "cc" || file.hasExt "hh");
+ in
+ fileset.unions [
+ ./.version
+ ../../.version
+ ./meson.build
+ ./doxygen.cfg.in
+ # Source is not compiled, but still must be available for Doxygen
+ # to gather comments.
+ (cpp ../.)
+ ];
nativeBuildInputs = [
- meson
- ninja
doxygen
];
- preConfigure =
- ''
- chmod u+w ./.version
- echo ${finalAttrs.version} > ./.version
- '';
+ preConfigure = ''
+ chmod u+w ./.version
+ echo ${finalAttrs.version} > ./.version
+ '';
postInstall = ''
mkdir -p ''${!outputDoc}/nix-support
diff --git a/src/libcmd/build-utils-meson b/src/libcmd/build-utils-meson
deleted file mode 120000
index 5fff21bab..000000000
--- a/src/libcmd/build-utils-meson
+++ /dev/null
@@ -1 +0,0 @@
-../../build-utils-meson
\ No newline at end of file
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 67fef1909..86d13fab7 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -1,3 +1,4 @@
+#include
#include
#include "command.hh"
@@ -9,8 +10,7 @@
#include "profiles.hh"
#include "repl.hh"
#include "strings.hh"
-
-extern char * * environ __attribute__((weak));
+#include "environment-variables.hh"
namespace nix {
@@ -23,7 +23,8 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector & p
if (name.size() == prefix.size() + 1) {
bool equal = true;
for (size_t i = 0; i < prefix.size(); ++i)
- if (name[i] != prefix[i]) equal = false;
+ if (name[i] != prefix[i])
+ equal = false;
if (equal)
res.insert_or_assign(name[prefix.size()], command);
}
@@ -42,16 +43,16 @@ void NixMultiCommand::run()
std::set subCommandTextLines;
for (auto & [name, _] : commands)
subCommandTextLines.insert(fmt("- `%s`", name));
- std::string markdownError = fmt("`nix %s` requires a sub-command. Available sub-commands:\n\n%s\n",
- commandName, concatStringsSep("\n", subCommandTextLines));
+ std::string markdownError =
+ fmt("`nix %s` requires a sub-command. Available sub-commands:\n\n%s\n",
+ commandName,
+ concatStringsSep("\n", subCommandTextLines));
throw UsageError(renderMarkdownToTerminal(markdownError));
}
command->second->run();
}
-StoreCommand::StoreCommand()
-{
-}
+StoreCommand::StoreCommand() {}
ref StoreCommand::getStore()
{
@@ -126,15 +127,8 @@ ref EvalCommand::getEvalStore()
ref EvalCommand::getEvalState()
{
if (!evalState) {
- evalState =
- #if HAVE_BOEHMGC
- std::allocate_shared(
- traceable_allocator(),
- #else
- std::make_shared(
- #endif
- lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore())
- ;
+ evalState = std::allocate_shared(
+ traceable_allocator(), lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore());
evalState->repair = repair;
@@ -149,7 +143,8 @@ MixOperateOnOptions::MixOperateOnOptions()
{
addFlag({
.longName = "derivation",
- .description = "Operate on the [store derivation](@docroot@/glossary.md#gloss-store-derivation) rather than its outputs.",
+ .description =
+ "Operate on the [store derivation](@docroot@/glossary.md#gloss-store-derivation) rather than its outputs.",
.category = installablesCategory,
.handler = {&operateOn, OperateOn::Derivation},
});
@@ -184,30 +179,34 @@ BuiltPathsCommand::BuiltPathsCommand(bool recursive)
void BuiltPathsCommand::run(ref store, Installables && installables)
{
- BuiltPaths paths;
+ BuiltPaths rootPaths, allPaths;
+
if (all) {
if (installables.size())
throw UsageError("'--all' does not expect arguments");
// XXX: Only uses opaque paths, ignores all the realisations
for (auto & p : store->queryAllValidPaths())
- paths.emplace_back(BuiltPath::Opaque{p});
+ rootPaths.emplace_back(BuiltPath::Opaque{p});
+ allPaths = rootPaths;
} else {
- paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
+ rootPaths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
+ allPaths = rootPaths;
+
if (recursive) {
// XXX: This only computes the store path closure, ignoring
// intermediate realisations
StorePathSet pathsRoots, pathsClosure;
- for (auto & root : paths) {
+ for (auto & root : rootPaths) {
auto rootFromThis = root.outPaths();
pathsRoots.insert(rootFromThis.begin(), rootFromThis.end());
}
store->computeFSClosure(pathsRoots, pathsClosure);
for (auto & path : pathsClosure)
- paths.emplace_back(BuiltPath::Opaque{path});
+ allPaths.emplace_back(BuiltPath::Opaque{path});
}
}
- run(store, std::move(paths));
+ run(store, std::move(allPaths), std::move(rootPaths));
}
StorePathsCommand::StorePathsCommand(bool recursive)
@@ -215,10 +214,10 @@ StorePathsCommand::StorePathsCommand(bool recursive)
{
}
-void StorePathsCommand::run(ref store, BuiltPaths && paths)
+void StorePathsCommand::run(ref store, BuiltPaths && allPaths, BuiltPaths && rootPaths)
{
StorePathSet storePaths;
- for (auto & builtPath : paths)
+ for (auto & builtPath : allPaths)
for (auto & p : builtPath.outPaths())
storePaths.insert(p);
@@ -238,46 +237,48 @@ void StorePathCommand::run(ref store, StorePaths && storePaths)
MixProfile::MixProfile()
{
- addFlag({
- .longName = "profile",
- .description = "The profile to operate on.",
- .labels = {"path"},
- .handler = {&profile},
- .completer = completePath
- });
+ addFlag(
+ {.longName = "profile",
+ .description = "The profile to operate on.",
+ .labels = {"path"},
+ .handler = {&profile},
+ .completer = completePath});
}
void MixProfile::updateProfile(const StorePath & storePath)
{
- if (!profile) return;
- auto store = getStore().dynamic_pointer_cast();
- if (!store) throw Error("'--profile' is not supported for this Nix store");
+ if (!profile)
+ return;
+ auto store = getDstStore().dynamic_pointer_cast();
+ if (!store)
+ throw Error("'--profile' is not supported for this Nix store");
auto profile2 = absPath(*profile);
- switchLink(profile2,
- createGeneration(*store, profile2, storePath));
+ switchLink(profile2, createGeneration(*store, profile2, storePath));
}
void MixProfile::updateProfile(const BuiltPaths & buildables)
{
- if (!profile) return;
+ if (!profile)
+ return;
StorePaths result;
for (auto & buildable : buildables) {
- std::visit(overloaded {
- [&](const BuiltPath::Opaque & bo) {
- result.push_back(bo.path);
+ std::visit(
+ overloaded{
+ [&](const BuiltPath::Opaque & bo) { result.push_back(bo.path); },
+ [&](const BuiltPath::Built & bfd) {
+ for (auto & output : bfd.outputs) {
+ result.push_back(output.second);
+ }
+ },
},
- [&](const BuiltPath::Built & bfd) {
- for (auto & output : bfd.outputs) {
- result.push_back(output.second);
- }
- },
- }, buildable.raw());
+ buildable.raw());
}
if (result.size() != 1)
- throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
+ throw UsageError(
+ "'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
updateProfile(result[0]);
}
@@ -287,50 +288,111 @@ MixDefaultProfile::MixDefaultProfile()
profile = getDefaultProfile();
}
-MixEnvironment::MixEnvironment() : ignoreEnvironment(false)
+MixEnvironment::MixEnvironment()
+ : ignoreEnvironment(false)
{
addFlag({
- .longName = "ignore-environment",
+ .longName = "ignore-env",
+ .aliases = {"ignore-environment"},
.shortName = 'i',
- .description = "Clear the entire environment (except those specified with `--keep`).",
+ .description = "Clear the entire environment, except for those specified with `--keep-env-var`.",
+ .category = environmentVariablesCategory,
.handler = {&ignoreEnvironment, true},
});
addFlag({
- .longName = "keep",
+ .longName = "keep-env-var",
+ .aliases = {"keep"},
.shortName = 'k',
- .description = "Keep the environment variable *name*.",
+ .description = "Keep the environment variable *name*, when using `--ignore-env`.",
+ .category = environmentVariablesCategory,
.labels = {"name"},
- .handler = {[&](std::string s) { keep.insert(s); }},
+ .handler = {[&](std::string s) { keepVars.insert(s); }},
});
addFlag({
- .longName = "unset",
+ .longName = "unset-env-var",
+ .aliases = {"unset"},
.shortName = 'u',
.description = "Unset the environment variable *name*.",
+ .category = environmentVariablesCategory,
.labels = {"name"},
- .handler = {[&](std::string s) { unset.insert(s); }},
+ .handler = {[&](std::string name) {
+ if (setVars.contains(name))
+ throw UsageError("Cannot unset environment variable '%s' that is set with '%s'", name, "--set-env-var");
+
+ unsetVars.insert(name);
+ }},
+ });
+
+ addFlag({
+ .longName = "set-env-var",
+ .shortName = 's',
+ .description = "Sets an environment variable *name* with *value*.",
+ .category = environmentVariablesCategory,
+ .labels = {"name", "value"},
+ .handler = {[&](std::string name, std::string value) {
+ if (unsetVars.contains(name))
+ throw UsageError(
+ "Cannot set environment variable '%s' that is unset with '%s'", name, "--unset-env-var");
+
+ if (setVars.contains(name))
+ throw UsageError(
+ "Duplicate definition of environment variable '%s' with '%s' is ambiguous", name, "--set-env-var");
+
+ setVars.insert_or_assign(name, value);
+ }},
});
}
-void MixEnvironment::setEnviron() {
- if (ignoreEnvironment) {
- if (!unset.empty())
- throw UsageError("--unset does not make sense with --ignore-environment");
+void MixEnvironment::setEnviron()
+{
+ if (ignoreEnvironment && !unsetVars.empty())
+ throw UsageError("--unset-env-var does not make sense with --ignore-env");
- for (const auto & var : keep) {
- auto val = getenv(var.c_str());
- if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
- }
+ if (!ignoreEnvironment && !keepVars.empty())
+ throw UsageError("--keep-env-var does not make sense without --ignore-env");
- vectorEnv = stringsToCharPtrs(stringsEnv);
- environ = vectorEnv.data();
- } else {
- if (!keep.empty())
- throw UsageError("--keep does not make sense without --ignore-environment");
+ auto env = getEnv();
- for (const auto & var : unset)
- unsetenv(var.c_str());
+ if (ignoreEnvironment)
+ std::erase_if(env, [&](const auto & var) { return !keepVars.contains(var.first); });
+
+ for (const auto & [name, value] : setVars)
+ env[name] = value;
+
+ if (!unsetVars.empty())
+ std::erase_if(env, [&](const auto & var) { return unsetVars.contains(var.first); });
+
+ replaceEnv(env);
+
+ return;
+}
+
+void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & buildables, LocalFSStore & store)
+{
+ for (const auto & [_i, buildable] : enumerate(buildables)) {
+ auto i = _i;
+ std::visit(
+ overloaded{
+ [&](const BuiltPath::Opaque & bo) {
+ auto symlink = outLink;
+ if (i)
+ symlink += fmt("-%d", i);
+ store.addPermRoot(bo.path, absPath(symlink.string()));
+ },
+ [&](const BuiltPath::Built & bfd) {
+ for (auto & output : bfd.outputs) {
+ auto symlink = outLink;
+ if (i)
+ symlink += fmt("-%d", i);
+ if (output.first != "out")
+ symlink += fmt("-%s", output.first);
+ store.addPermRoot(output.second, absPath(symlink.string()));
+ }
+ },
+ },
+ buildable.raw());
}
}
diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh
index 4a72627ed..23529848f 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -13,18 +13,20 @@ namespace nix {
extern std::string programPath;
-extern char * * savedArgv;
+extern char ** savedArgv;
class EvalState;
struct Pos;
class Store;
+class LocalFSStore;
static constexpr Command::Category catHelp = -1;
static constexpr Command::Category catSecondary = 100;
static constexpr Command::Category catUtility = 101;
static constexpr Command::Category catNixInstallation = 102;
-static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
+static constexpr auto installablesCategory =
+ "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
struct NixMultiCommand : MultiCommand, virtual Command
{
@@ -45,7 +47,20 @@ struct StoreCommand : virtual Command
{
StoreCommand();
void run() override;
+
+ /**
+ * Return the default Nix store.
+ */
ref getStore();
+
+ /**
+ * Return the destination Nix store.
+ */
+ virtual ref getDstStore()
+ {
+ return getStore();
+ }
+
virtual ref createStore();
/**
* Main entry point, with a `Store` provided
@@ -68,7 +83,7 @@ struct CopyCommand : virtual StoreCommand
ref createStore() override;
- ref getDstStore();
+ ref getDstStore() override;
};
/**
@@ -112,7 +127,9 @@ struct MixFlakeOptions : virtual Args, EvalCommand
* arguments) so that the completions for these flags can use them.
*/
virtual std::vector getFlakeRefsForCompletion()
- { return {}; }
+ {
+ return {};
+ }
};
struct SourceExprCommand : virtual Args, MixFlakeOptions
@@ -122,11 +139,9 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
SourceExprCommand();
- Installables parseInstallables(
- ref store, std::vector ss);
+ Installables parseInstallables(ref store, std::vector ss);
- ref parseInstallable(
- ref store, const std::string & installable);
+ ref parseInstallable(ref store, const std::string & installable);
virtual Strings getDefaultFlakeAttrPaths();
@@ -238,7 +253,7 @@ public:
BuiltPathsCommand(bool recursive = false);
- virtual void run(ref store, BuiltPaths && paths) = 0;
+ virtual void run(ref store, BuiltPaths && allPaths, BuiltPaths && rootPaths) = 0;
void run(ref store, Installables && installables) override;
@@ -251,7 +266,7 @@ struct StorePathsCommand : public BuiltPathsCommand
virtual void run(ref store, StorePaths && storePaths) = 0;
- void run(ref store, BuiltPaths && paths) override;
+ void run(ref store, BuiltPaths && allPaths, BuiltPaths && rootPaths) override;
};
/**
@@ -272,10 +287,10 @@ struct RegisterCommand
typedef std::map, std::function[()>> Commands;
static Commands * commands;
- RegisterCommand(std::vector && name,
- std::function][()> command)
+ RegisterCommand(std::vector && name, std::function][()> command)
{
- if (!commands) commands = new Commands;
+ if (!commands)
+ commands = new Commands;
commands->emplace(name, command);
}
@@ -285,13 +300,13 @@ struct RegisterCommand
template
static RegisterCommand registerCommand(const std::string & name)
{
- return RegisterCommand({name}, [](){ return make_ref(); });
+ return RegisterCommand({name}, []() { return make_ref(); });
}
template
static RegisterCommand registerCommand2(std::vector && name)
{
- return RegisterCommand(std::move(name), [](){ return make_ref(); });
+ return RegisterCommand(std::move(name), []() { return make_ref(); });
}
struct MixProfile : virtual StoreCommand
@@ -313,19 +328,21 @@ struct MixDefaultProfile : MixProfile
MixDefaultProfile();
};
-struct MixEnvironment : virtual Args {
+struct MixEnvironment : virtual Args
+{
- StringSet keep, unset;
- Strings stringsEnv;
- std::vector vectorEnv;
+ StringSet keepVars;
+ StringSet unsetVars;
+ std::map setVars;
bool ignoreEnvironment;
MixEnvironment();
/***
- * Modify global environ based on `ignoreEnvironment`, `keep`, and
- * `unset`. It's expected that exec will be called before this class
- * goes out of scope, otherwise `environ` will become invalid.
+ * Modify global environ based on `ignoreEnvironment`, `keep`,
+ * `unset`, and `added`. It's expected that exec will be called
+ * before this class goes out of scope, otherwise `environ` will
+ * become invalid.
*/
void setEnviron();
};
@@ -349,9 +366,12 @@ void completeFlakeRefWithFragment(
std::string showVersions(const std::set & versions);
void printClosureDiff(
- ref store,
- const StorePath & beforePath,
- const StorePath & afterPath,
- std::string_view indent);
+ ref store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent);
+
+/**
+ * Create symlinks prefixed by `outLink` to the store paths in
+ * `buildables`.
+ */
+void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & buildables, LocalFSStore & store);
}
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index f385361e5..36af9120e 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -18,6 +18,8 @@
namespace nix {
+namespace fs { using namespace std::filesystem; }
+
fetchers::Settings fetchSettings;
static GlobalConfig::Register rFetchSettings(&fetchSettings);
@@ -27,12 +29,12 @@ EvalSettings evalSettings {
{
{
"flake",
- [](ref store, std::string_view rest) {
+ [](EvalState & state, std::string_view rest) {
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(fetchSettings, std::string { rest }, {}, true, false);
debug("fetching flake search path element '%s''", rest);
- auto storePath = flakeRef.resolve(store).fetchTree(store).first;
- return store->toRealPath(storePath);
+ auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first;
+ return state.rootPath(state.store->toRealPath(storePath));
},
},
},
@@ -118,8 +120,8 @@ MixEvalArgs::MixEvalArgs()
.category = category,
.labels = {"original-ref", "resolved-ref"},
.handler = {[&](std::string _from, std::string _to) {
- auto from = parseFlakeRef(fetchSettings, _from, absPath("."));
- auto to = parseFlakeRef(fetchSettings, _to, absPath("."));
+ auto from = parseFlakeRef(fetchSettings, _from, fs::current_path().string());
+ auto to = parseFlakeRef(fetchSettings, _to, fs::current_path().string());
fetchers::Attrs extraAttrs;
if (to.subdir != "") extraAttrs["dir"] = to.subdir;
fetchers::overrideRegistry(from.input, to.input, extraAttrs);
diff --git a/src/libcmd/installable-derived-path.cc b/src/libcmd/installable-derived-path.cc
index 4d1f83a1c..abacd7350 100644
--- a/src/libcmd/installable-derived-path.cc
+++ b/src/libcmd/installable-derived-path.cc
@@ -32,16 +32,6 @@ InstallableDerivedPath InstallableDerivedPath::parse(
// store path.
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
auto storePath = store->followLinksToStorePath(prefix);
- // Remove this prior to stabilizing the new CLI.
- if (storePath.isDerivation()) {
- auto oldDerivedPath = DerivedPath::Built {
- .drvPath = makeConstantStorePathRef(storePath),
- .outputs = OutputsSpec::All { },
- };
- warn(
- "The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '%s'",
- oldDerivedPath.to_string(*store));
- };
return DerivedPath::Opaque {
.path = std::move(storePath),
};
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 8796ad5ba..6c9ee6748 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -104,12 +104,12 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
auto drvPath = attr->forceDerivation();
- std::optional priority;
+ std::optional priority;
if (attr->maybeGetAttr(state->sOutputSpecified)) {
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
if (auto aPriority = aMeta->maybeGetAttr("priority"))
- priority = aPriority->getInt();
+ priority = aPriority->getInt().value;
}
return {{
diff --git a/src/libcmd/installable-flake.hh b/src/libcmd/installable-flake.hh
index 8e0a232ef..212403dd4 100644
--- a/src/libcmd/installable-flake.hh
+++ b/src/libcmd/installable-flake.hh
@@ -26,7 +26,7 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue
Flake flake;
ExtraPathInfoFlake(Value && v, Flake && f)
- : ExtraPathInfoValue(std::move(v)), flake(f)
+ : ExtraPathInfoValue(std::move(v)), flake(std::move(f))
{ }
};
diff --git a/src/libcmd/installable-value.hh b/src/libcmd/installable-value.hh
index 798cb5e1a..4b6dbd306 100644
--- a/src/libcmd/installable-value.hh
+++ b/src/libcmd/installable-value.hh
@@ -40,7 +40,7 @@ struct ExtraPathInfoValue : ExtraPathInfo
/**
* An optional priority for use with "build envs". See Package
*/
- std::optional priority;
+ std::optional]