aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--configure.ac51
-rw-r--r--doc/manual/local.mk11
-rw-r--r--doc/manual/src/installation/prerequisites-source.md9
-rw-r--r--doc/manual/theme/highlight.js (renamed from doc/manual/highlight.pack.js)0
-rw-r--r--flake.lock6
-rw-r--r--mk/libraries.mk4
-rw-r--r--mk/programs.mk4
-rwxr-xr-xscripts/create-darwin-volume.sh4
-rw-r--r--scripts/install-darwin-multi-user.sh4
-rw-r--r--scripts/install-multi-user.sh7
-rw-r--r--src/libcmd/installables.cc2
-rw-r--r--src/libcmd/local.mk4
-rw-r--r--src/libexpr/attr-set.hh8
-rw-r--r--src/libexpr/eval.cc24
-rw-r--r--src/libexpr/eval.hh4
-rw-r--r--src/libexpr/flake/config.cc2
-rw-r--r--src/libexpr/flake/flake.cc88
-rw-r--r--src/libexpr/flake/flake.hh1
-rw-r--r--src/libexpr/flake/lockfile.cc21
-rw-r--r--src/libexpr/local.mk4
-rw-r--r--src/libexpr/primops.cc17
-rw-r--r--src/libexpr/value-to-xml.cc2
-rw-r--r--src/libfetchers/fetchers.hh3
-rw-r--r--src/libfetchers/local.mk2
-rw-r--r--src/libfetchers/path.cc18
-rw-r--r--src/libmain/local.mk4
-rw-r--r--src/libstore/binary-cache-store.cc11
-rw-r--r--src/libstore/build/goal.cc13
-rw-r--r--src/libstore/build/goal.hh2
-rw-r--r--src/libstore/local.mk4
-rw-r--r--src/libstore/references.cc8
-rw-r--r--src/libutil/compression.cc2
-rw-r--r--src/libutil/local.mk2
-rw-r--r--src/libutil/logging.cc2
-rw-r--r--src/libutil/ref.hh43
-rw-r--r--src/libutil/util.cc22
-rwxr-xr-xsrc/nix-build/nix-build.cc3
-rw-r--r--src/nix-env/user-env.cc4
-rw-r--r--src/nix/bundle.cc2
-rw-r--r--src/nix/develop.cc2
-rw-r--r--src/nix/run.cc2
-rw-r--r--tests/flakes.sh95
43 files changed, 352 insertions, 172 deletions
diff --git a/.gitignore b/.gitignore
index 1affd733d..86ffe9304 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,9 +57,6 @@ perl/Makefile.config
/src/nix-prefetch-url/nix-prefetch-url
-# /src/nix-daemon/
-/src/nix-daemon/nix-daemon
-
/src/nix-collect-garbage/nix-collect-garbage
# /src/nix-channel/
diff --git a/configure.ac b/configure.ac
index 6e563eec3..2841a87c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,14 +32,6 @@ AC_ARG_WITH(system, AS_HELP_STRING([--with-system=SYSTEM],[Platform identifier (
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
esac])
-sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
-
-case $sys_name in
- cygwin*)
- sys_name=cygwin
- ;;
-esac
-
AC_MSG_RESULT($system)
AC_SUBST(system)
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier ('cpu-os')])
@@ -63,10 +55,12 @@ AC_SYS_LARGEFILE
# Solaris-specific stuff.
AC_STRUCT_DIRENT_D_TYPE
-if test "$sys_name" = sunos; then
+case "$host_os" in
+ solaris*)
# Solaris requires -lsocket -lnsl for network functions
LDFLAGS="-lsocket -lnsl $LDFLAGS"
-fi
+ ;;
+esac
# Check for pubsetbuf.
@@ -210,21 +204,24 @@ AC_SUBST(HAVE_LIBCPUID, [$have_libcpuid])
# Look for libseccomp, required for Linux sandboxing.
-if test "$sys_name" = linux; then
- AC_ARG_ENABLE([seccomp-sandboxing],
- AS_HELP_STRING([--disable-seccomp-sandboxing],[Don't build support for seccomp sandboxing (only recommended if your arch doesn't support libseccomp yet!)
- ]))
- if test "x$enable_seccomp_sandboxing" != "xno"; then
- PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
- [CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
- have_seccomp=1
- AC_DEFINE([HAVE_SECCOMP], [1], [Whether seccomp is available and should be used for sandboxing.])
- else
+case "$host_os" in
+ linux*)
+ AC_ARG_ENABLE([seccomp-sandboxing],
+ AS_HELP_STRING([--disable-seccomp-sandboxing],[Don't build support for seccomp sandboxing (only recommended if your arch doesn't support libseccomp yet!)
+ ]))
+ if test "x$enable_seccomp_sandboxing" != "xno"; then
+ PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
+ [CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
+ have_seccomp=1
+ AC_DEFINE([HAVE_SECCOMP], [1], [Whether seccomp is available and should be used for sandboxing.])
+ else
+ have_seccomp=
+ fi
+ ;;
+ *)
have_seccomp=
- fi
-else
- have_seccomp=
-fi
+ ;;
+esac
AC_SUBST(HAVE_SECCOMP, [$have_seccomp])
@@ -274,9 +271,11 @@ AC_CHECK_FUNCS([strsignal posix_fallocate sysconf])
# This is needed if bzip2 is a static library, and the Nix libraries
# are dynamic.
-if test "$(uname)" = "Darwin"; then
+case "${host_os}" in
+ darwin*)
LDFLAGS="-all_load $LDFLAGS"
-fi
+ ;;
+esac
AC_ARG_WITH(sandbox-shell, AS_HELP_STRING([--with-sandbox-shell=PATH],[path of a statically-linked shell to use as /bin/sh in sandboxes]),
diff --git a/doc/manual/local.mk b/doc/manual/local.mk
index dd1d5f0fa..ca9af9c4a 100644
--- a/doc/manual/local.mk
+++ b/doc/manual/local.mk
@@ -78,24 +78,23 @@ man: doc/manual/generated/man1/nix3-manpages
all: doc/manual/generated/man1/nix3-manpages
$(mandir)/man1/nix3-manpages: doc/manual/generated/man1/nix3-manpages
- @mkdir -p $$(dirname $@)
- $(trace-install) install -m 0644 $$(dirname $<)/* $$(dirname $@)
+ @mkdir -p $(DESTDIR)$$(dirname $@)
+ $(trace-install) install -m 0644 $$(dirname $<)/* $(DESTDIR)$$(dirname $@)
doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli
- @mkdir -p $$(dirname $@)
+ @mkdir -p $(DESTDIR)$$(dirname $@)
$(trace-gen) for i in doc/manual/src/command-ref/new-cli/*.md; do \
name=$$(basename $$i .md); \
tmpFile=$$(mktemp); \
if [[ $$name = SUMMARY ]]; then continue; fi; \
printf "Title: %s\n\n" "$$name" > $$tmpFile; \
cat $$i >> $$tmpFile; \
- lowdown -sT man -M section=1 $$tmpFile -o $$(dirname $@)/$$name.1; \
+ lowdown -sT man -M section=1 $$tmpFile -o $(DESTDIR)$$(dirname $@)/$$name.1; \
rm $$tmpFile; \
done
touch $@
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/command-ref/conf-file.md $(d)/src/expressions/builtins.md
- $(trace-gen) RUST_LOG=warn mdbook build doc/manual -d $(docdir)/manual
- @cp doc/manual/highlight.pack.js $(docdir)/manual/highlight.js
+ $(trace-gen) RUST_LOG=warn mdbook build doc/manual -d $(DESTDIR)$(docdir)/manual
endif
diff --git a/doc/manual/src/installation/prerequisites-source.md b/doc/manual/src/installation/prerequisites-source.md
index 6825af707..40cb79627 100644
--- a/doc/manual/src/installation/prerequisites-source.md
+++ b/doc/manual/src/installation/prerequisites-source.md
@@ -26,15 +26,6 @@
available for download from the official repository
<https://github.com/google/brotli>.
- - The bzip2 compressor program and the `libbz2` library. Thus you must
- have bzip2 installed, including development headers and libraries.
- If your distribution does not provide these, you can obtain bzip2
- from
- <https://sourceware.org/bzip2/>.
-
- - `liblzma`, which is provided by XZ Utils. If your distribution does
- not provide this, you can get it from <https://tukaani.org/xz/>.
-
- cURL and its library. If your distribution does not provide it, you
can get it from <https://curl.haxx.se/>.
diff --git a/doc/manual/highlight.pack.js b/doc/manual/theme/highlight.js
index fba8b4a5a..fba8b4a5a 100644
--- a/doc/manual/highlight.pack.js
+++ b/doc/manual/theme/highlight.js
diff --git a/flake.lock b/flake.lock
index 5fc969d7b..8c0d5a2d2 100644
--- a/flake.lock
+++ b/flake.lock
@@ -19,11 +19,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1624862269,
- "narHash": "sha256-JFcsh2+7QtfKdJFoPibLFPLgIW6Ycnv8Bts9a7RYme0=",
+ "lastModified": 1628689438,
+ "narHash": "sha256-YMINW6YmubHZVdliGsAJpnnMYXRrvppv59LgwtnyYhs=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "f77036342e2b690c61c97202bf48f2ce13acc022",
+ "rev": "f6551e1efa261568c82b76c3a582b2c2ceb1f53f",
"type": "github"
},
"original": {
diff --git a/mk/libraries.mk b/mk/libraries.mk
index 07bd54dab..fd4d4ee72 100644
--- a/mk/libraries.mk
+++ b/mk/libraries.mk
@@ -91,7 +91,7 @@ define build-library
$(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT)
$$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/
- $$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED)
+ $$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED) $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED)
ifndef HOST_DARWIN
$(1)_LDFLAGS_USE += -Wl,-rpath,$$(abspath $$(_d))
@@ -105,7 +105,7 @@ define build-library
$$(eval $$(call create-dir, $$($(1)_INSTALL_DIR)))
$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/
- $$(trace-ld) $(CXX) -o $$@ -shared $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
+ $$(trace-ld) $(CXX) -o $$@ -shared $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED)
$(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))
ifndef HOST_DARWIN
diff --git a/mk/programs.mk b/mk/programs.mk
index d0cf5baf0..70b09f0dd 100644
--- a/mk/programs.mk
+++ b/mk/programs.mk
@@ -32,7 +32,7 @@ define build-program
$$(eval $$(call create-dir, $$(_d)))
$$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/
- $$(trace-ld) $(CXX) -o $$@ $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE))
+ $$(trace-ld) $(CXX) -o $$@ $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS)
$(1)_INSTALL_DIR ?= $$(bindir)
@@ -49,7 +49,7 @@ define build-program
_libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH))
$(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/
- $$(trace-ld) $(CXX) -o $$@ $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
+ $$(trace-ld) $(CXX) -o $$@ $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS)
else
diff --git a/scripts/create-darwin-volume.sh b/scripts/create-darwin-volume.sh
index 8aff03199..1a17b3439 100755
--- a/scripts/create-darwin-volume.sh
+++ b/scripts/create-darwin-volume.sh
@@ -759,6 +759,10 @@ setup_volume() {
await_volume
+ if [ "$(/usr/sbin/diskutil info -plist "$NIX_ROOT" | xmllint --xpath "(/plist/dict/key[text()='GlobalPermissionsEnabled'])/following-sibling::*[1]" -)" = "<false/>" ]; then
+ sudo /usr/sbin/diskutil enableOwnership "$NIX_ROOT"
+ fi
+
# TODO: below is a vague kludge for now; I just don't know
# what if any safe action there is to take here. Also, the
# reminder isn't very helpful.
diff --git a/scripts/install-darwin-multi-user.sh b/scripts/install-darwin-multi-user.sh
index f8d6c5e8f..a5166de64 100644
--- a/scripts/install-darwin-multi-user.sh
+++ b/scripts/install-darwin-multi-user.sh
@@ -206,4 +206,8 @@ poly_prepare_to_install() {
EOF
setup_darwin_volume
fi
+
+ if [ "$(diskutil info -plist /nix | xmllint --xpath "(/plist/dict/key[text()='GlobalPermissionsEnabled'])/following-sibling::*[1]" -)" = "<false/>" ]; then
+ failure "This script needs a /nix volume with global permissions! This may require running sudo diskutil enableOwnership /nix."
+ fi
}
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index e1046c19c..513127a62 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -33,7 +33,7 @@ NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d"
readonly NIX_ROOT="/nix"
readonly NIX_EXTRA_CONF=${NIX_EXTRA_CONF:-}
-readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshenv" "/etc/bash.bashrc" "/etc/zsh/zshenv")
+readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc")
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
@@ -701,7 +701,10 @@ install_from_extracted_nix() {
cd "$EXTRACTED_NIX_PATH"
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
- rsync -rlpt --chmod=-w ./store/* "$NIX_ROOT/store/"
+ cp -RLp ./store/* "$NIX_ROOT/store/"
+
+ _sudo "to make the new store non-writable at $NIX_ROOT/store" \
+ chmod -R ugo-w "$NIX_ROOT/store/"
if [ -d "$NIX_INSTALLED_NIX" ]; then
echo " Alright! We have our first nix at $NIX_INSTALLED_NIX"
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index e3ce564b0..68e0469c3 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -729,7 +729,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
if (!realisation)
throw Error(
"cannot operate on an output of unbuilt "
- "content-addresed derivation '%s'",
+ "content-addressed derivation '%s'",
outputId.to_string());
outputs.insert_or_assign(
output, realisation->outPath);
diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk
index 431d8ec06..8b0662753 100644
--- a/src/libcmd/local.mk
+++ b/src/libcmd/local.mk
@@ -8,8 +8,8 @@ libcmd_SOURCES := $(wildcard $(d)/*.cc)
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers
-libcmd_LDFLAGS = -llowdown -pthread
+libcmd_LDFLAGS += -llowdown -pthread
libcmd_LIBS = libstore libutil libexpr libmain libfetchers
-$(eval $(call install-file-in, $(d)/nix-cmd.pc, $(prefix)/lib/pkgconfig, 0644))
+$(eval $(call install-file-in, $(d)/nix-cmd.pc, $(libdir)/pkgconfig, 0644))
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index 1da8d91df..7d6ffc9f3 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -17,8 +17,8 @@ struct Attr
{
Symbol name;
Value * value;
- Pos * pos;
- Attr(Symbol name, Value * value, Pos * pos = &noPos)
+ ptr<Pos> pos;
+ Attr(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
: name(name), value(value), pos(pos) { };
Attr() : pos(&noPos) { };
bool operator < (const Attr & a) const
@@ -35,13 +35,13 @@ class Bindings
{
public:
typedef uint32_t size_t;
- Pos *pos;
+ ptr<Pos> pos;
private:
size_t size_, capacity_;
Attr attrs[0];
- Bindings(size_t capacity) : size_(0), capacity_(capacity) { }
+ Bindings(size_t capacity) : pos(&noPos), size_(0), capacity_(capacity) { }
Bindings(const Bindings & bindings) = delete;
public:
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 327f7e974..361c52151 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -770,7 +770,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
- if (countCalls && j->pos) attrSelects[*j->pos]++;
+ if (countCalls) attrSelects[*j->pos]++;
return j->value;
}
if (!env->prevWith)
@@ -825,9 +825,9 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
}
-void EvalState::mkPos(Value & v, Pos * pos)
+void EvalState::mkPos(Value & v, ptr<Pos> pos)
{
- if (pos && pos->file.set()) {
+ if (pos->file.set()) {
mkAttrs(v, 3);
mkString(*allocAttr(v, sFile), pos->file);
mkInt(*allocAttr(v, sLine), pos->line);
@@ -1027,7 +1027,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
} else
vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
env2.values[displ++] = vAttr;
- v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos));
+ v.attrs->push_back(Attr(i.first, vAttr, ptr(&i.second.pos)));
}
/* If the rec contains an attribute called `__overrides', then
@@ -1059,7 +1059,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else
for (auto & i : attrs)
- v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), &i.second.pos));
+ v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), ptr(&i.second.pos)));
/* Dynamic attrs apply *after* rec and __overrides. */
for (auto & i : dynamicAttrs) {
@@ -1076,11 +1076,11 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
i.valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */
- v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), &i.pos));
+ v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), ptr(&i.pos)));
v.attrs->sort(); // FIXME: inefficient
}
- v.attrs->pos = &pos;
+ v.attrs->pos = ptr(&pos);
}
@@ -1138,7 +1138,7 @@ static string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPa
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
{
Value vTmp;
- Pos * pos2 = 0;
+ ptr<Pos> pos2(&noPos);
Value * vAttrs = &vTmp;
e->eval(state, env, vTmp);
@@ -1164,13 +1164,13 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
vAttrs = j->value;
pos2 = j->pos;
- if (state.countCalls && pos2) state.attrSelects[*pos2]++;
+ if (state.countCalls) state.attrSelects[*pos2]++;
}
- state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) );
+ state.forceValue(*vAttrs, (*pos2 != noPos ? *pos2 : this->pos ) );
} catch (Error & e) {
- if (pos2 && pos2->file != state.sDerivationNix)
+ if (*pos2 != noPos && pos2->file != state.sDerivationNix)
addErrorTrace(e, *pos2, "while evaluating the attribute '%1%'",
showAttrPath(state, env, attrPath));
throw;
@@ -1616,7 +1616,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
void ExprPos::eval(EvalState & state, Env & env, Value & v)
{
- state.mkPos(v, &pos);
+ state.mkPos(v, ptr(&pos));
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 6f3474854..0fced795d 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -100,6 +100,8 @@ public:
/* Store used to build stuff. */
const ref<Store> buildStore;
+ RootValue vCallFlake = nullptr;
+ RootValue vImportedDrvToDerivation = nullptr;
private:
SrcToStore srcToStore;
@@ -308,7 +310,7 @@ public:
void mkList(Value & v, size_t length);
void mkAttrs(Value & v, size_t capacity);
void mkThunk_(Value & v, Expr * expr);
- void mkPos(Value & v, Pos * pos);
+ void mkPos(Value & v, ptr<Pos> pos);
void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos);
diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc
index c8a5a319f..41b6f78ed 100644
--- a/src/libexpr/flake/config.cc
+++ b/src/libexpr/flake/config.cc
@@ -29,7 +29,7 @@ static void writeTrustedList(const TrustedList & trustedList)
void ConfigFile::apply()
{
- std::set<std::string> whitelist{"bash-prompt", "bash-prompt-suffix"};
+ std::set<std::string> whitelist{"bash-prompt", "bash-prompt-suffix", "flake-registry"};
for (auto & [name, value] : settings) {
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index e7013b241..ee345bdbc 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -325,25 +325,38 @@ LockedFlake lockFlake(
std::vector<FlakeRef> parents;
+ struct LockParent {
+ /* The path to this parent. */
+ InputPath path;
+
+ /* Whether we are currently inside a top-level lockfile
+ (inputs absolute) or subordinate lockfile (inputs
+ relative). */
+ bool absolute;
+ };
+
std::function<void(
const FlakeInputs & flakeInputs,
std::shared_ptr<Node> node,
const InputPath & inputPathPrefix,
- std::shared_ptr<const Node> oldNode)>
+ std::shared_ptr<const Node> oldNode,
+ const LockParent & parent,
+ const Path & parentPath)>
computeLocks;
computeLocks = [&](
const FlakeInputs & flakeInputs,
std::shared_ptr<Node> node,
const InputPath & inputPathPrefix,
- std::shared_ptr<const Node> oldNode)
+ std::shared_ptr<const Node> oldNode,
+ const LockParent & parent,
+ const Path & parentPath)
{
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
/* Get the overrides (i.e. attributes of the form
'inputs.nixops.inputs.nixpkgs.url = ...'). */
- // FIXME: check this
- for (auto & [id, input] : flake.inputs) {
+ for (auto & [id, input] : flakeInputs) {
for (auto & [idOverride, inputOverride] : input.overrides) {
auto inputPath(inputPathPrefix);
inputPath.push_back(id);
@@ -379,15 +392,19 @@ LockedFlake lockFlake(
path we haven't processed yet. */
if (input.follows) {
InputPath target;
- if (hasOverride || input.absolute)
- /* 'follows' from an override is relative to the
- root of the graph. */
+
+ if (parent.absolute && !hasOverride) {
target = *input.follows;
- else {
- /* Otherwise, it's relative to the current flake. */
- target = inputPathPrefix;
+ } else {
+ if (hasOverride) {
+ target = inputPathPrefix;
+ target.pop_back();
+ } else
+ target = parent.path;
+
for (auto & i : *input.follows) target.push_back(i);
}
+
debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
node->inputs.insert_or_assign(id, target);
continue;
@@ -433,7 +450,7 @@ LockedFlake lockFlake(
if (hasChildUpdate) {
auto inputFlake = getFlake(
state, oldLock->lockedRef, false, flakeCache);
- computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
+ computeLocks(inputFlake.inputs, childNode, inputPath, oldLock, parent, parentPath);
} else {
/* No need to fetch this flake, we can be
lazy. However there may be new overrides on the
@@ -450,12 +467,11 @@ LockedFlake lockFlake(
} else if (auto follows = std::get_if<1>(&i.second)) {
fakeInputs.emplace(i.first, FlakeInput {
.follows = *follows,
- .absolute = true
});
}
}
- computeLocks(fakeInputs, childNode, inputPath, oldLock);
+ computeLocks(fakeInputs, childNode, inputPath, oldLock, parent, parentPath);
}
} else {
@@ -467,7 +483,17 @@ LockedFlake lockFlake(
throw Error("cannot update flake input '%s' in pure mode", inputPathS);
if (input.isFlake) {
- auto inputFlake = getFlake(state, *input.ref, useRegistries, flakeCache);
+ Path localPath = parentPath;
+ FlakeRef localRef = *input.ref;
+
+ // If this input is a path, recurse it down.
+ // This allows us to resolve path inputs relative to the current flake.
+ if (localRef.input.getType() == "path") {
+ localRef.input.parent = parentPath;
+ localPath = canonPath(parentPath + "/" + *input.ref->input.getSourcePath());
+ }
+
+ auto inputFlake = getFlake(state, localRef, useRegistries, flakeCache);
/* Note: in case of an --override-input, we use
the *original* ref (input2.ref) for the
@@ -488,6 +514,13 @@ LockedFlake lockFlake(
parents.push_back(*input.ref);
Finally cleanup([&]() { parents.pop_back(); });
+ // Follows paths from existing inputs in the top-level lockfile are absolute,
+ // whereas paths in subordinate lockfiles are relative to those lockfiles.
+ LockParent newParent {
+ .path = inputPath,
+ .absolute = oldLock ? true : false
+ };
+
/* Recursively process the inputs of this
flake. Also, unless we already have this flake
in the top-level lock file, use this flake's
@@ -497,7 +530,8 @@ LockedFlake lockFlake(
oldLock
? std::dynamic_pointer_cast<const Node>(oldLock)
: LockFile::read(
- inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root);
+ inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root,
+ newParent, localPath);
}
else {
@@ -515,9 +549,17 @@ LockedFlake lockFlake(
}
};
+ LockParent parent {
+ .path = {},
+ .absolute = true
+ };
+
+ // Bring in the current ref for relative path resolution if we have it
+ auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir);
+
computeLocks(
flake.inputs, newLockFile.root, {},
- lockFlags.recreateLockFile ? nullptr : oldLockFile.root);
+ lockFlags.recreateLockFile ? nullptr : oldLockFile.root, parent, parentPath);
for (auto & i : lockFlags.inputOverrides)
if (!overridesUsed.count(i.first))
@@ -567,8 +609,8 @@ LockedFlake lockFlake(
topRef.input.markChangedFile(
(topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock",
lockFlags.commitLockFile
- ? std::optional<std::string>(fmt("%s: %s\n\nFlake input changes:\n\n%s",
- relPath, lockFileExists ? "Update" : "Add", diff))
+ ? std::optional<std::string>(fmt("%s: %s\n\nFlake lock file changes:\n\n%s",
+ relPath, lockFileExists ? "Update" : "Add", filterANSIEscapes(diff, true)))
: std::nullopt);
/* Rewriting the lockfile changed the top-level
@@ -621,16 +663,14 @@ void callFlake(EvalState & state,
mkString(*vRootSubdir, lockedFlake.flake.lockedRef.subdir);
- static RootValue vCallFlake = nullptr;
-
- if (!vCallFlake) {
- vCallFlake = allocRootValue(state.allocValue());
+ if (!state.vCallFlake) {
+ state.vCallFlake = allocRootValue(state.allocValue());
state.eval(state.parseExprFromString(
#include "call-flake.nix.gen.hh"
- , "/"), **vCallFlake);
+ , "/"), **state.vCallFlake);
}
- state.callFunction(**vCallFlake, *vLocks, *vTmp1, noPos);
+ state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos);
state.callFunction(*vTmp1, *vRootSrc, *vTmp2, noPos);
state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos);
}
diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh
index 15fd394f8..d46da9d68 100644
--- a/src/libexpr/flake/flake.hh
+++ b/src/libexpr/flake/flake.hh
@@ -43,7 +43,6 @@ struct FlakeInput
std::optional<FlakeRef> ref;
bool isFlake = true; // true = process flake to get outputs, false = (fetched) static source path
std::optional<InputPath> follows;
- bool absolute = false; // whether 'follows' is relative to the flake root
FlakeInputs overrides;
};
diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc
index 6089d1363..fda340789 100644
--- a/src/libexpr/flake/lockfile.cc
+++ b/src/libexpr/flake/lockfile.cc
@@ -2,6 +2,8 @@
#include "store-api.hh"
#include "url-parts.hh"
+#include <iomanip>
+
#include <nlohmann/json.hpp>
namespace nix::flake {
@@ -268,10 +270,20 @@ std::map<InputPath, Node::Edge> LockFile::getAllInputs() const
return res;
}
+static std::string describe(const FlakeRef & flakeRef)
+{
+ auto s = fmt("'%s'", flakeRef.to_string());
+
+ if (auto lastModified = flakeRef.input.getLastModified())
+ s += fmt(" (%s)", std::put_time(std::gmtime(&*lastModified), "%Y-%m-%d"));
+
+ return s;
+}
+
std::ostream & operator <<(std::ostream & stream, const Node::Edge & edge)
{
if (auto node = std::get_if<0>(&edge))
- stream << "'" << (*node)->lockedRef << "'";
+ stream << describe((*node)->lockedRef);
else if (auto follows = std::get_if<1>(&edge))
stream << fmt("follows '%s'", printInputPath(*follows));
return stream;
@@ -299,14 +311,15 @@ std::string LockFile::diff(const LockFile & oldLocks, const LockFile & newLocks)
while (i != oldFlat.end() || j != newFlat.end()) {
if (j != newFlat.end() && (i == oldFlat.end() || i->first > j->first)) {
- res += fmt("* Added '%s': %s\n", printInputPath(j->first), j->second);
+ res += fmt("• " ANSI_GREEN "Added input '%s':" ANSI_NORMAL "\n %s\n",
+ printInputPath(j->first), j->second);
++j;
} else if (i != oldFlat.end() && (j == newFlat.end() || i->first < j->first)) {
- res += fmt("* Removed '%s'\n", printInputPath(i->first));
+ res += fmt("• " ANSI_RED "Removed input '%s'" ANSI_NORMAL "\n", printInputPath(i->first));
++i;
} else {
if (!equals(i->second, j->second)) {
- res += fmt("* Updated '%s': %s -> %s\n",
+ res += fmt("• " ANSI_BOLD "Updated input '%s':" ANSI_NORMAL "\n %s\n → %s\n",
printInputPath(i->first),
i->second,
j->second);
diff --git a/src/libexpr/local.mk b/src/libexpr/local.mk
index 17b83aafd..016631647 100644
--- a/src/libexpr/local.mk
+++ b/src/libexpr/local.mk
@@ -15,7 +15,7 @@ libexpr_CXXFLAGS += -I src/libutil -I src/libstore -I src/libfetchers -I src/lib
libexpr_LIBS = libutil libstore libfetchers
-libexpr_LDFLAGS = -lboost_context -pthread
+libexpr_LDFLAGS += -lboost_context -pthread
ifdef HOST_LINUX
libexpr_LDFLAGS += -ldl
endif
@@ -35,7 +35,7 @@ $(d)/lexer-tab.cc $(d)/lexer-tab.hh: $(d)/lexer.l
clean-files += $(d)/parser-tab.cc $(d)/parser-tab.hh $(d)/lexer-tab.cc $(d)/lexer-tab.hh
-$(eval $(call install-file-in, $(d)/nix-expr.pc, $(prefix)/lib/pkgconfig, 0644))
+$(eval $(call install-file-in, $(d)/nix-expr.pc, $(libdir)/pkgconfig, 0644))
$(foreach i, $(wildcard src/libexpr/flake/*.hh), \
$(eval $(call install-file-in, $(i), $(includedir)/nix/flake, 0644)))
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 209a05d11..25d60e175 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -160,16 +160,15 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
}
w.attrs->sort();
- static RootValue fun;
- if (!fun) {
- fun = allocRootValue(state.allocValue());
+ if (!state.vImportedDrvToDerivation) {
+ state.vImportedDrvToDerivation = allocRootValue(state.allocValue());
state.eval(state.parseExprFromString(
#include "imported-drv-to-derivation.nix.gen.hh"
- , "/"), **fun);
+ , "/"), **state.vImportedDrvToDerivation);
}
- state.forceFunction(**fun, pos);
- mkApp(v, **fun, w);
+ state.forceFunction(**state.vImportedDrvToDerivation, pos);
+ mkApp(v, **state.vImportedDrvToDerivation, w);
state.forceAttrs(v, pos);
}
@@ -2109,7 +2108,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
pos
);
// !!! add to stack trace?
- if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
+ if (state.countCalls && *i->pos != noPos) state.attrSelects[*i->pos]++;
state.forceValue(*i->value, pos);
v = *i->value;
}
@@ -2369,7 +2368,7 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
for (auto & i : args[0]->lambda.fun->formals->formals) {
// !!! should optimise booleans (allocate only once)
Value * value = state.allocValue();
- v.attrs->push_back(Attr(i.name, value, &i.pos));
+ v.attrs->push_back(Attr(i.name, value, ptr(&i.pos)));
mkBool(*value, i.def);
}
v.attrs->sort();
@@ -3645,9 +3644,7 @@ void EvalState::createBaseEnv()
if (!evalSettings.pureEval) {
mkInt(v, time(0));
addConstant("__currentTime", v);
- }
- if (!evalSettings.pureEval) {
mkString(v, settings.thisSystem.get());
addConstant("__currentSystem", v);
}
diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc
index 7464455d8..2ddc5f751 100644
--- a/src/libexpr/value-to-xml.cc
+++ b/src/libexpr/value-to-xml.cc
@@ -42,7 +42,7 @@ static void showAttrs(EvalState & state, bool strict, bool location,
XMLAttrs xmlAttrs;
xmlAttrs["name"] = i;
- if (location && a.pos != &noPos) posToXML(xmlAttrs, *a.pos);
+ if (location && a.pos != ptr(&noPos)) posToXML(xmlAttrs, *a.pos);
XMLOpenElement _(doc, "attr", xmlAttrs);
printValueAsXML(state, strict, location,
diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh
index c839cf23b..c43b047a7 100644
--- a/src/libfetchers/fetchers.hh
+++ b/src/libfetchers/fetchers.hh
@@ -38,6 +38,9 @@ struct Input
bool immutable = false;
bool direct = true;
+ /* path of the parent of this input, used for relative path resolution */
+ std::optional<Path> parent;
+
public:
static Input fromURL(const std::string & url);
diff --git a/src/libfetchers/local.mk b/src/libfetchers/local.mk
index bbef03afe..2e8869d83 100644
--- a/src/libfetchers/local.mk
+++ b/src/libfetchers/local.mk
@@ -8,6 +8,6 @@ libfetchers_SOURCES := $(wildcard $(d)/*.cc)
libfetchers_CXXFLAGS += -I src/libutil -I src/libstore
-libfetchers_LDFLAGS = -pthread
+libfetchers_LDFLAGS += -pthread
libfetchers_LIBS = libutil libstore
diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc
index d1003de57..b6fcdac9e 100644
--- a/src/libfetchers/path.cc
+++ b/src/libfetchers/path.cc
@@ -82,18 +82,30 @@ struct PathInputScheme : InputScheme
std::pair<Tree, Input> fetch(ref<Store> store, const Input & input) override
{
+ std::string absPath;
auto path = getStrAttr(input.attrs, "path");
- // FIXME: check whether access to 'path' is allowed.
+ if (path[0] != '/' && input.parent) {
+ auto parent = canonPath(*input.parent);
+
+ // the path isn't relative, prefix it
+ absPath = canonPath(parent + "/" + path);
- auto storePath = store->maybeParseStorePath(path);
+ // for security, ensure that if the parent is a store path, it's inside it
+ if (!parent.rfind(store->storeDir, 0) && absPath.rfind(store->storeDir, 0))
+ throw BadStorePath("relative path '%s' points outside of its parent's store path %s, this is a security violation", path, parent);
+ } else
+ absPath = path;
+
+ // FIXME: check whether access to 'path' is allowed.
+ auto storePath = store->maybeParseStorePath(absPath);
if (storePath)
store->addTempRoot(*storePath);
if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath))
// FIXME: try to substitute storePath.
- storePath = store->addToStore("source", path);
+ storePath = store->addToStore("source", absPath);
return {
Tree(store->toRealPath(*storePath), std::move(*storePath)),
diff --git a/src/libmain/local.mk b/src/libmain/local.mk
index a8eed6c65..99da95e27 100644
--- a/src/libmain/local.mk
+++ b/src/libmain/local.mk
@@ -8,10 +8,10 @@ libmain_SOURCES := $(wildcard $(d)/*.cc)
libmain_CXXFLAGS += -I src/libutil -I src/libstore
-libmain_LDFLAGS = $(OPENSSL_LIBS)
+libmain_LDFLAGS += $(OPENSSL_LIBS)
libmain_LIBS = libstore libutil
libmain_ALLOW_UNDEFINED = 1
-$(eval $(call install-file-in, $(d)/nix-main.pc, $(prefix)/lib/pkgconfig, 0644))
+$(eval $(call install-file-in, $(d)/nix-main.pc, $(libdir)/pkgconfig, 0644))
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index df401e6f4..74eb0a9ab 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -130,17 +130,6 @@ AutoCloseFD openFile(const Path & path)
return fd;
}
-struct FileSource : FdSource
-{
- AutoCloseFD fd2;
-
- FileSource(const Path & path)
- : fd2(openFile(path))
- {
- fd = fd2.get();
- }
-};
-
ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs,
std::function<ValidPathInfo(HashResult)> mkInfo)
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index 9de40bdf2..7c985128b 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -13,11 +13,9 @@ bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const {
void addToWeakGoals(WeakGoals & goals, GoalPtr p)
{
- // FIXME: necessary?
- // FIXME: O(n)
- for (auto & i : goals)
- if (i.lock() == p) return;
- goals.push_back(p);
+ if (goals.find(p) != goals.end())
+ return;
+ goals.insert(p);
}
@@ -46,10 +44,7 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
/* If we failed and keepGoing is not set, we remove all
remaining waitees. */
for (auto & goal : waitees) {
- WeakGoals waiters2;
- for (auto & j : goal->waiters)
- if (j.lock() != shared_from_this()) waiters2.push_back(j);
- goal->waiters = waiters2;
+ goal->waiters.extract(shared_from_this());
}
waitees.clear();
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index e6bf628cb..192e416d2 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -19,7 +19,7 @@ struct CompareGoalPtrs {
/* Set of goals. */
typedef set<GoalPtr, CompareGoalPtrs> Goals;
-typedef list<WeakGoalPtr> WeakGoals;
+typedef set<WeakGoalPtr, std::owner_less<WeakGoalPtr>> WeakGoals;
/* A map of paths to goals (and the other way around). */
typedef std::map<StorePath, WeakGoalPtr> WeakGoalMap;
diff --git a/src/libstore/local.mk b/src/libstore/local.mk
index 2fc334a82..b992bcbc0 100644
--- a/src/libstore/local.mk
+++ b/src/libstore/local.mk
@@ -8,7 +8,7 @@ libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc $(d)/build/*.cc)
libstore_LIBS = libutil
-libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
+libstore_LDFLAGS += $(SQLITE3_LIBS) $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
ifdef HOST_LINUX
libstore_LDFLAGS += -ldl
endif
@@ -60,7 +60,7 @@ $(d)/build.cc:
clean-files += $(d)/schema.sql.gen.hh $(d)/ca-specific-schema.sql.gen.hh
-$(eval $(call install-file-in, $(d)/nix-store.pc, $(prefix)/lib/pkgconfig, 0644))
+$(eval $(call install-file-in, $(d)/nix-store.pc, $(libdir)/pkgconfig, 0644))
$(foreach i, $(wildcard src/libstore/builtins/*.hh), \
$(eval $(call install-file-in, $(i), $(includedir)/nix/builtins, 0644)))
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 39c4970c6..3a07c1411 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -5,6 +5,7 @@
#include <map>
#include <cstdlib>
+#include <mutex>
namespace nix {
@@ -16,14 +17,13 @@ static unsigned int refLength = 32; /* characters */
static void search(const unsigned char * s, size_t len,
StringSet & hashes, StringSet & seen)
{
- static bool initialised = false;
+ static std::once_flag initialised;
static bool isBase32[256];
- if (!initialised) {
+ std::call_once(initialised, [](){
for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false;
for (unsigned int i = 0; i < base32Chars.size(); ++i)
isBase32[(unsigned char) base32Chars[i]] = true;
- initialised = true;
- }
+ });
for (size_t i = 0; i + refLength <= len; ) {
int j;
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc
index 7e725cae1..d26f68fde 100644
--- a/src/libutil/compression.cc
+++ b/src/libutil/compression.cc
@@ -12,8 +12,6 @@
#include <brotli/decode.h>
#include <brotli/encode.h>
-#include <zlib.h>
-
#include <iostream>
namespace nix {
diff --git a/src/libutil/local.mk b/src/libutil/local.mk
index 3a6415ee3..f880c0fc5 100644
--- a/src/libutil/local.mk
+++ b/src/libutil/local.mk
@@ -6,7 +6,7 @@ libutil_DIR := $(d)
libutil_SOURCES := $(wildcard $(d)/*.cc)
-libutil_LDFLAGS = -pthread $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) $(LIBARCHIVE_LIBS) $(BOOST_LDFLAGS) -lboost_context
+libutil_LDFLAGS += -pthread $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) $(LIBARCHIVE_LIBS) $(BOOST_LDFLAGS) -lboost_context
ifeq ($(HAVE_LIBCPUID), 1)
libutil_LDFLAGS += -lcpuid
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index 6b9b850ca..7d6090e0a 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -163,7 +163,7 @@ struct JSONLogger : Logger {
void write(const nlohmann::json & json)
{
- prevLogger.log(lvlError, "@nix " + json.dump());
+ prevLogger.log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
}
void log(Verbosity lvl, const FormatOrString & fs) override
diff --git a/src/libutil/ref.hh b/src/libutil/ref.hh
index 2549ef496..d6bf53bb8 100644
--- a/src/libutil/ref.hh
+++ b/src/libutil/ref.hh
@@ -99,4 +99,47 @@ make_ref(Args&&... args)
return ref<T>(p);
}
+
+/* A non-nullable pointer.
+ This is similar to a C++ "& reference", but mutable.
+ This is similar to ref<T> but backed by a regular pointer instead of a smart pointer.
+ */
+template<typename T>
+class ptr {
+private:
+ T * p;
+
+public:
+ ptr<T>(const ptr<T> & r)
+ : p(r.p)
+ { }
+
+ explicit ptr<T>(T * p)
+ : p(p)
+ {
+ if (!p)
+ throw std::invalid_argument("null pointer cast to ptr");
+ }
+
+ T* operator ->() const
+ {
+ return &*p;
+ }
+
+ T& operator *() const
+ {
+ return *p;
+ }
+
+ bool operator == (const ptr<T> & other) const
+ {
+ return p == other.p;
+ }
+
+ bool operator != (const ptr<T> & other) const
+ {
+ return p != other.p;
+ }
+};
+
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index d876315c8..d1270cd31 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -6,14 +6,15 @@
#include <cctype>
#include <cerrno>
+#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <climits>
+#include <future>
#include <iostream>
+#include <mutex>
#include <sstream>
#include <thread>
-#include <future>
#include <fcntl.h>
#include <grp.h>
@@ -1447,7 +1448,7 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in
static char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
+static std::array<char, 256> base64DecodeChars;
string base64Encode(std::string_view s)
{
@@ -1472,15 +1473,12 @@ string base64Encode(std::string_view s)
string base64Decode(std::string_view s)
{
- bool init = false;
- char decode[256];
- if (!init) {
- // FIXME: not thread-safe.
- memset(decode, -1, sizeof(decode));
+ static std::once_flag flag;
+ std::call_once(flag, [](){
+ base64DecodeChars = { (char)-1 };
for (int i = 0; i < 64; i++)
- decode[(int) base64Chars[i]] = i;
- init = true;
- }
+ base64DecodeChars[(int) base64Chars[i]] = i;
+ });
string res;
unsigned int d = 0, bits = 0;
@@ -1489,7 +1487,7 @@ string base64Decode(std::string_view s)
if (c == '=') break;
if (c == '\n') continue;
- char digit = decode[(unsigned char) c];
+ char digit = base64DecodeChars[(unsigned char) c];
if (digit == -1)
throw Error("invalid character in Base64 string: '%c'", c);
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 9e3538394..77594f046 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -489,6 +489,9 @@ static void main_nix_build(int argc, char * * argv)
"_nix_shell_clean_tmpdir; ") +
(pure ? "" : "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;") +
"%2%"
+ // always clear PATH.
+ // when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
+ "unset PATH;"
"dontAddDisableDepTrack=1;\n"
+ structuredAttrsRC +
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index 5ceb2ae67..1fd4bcbd3 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -131,9 +131,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.forceValue(topLevel);
PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
- auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context));
+ auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context));
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
- Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context);
+ Path topLevelOut = state.coerceToPath(*aOutPath.pos, *aOutPath.value, context);
/* Realise the resulting store expression. */
debug("building user environment");
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index cedb5704c..aca024bca 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -59,7 +59,7 @@ struct CmdBundle : InstallableCommand
Strings getDefaultFlakeAttrPathPrefixes() override
{
- Strings res{"apps." + settings.thisSystem.get() + ".", "packages"};
+ Strings res{"apps." + settings.thisSystem.get() + "."};
for (auto & s : SourceExprCommand::getDefaultFlakeAttrPathPrefixes())
res.push_back(s);
return res;
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 55023545d..c823f16c8 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -330,7 +330,7 @@ struct Common : InstallableCommand, MixProfile
Strings getDefaultFlakeAttrPathPrefixes() override
{
auto res = SourceExprCommand::getDefaultFlakeAttrPathPrefixes();
- res.emplace_front("devShells." + settings.thisSystem.get());
+ res.emplace_front("devShells." + settings.thisSystem.get() + ".");
return res;
}
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 7597b61f7..b01fdebaa 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -167,7 +167,7 @@ struct CmdRun : InstallableCommand
Strings getDefaultFlakeAttrPathPrefixes() override
{
- Strings res{"apps." + settings.thisSystem.get() + ".", "packages"};
+ Strings res{"apps." + settings.thisSystem.get() + "."};
for (auto & s : SourceExprCommand::getDefaultFlakeAttrPathPrefixes())
res.push_back(s);
return res;
diff --git a/tests/flakes.sh b/tests/flakes.sh
index 9e1b5b508..f5c7b6804 100644
--- a/tests/flakes.sh
+++ b/tests/flakes.sh
@@ -26,10 +26,15 @@ nonFlakeDir=$TEST_ROOT/nonFlake
flakeA=$TEST_ROOT/flakeA
flakeB=$TEST_ROOT/flakeB
flakeGitBare=$TEST_ROOT/flakeGitBare
+flakeFollowsA=$TEST_ROOT/follows/flakeA
+flakeFollowsB=$TEST_ROOT/follows/flakeA/flakeB
+flakeFollowsC=$TEST_ROOT/follows/flakeA/flakeB/flakeC
+flakeFollowsD=$TEST_ROOT/follows/flakeA/flakeD
+flakeFollowsE=$TEST_ROOT/follows/flakeA/flakeE
-for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $templatesDir $nonFlakeDir $flakeA $flakeB; do
+for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $templatesDir $nonFlakeDir $flakeA $flakeB $flakeFollowsA; do
rm -rf $repo $repo.tmp
- mkdir $repo
+ mkdir -p $repo
git -C $repo init
git -C $repo config user.email "foobar@example.com"
git -C $repo config user.name "Foobar"
@@ -681,3 +686,89 @@ git -C $flakeB commit -a -m 'Foo'
# Test list-inputs with circular dependencies
nix flake metadata $flakeA
+
+# Test flake follow paths
+mkdir -p $flakeFollowsB
+mkdir -p $flakeFollowsC
+mkdir -p $flakeFollowsD
+mkdir -p $flakeFollowsE
+
+cat > $flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs = {
+ B = {
+ url = "path:./flakeB";
+ inputs.foobar.follows = "D";
+ };
+
+ D.url = "path:./flakeD";
+ foobar.url = "path:./flakeE";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsB/flake.nix <<EOF
+{
+ description = "Flake B";
+ inputs = {
+ foobar.url = "path:./../flakeE";
+ C = {
+ url = "path:./flakeC";
+ inputs.foobar.follows = "foobar";
+ };
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsC/flake.nix <<EOF
+{
+ description = "Flake C";
+ inputs = {
+ foobar.url = "path:./../../flakeE";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsD/flake.nix <<EOF
+{
+ description = "Flake D";
+ inputs = {};
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsE/flake.nix <<EOF
+{
+ description = "Flake D";
+ inputs = {};
+ outputs = { ... }: {};
+}
+EOF
+
+git -C $flakeFollowsA add flake.nix flakeB/flake.nix \
+ flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix
+
+nix flake lock $flakeFollowsA
+
+[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
+[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
+[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
+
+# Ensure a relative path is not allowed to go outside the store path
+cat > $flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs = {
+ B.url = "path:./../../flakeB";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+git -C $flakeFollowsA add flake.nix
+
+nix flake lock $flakeFollowsA 2>&1 | grep 'this is a security violation'