From 96bd9bad2f434fe3489b039ac665679878460b0c Mon Sep 17 00:00:00 2001 From: Bryan Lai Date: Thu, 26 Dec 2024 20:50:36 +0800 Subject: [PATCH 01/10] fetchers/git: make path absolute for local repo --- src/libfetchers/git.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index d894550c0..c4dfc27a2 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -426,7 +426,16 @@ struct GitInputScheme : InputScheme auto url = parseURL(getStrAttr(input.attrs, "url")); bool isBareRepository = url.scheme == "file" && !pathExists(url.path + "/.git"); repoInfo.isLocal = url.scheme == "file" && !forceHttp && !isBareRepository; - repoInfo.url = repoInfo.isLocal ? url.path : url.to_string(); + // + // FIXME: here we turn a possibly relative path into an absolute path. + // This allows relative git flake inputs to be resolved against the + // **current working directory** (as in POSIX), which tends to work out + // ok in the context of flakes, but is the wrong behavior, + // as it should resolve against the flake.nix base directory instead. + // + // See: https://discourse.nixos.org/t/57783 and #9708 + // + repoInfo.url = repoInfo.isLocal ? std::filesystem::absolute(url.path).string() : url.to_string(); // If this is a local directory and no ref or revision is // given, then allow the use of an unclean working tree. From 9d088fa50242c5fe2ad94bffb61a4742f232ff0b Mon Sep 17 00:00:00 2001 From: Bryan Lai Date: Fri, 27 Dec 2024 17:35:44 +0800 Subject: [PATCH 02/10] tests/flakes: check git+file:./${submodule} protocol Relative, local git repo used to work (for submodules), but it fails after 3e0129ce3b9eb094d4a3cc8023884f372f1d7ff6. This commit adds a test to prevent such failure in the future. --- tests/functional/flakes/flakes.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index 6c466a0c7..acbd32a91 100755 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -106,6 +106,14 @@ nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir#default" nix build -o "$TEST_ROOT/result" "$flake1Dir?ref=HEAD#default" nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default" +# Check that relative paths are allowed for git flakes. +# This may change in the future once git submodule support is refined. +# See: https://discourse.nixos.org/t/57783 and #9708. +( + cd "$flake1Dir/.." + nix build -o "$TEST_ROOT/result" "git+file:./$(basename "$flake1Dir")" +) + # Check that store symlinks inside a flake are not interpreted as flakes. nix build -o "$flake1Dir/result" "git+file://$flake1Dir" nix path-info "$flake1Dir/result" From 37ac18d1d9faba24ce09653723342465bcac3e0b Mon Sep 17 00:00:00 2001 From: Bryan Lai Date: Wed, 1 Jan 2025 14:53:04 +0800 Subject: [PATCH 03/10] tests/flake-in-submodule: git+file:./* input --- tests/functional/flakes/flake-in-submodule.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/functional/flakes/flake-in-submodule.sh b/tests/functional/flakes/flake-in-submodule.sh index 643d729ff..f98c19aa8 100755 --- a/tests/functional/flakes/flake-in-submodule.sh +++ b/tests/functional/flakes/flake-in-submodule.sh @@ -76,3 +76,21 @@ git -C "$rootRepo" commit -m "Add flake.nix" storePath=$(nix flake metadata --json "$rootRepo?submodules=1" | jq -r .path) [[ -e "$storePath/submodule" ]] + +# The root repo may use the submodule repo as an input +# through the relative path. This may change in the future; +# see: https://discourse.nixos.org/t/57783 and #9708. +cat > "$rootRepo"/flake.nix < Date: Fri, 10 Jan 2025 09:57:54 +0100 Subject: [PATCH 04/10] Clarify cd call in tests/functional/flakes/flakes.sh --- tests/functional/flakes/flakes.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index acbd32a91..995ca03b0 100755 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -110,6 +110,7 @@ nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default" # This may change in the future once git submodule support is refined. # See: https://discourse.nixos.org/t/57783 and #9708. ( + # This `cd` should not be required and is indicative of aforementioned bug. cd "$flake1Dir/.." nix build -o "$TEST_ROOT/result" "git+file:./$(basename "$flake1Dir")" ) From e1613932991b719854a0b23ff0ab0b42fc9fc747 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 10 Jan 2025 16:27:40 +0100 Subject: [PATCH 05/10] Add setting 'allow-dirty-locks' This allows writing lock files with dirty inputs, so long as they have a NAR hash. (Currently they always have a NAR hash, but with lazy trees that may not always be the case.) Generally dirty locks are bad for reproducibility (we can detect if the dirty input has changed, but we have no way to fetch it except substitution). Hence we don't allow them by default. Fixes #11181. --- src/libcmd/installables.cc | 2 +- src/libexpr/primops/fetchTree.cc | 2 +- src/libfetchers/fetch-settings.hh | 16 ++++++++++++++++ src/libfetchers/fetchers.cc | 7 +++++++ src/libfetchers/fetchers.hh | 9 +++++++++ src/libflake/flake/flake.cc | 16 +++++++++++----- src/libflake/flake/flake.hh | 4 +++- src/libflake/flake/lockfile.cc | 9 +++++---- src/libflake/flake/lockfile.hh | 2 +- src/libflake/flake/settings.hh | 2 +- src/nix/flake.cc | 4 ++-- tests/functional/flakes/unlocked-override.sh | 11 ++++++++++- 12 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 250cd1413..ab3ab3104 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -450,7 +450,7 @@ ref openEvalCache( std::shared_ptr lockedFlake) { auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval - ? lockedFlake->getFingerprint(state.store) + ? lockedFlake->getFingerprint(state.store, state.fetchSettings) : std::nullopt; auto rootLoader = [&state, lockedFlake]() { diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 47d1be1cc..fe42b88f1 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -182,7 +182,7 @@ static void fetchTree( if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes)) input = lookupInRegistries(state.store, input).first; - if (state.settings.pureEval && !input.isLocked()) { + if (state.settings.pureEval && !input.isConsideredLocked(state.fetchSettings)) { auto fetcher = "fetchTree"; if (params.isFetchGit) fetcher = "fetchGit"; diff --git a/src/libfetchers/fetch-settings.hh b/src/libfetchers/fetch-settings.hh index f7cb34a02..2ad8aa327 100644 --- a/src/libfetchers/fetch-settings.hh +++ b/src/libfetchers/fetch-settings.hh @@ -70,6 +70,22 @@ struct Settings : public Config Setting warnDirty{this, true, "warn-dirty", "Whether to warn about dirty Git/Mercurial trees."}; + Setting allowDirtyLocks{ + this, + false, + "allow-dirty-locks", + R"( + Whether to allow dirty inputs (such as dirty Git workdirs) + to be locked via their NAR hash. This is generally bad + practice since Nix has no way to obtain such inputs if they + are subsequently modified. Therefore lock files with dirty + locks should generally only be used for local testing, and + should not be pushed to other users. + )", + {}, + true, + Xp::Flakes}; + Setting trustTarballsFromGitForges{ this, true, "trust-tarballs-from-git-forges", R"( diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 87bf0dd71..35976f6a3 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -4,6 +4,7 @@ #include "fetch-to-store.hh" #include "json-utils.hh" #include "store-path-accessor.hh" +#include "fetch-settings.hh" #include @@ -154,6 +155,12 @@ bool Input::isLocked() const return scheme && scheme->isLocked(*this); } +bool Input::isConsideredLocked( + const Settings & settings) const +{ + return isLocked() || (settings.allowDirtyLocks && getNarHash()); +} + bool Input::isFinal() const { return maybeGetBoolAttr(attrs, "__final").value_or(false); diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index 841a44041..8cabd5103 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -95,6 +95,15 @@ public: */ bool isLocked() const; + /** + * Return whether the input is either locked, or, if + * `allow-dirty-locks` is enabled, it has a NAR hash. In the + * latter case, we can verify the input but we may not be able to + * fetch it from anywhere. + */ + bool isConsideredLocked( + const Settings & settings) const; + /** * Return whether this is a "final" input, meaning that fetching * it will not add, remove or change any attributes. (See diff --git a/src/libflake/flake/flake.cc b/src/libflake/flake/flake.cc index 29090b900..8c0c36eb3 100644 --- a/src/libflake/flake/flake.cc +++ b/src/libflake/flake/flake.cc @@ -345,6 +345,7 @@ Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup } static LockFile readLockFile( + const Settings & settings, const fetchers::Settings & fetchSettings, const SourcePath & lockFilePath) { @@ -380,6 +381,7 @@ LockedFlake lockFlake( } auto oldLockFile = readLockFile( + settings, state.fetchSettings, lockFlags.referenceLockFilePath.value_or( flake.lockFilePath())); @@ -616,7 +618,7 @@ LockedFlake lockFlake( inputFlake.inputs, childNode, inputPath, oldLock ? std::dynamic_pointer_cast(oldLock) - : readLockFile(state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(), + : readLockFile(settings, state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(), oldLock ? lockRootPath : inputPath, localPath, false); @@ -678,9 +680,11 @@ LockedFlake lockFlake( if (lockFlags.writeLockFile) { if (sourcePath || lockFlags.outputLockFilePath) { - if (auto unlockedInput = newLockFile.isUnlocked()) { + if (auto unlockedInput = newLockFile.isUnlocked(state.fetchSettings)) { if (lockFlags.failOnUnlocked) - throw Error("cannot write lock file of flake '%s' because it has an unlocked input ('%s').\n", topRef, *unlockedInput); + throw Error( + "Will not write lock file of flake '%s' because it has an unlocked input ('%s'). " + "Use '--allow-dirty-locks' to allow this anyway.", topRef, *unlockedInput); if (state.fetchSettings.warnDirty) warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput); } else { @@ -979,9 +983,11 @@ static RegisterPrimOp r4({ } -std::optional LockedFlake::getFingerprint(ref store) const +std::optional LockedFlake::getFingerprint( + ref store, + const fetchers::Settings & fetchSettings) const { - if (lockFile.isUnlocked()) return std::nullopt; + if (lockFile.isUnlocked(fetchSettings)) return std::nullopt; auto fingerprint = flake.lockedRef.input.getFingerprint(store); if (!fingerprint) return std::nullopt; diff --git a/src/libflake/flake/flake.hh b/src/libflake/flake/flake.hh index 0dfd9440d..f85671a41 100644 --- a/src/libflake/flake/flake.hh +++ b/src/libflake/flake/flake.hh @@ -129,7 +129,9 @@ struct LockedFlake */ std::map, SourcePath> nodePaths; - std::optional getFingerprint(ref store) const; + std::optional getFingerprint( + ref store, + const fetchers::Settings & fetchSettings) const; }; struct LockFlags diff --git a/src/libflake/flake/lockfile.cc b/src/libflake/flake/lockfile.cc index 668ed165f..336054f5b 100644 --- a/src/libflake/flake/lockfile.cc +++ b/src/libflake/flake/lockfile.cc @@ -10,6 +10,7 @@ #include #include "strings.hh" +#include "flake/settings.hh" namespace nix::flake { @@ -43,8 +44,8 @@ LockedNode::LockedNode( , originalRef(getFlakeRef(fetchSettings, json, "original", nullptr)) , isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true) { - if (!lockedRef.input.isLocked()) - throw Error("lock file contains unlocked input '%s'", + if (!lockedRef.input.isConsideredLocked(fetchSettings)) + throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.", fetchers::attrsToJSON(lockedRef.input.toAttrs())); // For backward compatibility, lock file entries are implicitly final. @@ -228,7 +229,7 @@ std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile) return stream; } -std::optional LockFile::isUnlocked() const +std::optional LockFile::isUnlocked(const fetchers::Settings & fetchSettings) const { std::set> nodes; @@ -247,7 +248,7 @@ std::optional LockFile::isUnlocked() const for (auto & i : nodes) { if (i == ref(root)) continue; auto node = i.dynamic_pointer_cast(); - if (node && (!node->lockedRef.input.isLocked() || !node->lockedRef.input.isFinal())) + if (node && (!node->lockedRef.input.isConsideredLocked(fetchSettings) || !node->lockedRef.input.isFinal())) return node->lockedRef; } diff --git a/src/libflake/flake/lockfile.hh b/src/libflake/flake/lockfile.hh index a2711a516..bcc3c460c 100644 --- a/src/libflake/flake/lockfile.hh +++ b/src/libflake/flake/lockfile.hh @@ -71,7 +71,7 @@ struct LockFile * Check whether this lock file has any unlocked or non-final * inputs. If so, return one. */ - std::optional isUnlocked() const; + std::optional isUnlocked(const fetchers::Settings & fetchSettings) const; bool operator ==(const LockFile & other) const; diff --git a/src/libflake/flake/settings.hh b/src/libflake/flake/settings.hh index fee247a7d..991eaca1f 100644 --- a/src/libflake/flake/settings.hh +++ b/src/libflake/flake/settings.hh @@ -29,7 +29,7 @@ struct Settings : public Config this, false, "accept-flake-config", - "Whether to accept nix configuration from a flake without prompting.", + "Whether to accept Nix configuration settings from a flake without prompting.", {}, true, Xp::Flakes}; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 7189689cc..d92f644d9 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -238,7 +238,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON j["lastModified"] = *lastModified; j["path"] = storePath; j["locks"] = lockedFlake.lockFile.toJSON().first; - if (auto fingerprint = lockedFlake.getFingerprint(store)) + if (auto fingerprint = lockedFlake.getFingerprint(store, fetchSettings)) j["fingerprint"] = fingerprint->to_string(HashFormat::Base16, false); logger->cout("%s", j.dump()); } else { @@ -272,7 +272,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON logger->cout( ANSI_BOLD "Last modified:" ANSI_NORMAL " %s", std::put_time(std::localtime(&*lastModified), "%F %T")); - if (auto fingerprint = lockedFlake.getFingerprint(store)) + if (auto fingerprint = lockedFlake.getFingerprint(store, fetchSettings)) logger->cout( ANSI_BOLD "Fingerprint:" ANSI_NORMAL " %s", fingerprint->to_string(HashFormat::Base16, false)); diff --git a/tests/functional/flakes/unlocked-override.sh b/tests/functional/flakes/unlocked-override.sh index ebad332d0..dcb427a8f 100755 --- a/tests/functional/flakes/unlocked-override.sh +++ b/tests/functional/flakes/unlocked-override.sh @@ -31,5 +31,14 @@ echo 456 > "$flake1Dir"/x.nix [[ $(nix eval --json "$flake2Dir#x" --override-input flake1 "$TEST_ROOT/flake1") = 456 ]] +# Dirty overrides require --allow-dirty-locks. expectStderr 1 nix flake lock "$flake2Dir" --override-input flake1 "$TEST_ROOT/flake1" | - grepQuiet "cannot write lock file.*because it has an unlocked input" + grepQuiet "Will not write lock file.*because it has an unlocked input" + +nix flake lock "$flake2Dir" --override-input flake1 "$TEST_ROOT/flake1" --allow-dirty-locks + +# Using a lock file with a dirty lock requires --allow-dirty-locks as well. +expectStderr 1 nix eval "$flake2Dir#x" | + grepQuiet "Lock file contains unlocked input" + +[[ $(nix eval "$flake2Dir#x" --allow-dirty-locks) = 456 ]] From 47cf93ba80b8be3701589a25ba5d8e8382b3962f Mon Sep 17 00:00:00 2001 From: Tristan Ross Date: Fri, 10 Jan 2025 18:08:27 -0800 Subject: [PATCH 06/10] Add LLVM to Flake --- flake.nix | 5 +++++ src/libcmd/package.nix | 2 +- src/libexpr/package.nix | 2 +- src/libfetchers/package.nix | 2 +- src/libflake/package.nix | 2 +- src/libmain/package.nix | 2 +- src/libstore/package.nix | 2 +- src/libutil/package.nix | 2 +- src/nix/package.nix | 2 +- 9 files changed, 13 insertions(+), 8 deletions(-) diff --git a/flake.nix b/flake.nix index 83bdc5ecc..8edc2266f 100644 --- a/flake.nix +++ b/flake.nix @@ -107,6 +107,7 @@ in { inherit stdenvs native; static = native.pkgsStatic; + llvm = native.pkgsLLVM; cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "stdenv"); }); @@ -282,6 +283,7 @@ # These attributes go right into `packages.`. "${pkgName}" = nixpkgsFor.${system}.native.nixComponents.${pkgName}; "${pkgName}-static" = nixpkgsFor.${system}.static.nixComponents.${pkgName}; + "${pkgName}-llvm" = nixpkgsFor.${system}.llvm.nixComponents.${pkgName}; } // lib.optionalAttrs supportsCross (flatMapAttrs (lib.genAttrs crossSystems (_: { })) (crossSystem: {}: { # These attributes go right into `packages.`. @@ -321,6 +323,9 @@ prefixAttrs "static" (forAllStdenvs (stdenvName: makeShell { pkgs = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".pkgsStatic; })) // + prefixAttrs "llvm" (forAllStdenvs (stdenvName: makeShell { + pkgs = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".pkgsLLVM; + })) // prefixAttrs "cross" (forAllCrossSystems (crossSystem: makeShell { pkgs = nixpkgsFor.${system}.cross.${crossSystem}; })) diff --git a/src/libcmd/package.nix b/src/libcmd/package.nix index 53e54d2f8..9244a780a 100644 --- a/src/libcmd/package.nix +++ b/src/libcmd/package.nix @@ -76,7 +76,7 @@ mkMesonLibrary (finalAttrs: { (lib.mesonOption "readline-flavor" readlineFlavor) ]; - env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libexpr/package.nix b/src/libexpr/package.nix index 5171d70fd..9ef56b28c 100644 --- a/src/libexpr/package.nix +++ b/src/libexpr/package.nix @@ -96,7 +96,7 @@ mkMesonLibrary (finalAttrs: { # https://github.com/NixOS/nixpkgs/issues/86131. BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; BOOST_LIBRARYDIR = "${lib.getLib boost}/lib"; - } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libfetchers/package.nix b/src/libfetchers/package.nix index 7dad00025..86d505fbf 100644 --- a/src/libfetchers/package.nix +++ b/src/libfetchers/package.nix @@ -49,7 +49,7 @@ mkMesonLibrary (finalAttrs: { echo ${version} > ../../.version ''; - env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libflake/package.nix b/src/libflake/package.nix index 92445739f..29c9fdd80 100644 --- a/src/libflake/package.nix +++ b/src/libflake/package.nix @@ -48,7 +48,7 @@ mkMesonLibrary (finalAttrs: { echo ${version} > ../../.version ''; - env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libmain/package.nix b/src/libmain/package.nix index 7d9d99b61..ede1f005b 100644 --- a/src/libmain/package.nix +++ b/src/libmain/package.nix @@ -45,7 +45,7 @@ mkMesonLibrary (finalAttrs: { echo ${version} > ../../.version ''; - env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libstore/package.nix b/src/libstore/package.nix index 47a203f83..195efbb8a 100644 --- a/src/libstore/package.nix +++ b/src/libstore/package.nix @@ -87,7 +87,7 @@ mkMesonLibrary (finalAttrs: { # https://github.com/NixOS/nixpkgs/issues/86131. BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; BOOST_LIBRARYDIR = "${lib.getLib boost}/lib"; - } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/libutil/package.nix b/src/libutil/package.nix index 0a9f65782..11f7249ee 100644 --- a/src/libutil/package.nix +++ b/src/libutil/package.nix @@ -72,7 +72,7 @@ mkMesonLibrary (finalAttrs: { # https://github.com/NixOS/nixpkgs/issues/86131. BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; BOOST_LIBRARYDIR = "${lib.getLib boost}/lib"; - } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + } // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM or false)) { LDFLAGS = "-fuse-ld=gold"; }; diff --git a/src/nix/package.nix b/src/nix/package.nix index 9bc139c3b..67bf79f3f 100644 --- a/src/nix/package.nix +++ b/src/nix/package.nix @@ -99,7 +99,7 @@ mkMesonExecutable (finalAttrs: { mesonFlags = [ ]; - env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) { + env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") && !(stdenv.hostPlatform.useLLVM)) { LDFLAGS = "-fuse-ld=gold"; }; From fd053fdcad7bbd0dcff7a2daefd8011235653f06 Mon Sep 17 00:00:00 2001 From: Siddarth Kumar Date: Mon, 13 Jan 2025 14:12:41 +0530 Subject: [PATCH 07/10] scripts/install-multi-user: fix typo --- scripts/install-multi-user.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index b65e08682..f051ccc46 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -562,7 +562,7 @@ create_build_user_for_core() { if [ "$actual_uid" != "$uid" ]; then failure < Date: Fri, 15 Nov 2024 10:51:22 +1100 Subject: [PATCH 08/10] windows: create files if they don't exist, and with write permission --- src/libutil/fs-sink.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libutil/fs-sink.cc b/src/libutil/fs-sink.cc index dd979f83f..fadba5972 100644 --- a/src/libutil/fs-sink.cc +++ b/src/libutil/fs-sink.cc @@ -112,7 +112,7 @@ void RestoreSink::createRegularFile(const CanonPath & path, std::function Date: Tue, 14 Jan 2025 17:30:13 +0100 Subject: [PATCH 09/10] Fix relative 'path:' flakerefs in the CLI And handle relative 'git+file:' flakerefs while we're at it (these crashed with an assertion failure). Fixes #12248. --- src/libflake/flake/flakeref.cc | 11 ++++++++--- tests/functional/flakes/flakes.sh | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libflake/flake/flakeref.cc b/src/libflake/flake/flakeref.cc index cdf0a40e8..15d1191b3 100644 --- a/src/libflake/flake/flakeref.cc +++ b/src/libflake/flake/flakeref.cc @@ -102,8 +102,8 @@ std::pair parsePathFlakeRefWithFragment( if (baseDir) { /* Check if 'url' is a path (either absolute or relative - to 'baseDir'). If so, search upward to the root of the - repo (i.e. the directory containing .git). */ + to 'baseDir'). If so, search upward to the root of the + repo (i.e. the directory containing .git). */ path = absPath(path, baseDir); @@ -232,7 +232,12 @@ std::optional> parseURLFlakeRef( ) { try { - return fromParsedURL(fetchSettings, parseURL(url), isFlake); + auto parsed = parseURL(url); + if (baseDir + && (parsed.scheme == "path" || parsed.scheme == "git+file") + && !hasPrefix(parsed.path, "/")) + parsed.path = absPath(parsed.path, *baseDir); + return fromParsedURL(fetchSettings, std::move(parsed), isFlake); } catch (BadURL &) { return std::nullopt; } diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index 6c466a0c7..342c075a8 100755 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -97,6 +97,9 @@ nix build -o "$TEST_ROOT/result" flake1 nix build -o "$TEST_ROOT/result" "$flake1Dir" nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir" +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" ".") +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" "path:.") +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" "git+file:.") # Test explicit packages.default. nix build -o "$TEST_ROOT/result" "$flake1Dir#default" From ff9d886f3cb28db13bfb88d1dc4d6fe3dc83270f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 14 Jan 2025 17:42:26 +0100 Subject: [PATCH 10/10] Use isAbsolute() --- src/libexpr/eval.cc | 2 +- src/libfetchers/path.cc | 2 +- src/libfetchers/registry.cc | 2 +- src/libflake/flake/flakeref.cc | 4 ++-- src/libutil/file-system.cc | 7 +------ src/libutil/file-system.hh | 5 +++++ src/libutil/source-accessor.cc | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 21dd5a294..345c09e7e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -406,7 +406,7 @@ void EvalState::checkURI(const std::string & uri) /* If the URI is a path, then check it against allowedPaths as well. */ - if (hasPrefix(uri, "/")) { + if (isAbsolute(uri)) { if (auto rootFS2 = rootFS.dynamic_pointer_cast()) rootFS2->checkAccess(CanonPath(uri)); return; diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index f628e042c..340e7f4fa 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme std::optional isRelative(const Input & input) const { auto path = getStrAttr(input.attrs, "path"); - if (hasPrefix(path, "/")) + if (isAbsolute(path)) return std::nullopt; else return path; diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index 171afcea7..c18e12d23 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -153,7 +153,7 @@ static std::shared_ptr getGlobalRegistry(const Settings & settings, re return std::make_shared(settings, Registry::Global); // empty registry } - if (!hasPrefix(path, "/")) { + if (!isAbsolute(path)) { auto storePath = downloadFile(store, path, "flake-registry.json").storePath; if (auto store2 = store.dynamic_pointer_cast()) store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json"); diff --git a/src/libflake/flake/flakeref.cc b/src/libflake/flake/flakeref.cc index 15d1191b3..b81eb1292 100644 --- a/src/libflake/flake/flakeref.cc +++ b/src/libflake/flake/flakeref.cc @@ -178,7 +178,7 @@ std::pair parsePathFlakeRefWithFragment( } } else { - if (!hasPrefix(path, "/")) + if (!isAbsolute(path)) throw BadURL("flake reference '%s' is not an absolute path", url); path = canonPath(path + "/" + getOr(query, "dir", "")); } @@ -235,7 +235,7 @@ std::optional> parseURLFlakeRef( auto parsed = parseURL(url); if (baseDir && (parsed.scheme == "path" || parsed.scheme == "git+file") - && !hasPrefix(parsed.path, "/")) + && !isAbsolute(parsed.path)) parsed.path = absPath(parsed.path, *baseDir); return fromParsedURL(fetchSettings, std::move(parsed), isFlake); } catch (BadURL &) { diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 923220fd0..a86f1ba4f 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -31,12 +31,7 @@ namespace nix { namespace fs { using namespace std::filesystem; } -/** - * Treat the string as possibly an absolute path, by inspecting the - * start of it. Return whether it was probably intended to be - * absolute. - */ -static bool isAbsolute(PathView path) +bool isAbsolute(PathView path) { return fs::path { path }.is_absolute(); } diff --git a/src/libutil/file-system.hh b/src/libutil/file-system.hh index 7fdaba811..204907339 100644 --- a/src/libutil/file-system.hh +++ b/src/libutil/file-system.hh @@ -42,6 +42,11 @@ namespace nix { struct Sink; struct Source; +/** + * Return whether the path denotes an absolute path. + */ +bool isAbsolute(PathView path); + /** * @return An absolutized path, resolving paths relative to the * specified directory, or the current directory otherwise. The path diff --git a/src/libutil/source-accessor.cc b/src/libutil/source-accessor.cc index aa8dcf9fd..78f038cf3 100644 --- a/src/libutil/source-accessor.cc +++ b/src/libutil/source-accessor.cc @@ -115,7 +115,7 @@ CanonPath SourceAccessor::resolveSymlinks( throw Error("infinite symlink recursion in path '%s'", showPath(path)); auto target = readLink(res); res.pop(); - if (hasPrefix(target, "/")) + if (isAbsolute(target)) res = CanonPath::root; todo.splice(todo.begin(), tokenizeString>(target, "/")); }