mirror of
https://github.com/NixOS/nix
synced 2025-07-02 09:21:47 +02:00
Merge remote-tracking branch 'origin/master' into relative-flakes
This commit is contained in:
commit
550fe889ee
33 changed files with 142 additions and 42 deletions
|
@ -107,6 +107,7 @@
|
||||||
in {
|
in {
|
||||||
inherit stdenvs native;
|
inherit stdenvs native;
|
||||||
static = native.pkgsStatic;
|
static = native.pkgsStatic;
|
||||||
|
llvm = native.pkgsLLVM;
|
||||||
cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "stdenv");
|
cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "stdenv");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -282,6 +283,7 @@
|
||||||
# These attributes go right into `packages.<system>`.
|
# These attributes go right into `packages.<system>`.
|
||||||
"${pkgName}" = nixpkgsFor.${system}.native.nixComponents.${pkgName};
|
"${pkgName}" = nixpkgsFor.${system}.native.nixComponents.${pkgName};
|
||||||
"${pkgName}-static" = nixpkgsFor.${system}.static.nixComponents.${pkgName};
|
"${pkgName}-static" = nixpkgsFor.${system}.static.nixComponents.${pkgName};
|
||||||
|
"${pkgName}-llvm" = nixpkgsFor.${system}.llvm.nixComponents.${pkgName};
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs supportsCross (flatMapAttrs (lib.genAttrs crossSystems (_: { })) (crossSystem: {}: {
|
// lib.optionalAttrs supportsCross (flatMapAttrs (lib.genAttrs crossSystems (_: { })) (crossSystem: {}: {
|
||||||
# These attributes go right into `packages.<system>`.
|
# These attributes go right into `packages.<system>`.
|
||||||
|
@ -321,6 +323,9 @@
|
||||||
prefixAttrs "static" (forAllStdenvs (stdenvName: makeShell {
|
prefixAttrs "static" (forAllStdenvs (stdenvName: makeShell {
|
||||||
pkgs = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".pkgsStatic;
|
pkgs = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".pkgsStatic;
|
||||||
})) //
|
})) //
|
||||||
|
prefixAttrs "llvm" (forAllStdenvs (stdenvName: makeShell {
|
||||||
|
pkgs = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".pkgsLLVM;
|
||||||
|
})) //
|
||||||
prefixAttrs "cross" (forAllCrossSystems (crossSystem: makeShell {
|
prefixAttrs "cross" (forAllCrossSystems (crossSystem: makeShell {
|
||||||
pkgs = nixpkgsFor.${system}.cross.${crossSystem};
|
pkgs = nixpkgsFor.${system}.cross.${crossSystem};
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -562,7 +562,7 @@ create_build_user_for_core() {
|
||||||
if [ "$actual_uid" != "$uid" ]; then
|
if [ "$actual_uid" != "$uid" ]; then
|
||||||
failure <<EOF
|
failure <<EOF
|
||||||
It seems the build user $username already exists, but with the UID
|
It seems the build user $username already exists, but with the UID
|
||||||
with the UID '$actual_uid'. This script can't really handle that right
|
'$actual_uid'. This script can't really handle that right
|
||||||
now, so I'm going to give up.
|
now, so I'm going to give up.
|
||||||
|
|
||||||
If you already created the users and you know they start from
|
If you already created the users and you know they start from
|
||||||
|
|
|
@ -450,7 +450,7 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
||||||
{
|
{
|
||||||
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
||||||
? lockedFlake->getFingerprint(state.store)
|
? lockedFlake->getFingerprint(state.store, state.fetchSettings)
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
auto rootLoader = [&state, lockedFlake]()
|
auto rootLoader = [&state, lockedFlake]()
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,7 +76,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
(lib.mesonOption "readline-flavor" readlineFlavor)
|
(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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -406,7 +406,7 @@ void EvalState::checkURI(const std::string & uri)
|
||||||
|
|
||||||
/* If the URI is a path, then check it against allowedPaths as
|
/* If the URI is a path, then check it against allowedPaths as
|
||||||
well. */
|
well. */
|
||||||
if (hasPrefix(uri, "/")) {
|
if (isAbsolute(uri)) {
|
||||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>())
|
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>())
|
||||||
rootFS2->checkAccess(CanonPath(uri));
|
rootFS2->checkAccess(CanonPath(uri));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -96,7 +96,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
# https://github.com/NixOS/nixpkgs/issues/86131.
|
# https://github.com/NixOS/nixpkgs/issues/86131.
|
||||||
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
||||||
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ static void fetchTree(
|
||||||
if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes))
|
if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes))
|
||||||
input = lookupInRegistries(state.store, input).first;
|
input = lookupInRegistries(state.store, input).first;
|
||||||
|
|
||||||
if (state.settings.pureEval && !input.isLocked()) {
|
if (state.settings.pureEval && !input.isConsideredLocked(state.fetchSettings)) {
|
||||||
auto fetcher = "fetchTree";
|
auto fetcher = "fetchTree";
|
||||||
if (params.isFetchGit)
|
if (params.isFetchGit)
|
||||||
fetcher = "fetchGit";
|
fetcher = "fetchGit";
|
||||||
|
|
|
@ -70,6 +70,22 @@ struct Settings : public Config
|
||||||
Setting<bool> warnDirty{this, true, "warn-dirty",
|
Setting<bool> warnDirty{this, true, "warn-dirty",
|
||||||
"Whether to warn about dirty Git/Mercurial trees."};
|
"Whether to warn about dirty Git/Mercurial trees."};
|
||||||
|
|
||||||
|
Setting<bool> 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<bool> trustTarballsFromGitForges{
|
Setting<bool> trustTarballsFromGitForges{
|
||||||
this, true, "trust-tarballs-from-git-forges",
|
this, true, "trust-tarballs-from-git-forges",
|
||||||
R"(
|
R"(
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "fetch-to-store.hh"
|
#include "fetch-to-store.hh"
|
||||||
#include "json-utils.hh"
|
#include "json-utils.hh"
|
||||||
#include "store-path-accessor.hh"
|
#include "store-path-accessor.hh"
|
||||||
|
#include "fetch-settings.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
@ -154,6 +155,12 @@ bool Input::isLocked() const
|
||||||
return scheme && scheme->isLocked(*this);
|
return scheme && scheme->isLocked(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Input::isConsideredLocked(
|
||||||
|
const Settings & settings) const
|
||||||
|
{
|
||||||
|
return isLocked() || (settings.allowDirtyLocks && getNarHash());
|
||||||
|
}
|
||||||
|
|
||||||
bool Input::isFinal() const
|
bool Input::isFinal() const
|
||||||
{
|
{
|
||||||
return maybeGetBoolAttr(attrs, "__final").value_or(false);
|
return maybeGetBoolAttr(attrs, "__final").value_or(false);
|
||||||
|
|
|
@ -90,6 +90,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isLocked() const;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only for relative path flakes, i.e. 'path:./foo', returns the
|
* Only for relative path flakes, i.e. 'path:./foo', returns the
|
||||||
* relative path, i.e. './foo'.
|
* relative path, i.e. './foo'.
|
||||||
|
|
|
@ -426,7 +426,16 @@ struct GitInputScheme : InputScheme
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
bool isBareRepository = url.scheme == "file" && !pathExists(url.path + "/.git");
|
bool isBareRepository = url.scheme == "file" && !pathExists(url.path + "/.git");
|
||||||
repoInfo.isLocal = url.scheme == "file" && !forceHttp && !isBareRepository;
|
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
|
// If this is a local directory and no ref or revision is
|
||||||
// given, then allow the use of an unclean working tree.
|
// given, then allow the use of an unclean working tree.
|
||||||
|
|
|
@ -49,7 +49,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
echo ${version} > ../../.version
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme
|
||||||
std::optional<std::string> isRelative(const Input & input) const override
|
std::optional<std::string> isRelative(const Input & input) const override
|
||||||
{
|
{
|
||||||
auto path = getStrAttr(input.attrs, "path");
|
auto path = getStrAttr(input.attrs, "path");
|
||||||
if (hasPrefix(path, "/"))
|
if (isAbsolute(path))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
else
|
else
|
||||||
return path;
|
return path;
|
||||||
|
|
|
@ -153,7 +153,7 @@ static std::shared_ptr<Registry> getGlobalRegistry(const Settings & settings, re
|
||||||
return std::make_shared<Registry>(settings, Registry::Global); // empty registry
|
return std::make_shared<Registry>(settings, Registry::Global); // empty registry
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPrefix(path, "/")) {
|
if (!isAbsolute(path)) {
|
||||||
auto storePath = downloadFile(store, path, "flake-registry.json").storePath;
|
auto storePath = downloadFile(store, path, "flake-registry.json").storePath;
|
||||||
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
|
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
|
||||||
store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json");
|
store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json");
|
||||||
|
|
|
@ -367,6 +367,7 @@ Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup
|
||||||
}
|
}
|
||||||
|
|
||||||
static LockFile readLockFile(
|
static LockFile readLockFile(
|
||||||
|
const Settings & settings,
|
||||||
const fetchers::Settings & fetchSettings,
|
const fetchers::Settings & fetchSettings,
|
||||||
const SourcePath & lockFilePath)
|
const SourcePath & lockFilePath)
|
||||||
{
|
{
|
||||||
|
@ -402,6 +403,7 @@ LockedFlake lockFlake(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto oldLockFile = readLockFile(
|
auto oldLockFile = readLockFile(
|
||||||
|
settings,
|
||||||
state.fetchSettings,
|
state.fetchSettings,
|
||||||
lockFlags.referenceLockFilePath.value_or(
|
lockFlags.referenceLockFilePath.value_or(
|
||||||
flake.lockFilePath()));
|
flake.lockFilePath()));
|
||||||
|
@ -690,7 +692,7 @@ LockedFlake lockFlake(
|
||||||
inputFlake.inputs, childNode, inputPath,
|
inputFlake.inputs, childNode, inputPath,
|
||||||
oldLock
|
oldLock
|
||||||
? std::dynamic_pointer_cast<const Node>(oldLock)
|
? std::dynamic_pointer_cast<const Node>(oldLock)
|
||||||
: readLockFile(state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(),
|
: readLockFile(settings, state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(),
|
||||||
oldLock ? lockRootPath : inputPath,
|
oldLock ? lockRootPath : inputPath,
|
||||||
inputFlake.path,
|
inputFlake.path,
|
||||||
false);
|
false);
|
||||||
|
@ -758,9 +760,11 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
if (lockFlags.writeLockFile) {
|
if (lockFlags.writeLockFile) {
|
||||||
if (sourcePath || lockFlags.outputLockFilePath) {
|
if (sourcePath || lockFlags.outputLockFilePath) {
|
||||||
if (auto unlockedInput = newLockFile.isUnlocked()) {
|
if (auto unlockedInput = newLockFile.isUnlocked(state.fetchSettings)) {
|
||||||
if (lockFlags.failOnUnlocked)
|
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)
|
if (state.fetchSettings.warnDirty)
|
||||||
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1059,9 +1063,11 @@ static RegisterPrimOp r4({
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Fingerprint> LockedFlake::getFingerprint(ref<Store> store) const
|
std::optional<Fingerprint> LockedFlake::getFingerprint(
|
||||||
|
ref<Store> 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);
|
auto fingerprint = flake.lockedRef.input.getFingerprint(store);
|
||||||
if (!fingerprint) return std::nullopt;
|
if (!fingerprint) return std::nullopt;
|
||||||
|
|
|
@ -129,7 +129,9 @@ struct LockedFlake
|
||||||
*/
|
*/
|
||||||
std::map<ref<Node>, SourcePath> nodePaths;
|
std::map<ref<Node>, SourcePath> nodePaths;
|
||||||
|
|
||||||
std::optional<Fingerprint> getFingerprint(ref<Store> store) const;
|
std::optional<Fingerprint> getFingerprint(
|
||||||
|
ref<Store> store,
|
||||||
|
const fetchers::Settings & fetchSettings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LockFlags
|
struct LockFlags
|
||||||
|
|
|
@ -104,8 +104,8 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||||
|
|
||||||
if (baseDir) {
|
if (baseDir) {
|
||||||
/* Check if 'url' is a path (either absolute or relative
|
/* Check if 'url' is a path (either absolute or relative
|
||||||
to 'baseDir'). If so, search upward to the root of the
|
to 'baseDir'). If so, search upward to the root of the
|
||||||
repo (i.e. the directory containing .git). */
|
repo (i.e. the directory containing .git). */
|
||||||
|
|
||||||
path = absPath(path, baseDir);
|
path = absPath(path, baseDir);
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!preserveRelativePaths && !hasPrefix(path, "/"))
|
if (!preserveRelativePaths && !isAbsolute(path))
|
||||||
throw BadURL("flake reference '%s' is not an absolute path", url);
|
throw BadURL("flake reference '%s' is not an absolute path", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +231,12 @@ std::optional<std::pair<FlakeRef, std::string>> parseURLFlakeRef(
|
||||||
bool isFlake)
|
bool isFlake)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return fromParsedURL(fetchSettings, parseURL(url), isFlake);
|
auto parsed = parseURL(url);
|
||||||
|
if (baseDir
|
||||||
|
&& (parsed.scheme == "path" || parsed.scheme == "git+file")
|
||||||
|
&& !isAbsolute(parsed.path))
|
||||||
|
parsed.path = absPath(parsed.path, *baseDir);
|
||||||
|
return fromParsedURL(fetchSettings, std::move(parsed), isFlake);
|
||||||
} catch (BadURL &) {
|
} catch (BadURL &) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "strings.hh"
|
#include "strings.hh"
|
||||||
|
#include "flake/settings.hh"
|
||||||
|
|
||||||
namespace nix::flake {
|
namespace nix::flake {
|
||||||
|
|
||||||
|
@ -44,8 +45,8 @@ LockedNode::LockedNode(
|
||||||
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
||||||
, parentPath(json.find("parent") != json.end() ? (std::optional<InputPath>) json["parent"] : std::nullopt)
|
, parentPath(json.find("parent") != json.end() ? (std::optional<InputPath>) json["parent"] : std::nullopt)
|
||||||
{
|
{
|
||||||
if (!lockedRef.input.isLocked() && !lockedRef.input.isRelative())
|
if (!lockedRef.input.isConsideredLocked(fetchSettings) && !lockedRef.input.isRelative())
|
||||||
throw Error("lock file contains unlocked input '%s'",
|
throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.",
|
||||||
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
|
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
|
||||||
|
|
||||||
// For backward compatibility, lock file entries are implicitly final.
|
// For backward compatibility, lock file entries are implicitly final.
|
||||||
|
@ -231,7 +232,7 @@ std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile)
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FlakeRef> LockFile::isUnlocked() const
|
std::optional<FlakeRef> LockFile::isUnlocked(const fetchers::Settings & fetchSettings) const
|
||||||
{
|
{
|
||||||
std::set<ref<const Node>> nodes;
|
std::set<ref<const Node>> nodes;
|
||||||
|
|
||||||
|
@ -251,7 +252,8 @@ std::optional<FlakeRef> LockFile::isUnlocked() const
|
||||||
if (i == ref<const Node>(root)) continue;
|
if (i == ref<const Node>(root)) continue;
|
||||||
auto node = i.dynamic_pointer_cast<const LockedNode>();
|
auto node = i.dynamic_pointer_cast<const LockedNode>();
|
||||||
if (node
|
if (node
|
||||||
&& (!node->lockedRef.input.isLocked() || !node->lockedRef.input.isFinal())
|
&& (!node->lockedRef.input.isConsideredLocked(fetchSettings)
|
||||||
|
|| !node->lockedRef.input.isFinal())
|
||||||
&& !node->lockedRef.input.isRelative())
|
&& !node->lockedRef.input.isRelative())
|
||||||
return node->lockedRef;
|
return node->lockedRef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ struct LockFile
|
||||||
* Check whether this lock file has any unlocked or non-final
|
* Check whether this lock file has any unlocked or non-final
|
||||||
* inputs. If so, return one.
|
* inputs. If so, return one.
|
||||||
*/
|
*/
|
||||||
std::optional<FlakeRef> isUnlocked() const;
|
std::optional<FlakeRef> isUnlocked(const fetchers::Settings & fetchSettings) const;
|
||||||
|
|
||||||
bool operator ==(const LockFile & other) const;
|
bool operator ==(const LockFile & other) const;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct Settings : public Config
|
||||||
this,
|
this,
|
||||||
false,
|
false,
|
||||||
"accept-flake-config",
|
"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,
|
true,
|
||||||
Xp::Flakes};
|
Xp::Flakes};
|
||||||
|
|
|
@ -48,7 +48,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
echo ${version} > ../../.version
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
echo ${version} > ../../.version
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
# https://github.com/NixOS/nixpkgs/issues/86131.
|
# https://github.com/NixOS/nixpkgs/issues/86131.
|
||||||
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
||||||
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,7 @@ namespace nix {
|
||||||
|
|
||||||
namespace fs { using namespace std::filesystem; }
|
namespace fs { using namespace std::filesystem; }
|
||||||
|
|
||||||
/**
|
bool isAbsolute(PathView path)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
return fs::path { path }.is_absolute();
|
return fs::path { path }.is_absolute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,11 @@ namespace nix {
|
||||||
struct Sink;
|
struct Sink;
|
||||||
struct Source;
|
struct Source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the path denotes an absolute path.
|
||||||
|
*/
|
||||||
|
bool isAbsolute(PathView path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return An absolutized path, resolving paths relative to the
|
* @return An absolutized path, resolving paths relative to the
|
||||||
* specified directory, or the current directory otherwise. The path
|
* specified directory, or the current directory otherwise. The path
|
||||||
|
|
|
@ -112,7 +112,7 @@ void RestoreSink::createRegularFile(const CanonPath & path, std::function<void(C
|
||||||
crf.startFsync = startFsync;
|
crf.startFsync = startFsync;
|
||||||
crf.fd =
|
crf.fd =
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CreateFileW(p.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)
|
CreateFileW(p.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)
|
||||||
#else
|
#else
|
||||||
open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)
|
open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -72,7 +72,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
# https://github.com/NixOS/nixpkgs/issues/86131.
|
# https://github.com/NixOS/nixpkgs/issues/86131.
|
||||||
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
||||||
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ CanonPath SourceAccessor::resolveSymlinks(
|
||||||
throw Error("infinite symlink recursion in path '%s'", showPath(path));
|
throw Error("infinite symlink recursion in path '%s'", showPath(path));
|
||||||
auto target = readLink(res);
|
auto target = readLink(res);
|
||||||
res.pop();
|
res.pop();
|
||||||
if (hasPrefix(target, "/"))
|
if (isAbsolute(target))
|
||||||
res = CanonPath::root;
|
res = CanonPath::root;
|
||||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||||
j["lastModified"] = *lastModified;
|
j["lastModified"] = *lastModified;
|
||||||
j["path"] = storePath;
|
j["path"] = storePath;
|
||||||
j["locks"] = lockedFlake.lockFile.toJSON().first;
|
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);
|
j["fingerprint"] = fingerprint->to_string(HashFormat::Base16, false);
|
||||||
logger->cout("%s", j.dump());
|
logger->cout("%s", j.dump());
|
||||||
} else {
|
} else {
|
||||||
|
@ -272,7 +272,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||||
logger->cout(
|
logger->cout(
|
||||||
ANSI_BOLD "Last modified:" ANSI_NORMAL " %s",
|
ANSI_BOLD "Last modified:" ANSI_NORMAL " %s",
|
||||||
std::put_time(std::localtime(&*lastModified), "%F %T"));
|
std::put_time(std::localtime(&*lastModified), "%F %T"));
|
||||||
if (auto fingerprint = lockedFlake.getFingerprint(store))
|
if (auto fingerprint = lockedFlake.getFingerprint(store, fetchSettings))
|
||||||
logger->cout(
|
logger->cout(
|
||||||
ANSI_BOLD "Fingerprint:" ANSI_NORMAL " %s",
|
ANSI_BOLD "Fingerprint:" ANSI_NORMAL " %s",
|
||||||
fingerprint->to_string(HashFormat::Base16, false));
|
fingerprint->to_string(HashFormat::Base16, false));
|
||||||
|
|
|
@ -99,7 +99,7 @@ mkMesonExecutable (finalAttrs: {
|
||||||
mesonFlags = [
|
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";
|
LDFLAGS = "-fuse-ld=gold";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,3 +76,21 @@ git -C "$rootRepo" commit -m "Add flake.nix"
|
||||||
|
|
||||||
storePath=$(nix flake metadata --json "$rootRepo?submodules=1" | jq -r .path)
|
storePath=$(nix flake metadata --json "$rootRepo?submodules=1" | jq -r .path)
|
||||||
[[ -e "$storePath/submodule" ]]
|
[[ -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 <<EOF
|
||||||
|
{
|
||||||
|
inputs.subRepo.url = "git+file:./submodule";
|
||||||
|
outputs = { ... }: { };
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
git -C "$rootRepo" add flake.nix
|
||||||
|
git -C "$rootRepo" commit -m "Add subRepo input"
|
||||||
|
(
|
||||||
|
cd "$rootRepo"
|
||||||
|
# The submodule must be locked to the relative path,
|
||||||
|
# _not_ the absolute path:
|
||||||
|
[[ $(nix flake metadata --json | jq -r .locks.nodes.subRepo.locked.url) = "file:./submodule" ]]
|
||||||
|
)
|
||||||
|
|
|
@ -97,6 +97,9 @@ nix build -o "$TEST_ROOT/result" flake1
|
||||||
|
|
||||||
nix build -o "$TEST_ROOT/result" "$flake1Dir"
|
nix build -o "$TEST_ROOT/result" "$flake1Dir"
|
||||||
nix build -o "$TEST_ROOT/result" "git+file://$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.
|
# Test explicit packages.default.
|
||||||
nix build -o "$TEST_ROOT/result" "$flake1Dir#default"
|
nix build -o "$TEST_ROOT/result" "$flake1Dir#default"
|
||||||
|
@ -106,6 +109,15 @@ 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" "$flake1Dir?ref=HEAD#default"
|
||||||
nix build -o "$TEST_ROOT/result" "git+file://$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.
|
||||||
|
(
|
||||||
|
# This `cd` should not be required and is indicative of aforementioned bug.
|
||||||
|
cd "$flake1Dir/.."
|
||||||
|
nix build -o "$TEST_ROOT/result" "git+file:./$(basename "$flake1Dir")"
|
||||||
|
)
|
||||||
|
|
||||||
# Check that store symlinks inside a flake are not interpreted as flakes.
|
# Check that store symlinks inside a flake are not interpreted as flakes.
|
||||||
nix build -o "$flake1Dir/result" "git+file://$flake1Dir"
|
nix build -o "$flake1Dir/result" "git+file://$flake1Dir"
|
||||||
nix path-info "$flake1Dir/result"
|
nix path-info "$flake1Dir/result"
|
||||||
|
|
|
@ -31,5 +31,14 @@ echo 456 > "$flake1Dir"/x.nix
|
||||||
|
|
||||||
[[ $(nix eval --json "$flake2Dir#x" --override-input flake1 "$TEST_ROOT/flake1") = 456 ]]
|
[[ $(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" |
|
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 ]]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue