mirror of
https://github.com/NixOS/nix
synced 2025-06-28 22:01:15 +02:00
Merge remote-tracking branch 'upstream/master' into source-path
This commit is contained in:
commit
cb2615cf47
148 changed files with 3908 additions and 1449 deletions
|
@ -125,6 +125,9 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
|||
follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end());
|
||||
input.follows = follows;
|
||||
} else {
|
||||
// Allow selecting a subset of enum values
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
switch (attr.value->type()) {
|
||||
case nString:
|
||||
attrs.emplace(state.symbols[attr.name], attr.value->string.s);
|
||||
|
@ -139,6 +142,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
|||
throw TypeError("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
|
||||
state.symbols[attr.name], showType(*attr.value));
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
} catch (Error & e) {
|
||||
e.addTrace(
|
||||
|
@ -334,10 +338,14 @@ LockedFlake lockFlake(
|
|||
}
|
||||
|
||||
try {
|
||||
if (!fetchSettings.allowDirty && lockFlags.referenceLockFilePath) {
|
||||
throw Error("reference lock file was provided, but the `allow-dirty` setting is set to false");
|
||||
}
|
||||
|
||||
// FIXME: symlink attack
|
||||
auto oldLockFile = LockFile::read(
|
||||
flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock");
|
||||
lockFlags.referenceLockFilePath.value_or(
|
||||
flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock"));
|
||||
|
||||
debug("old lock file: %s", oldLockFile);
|
||||
|
||||
|
@ -619,13 +627,20 @@ LockedFlake lockFlake(
|
|||
|
||||
debug("new lock file: %s", newLockFile);
|
||||
|
||||
auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
|
||||
auto sourcePath = topRef.input.getSourcePath();
|
||||
auto outputLockFilePath = sourcePath ? std::optional{*sourcePath + "/" + relPath} : std::nullopt;
|
||||
if (lockFlags.outputLockFilePath) {
|
||||
outputLockFilePath = lockFlags.outputLockFilePath;
|
||||
}
|
||||
|
||||
/* Check whether we need to / can write the new lock file. */
|
||||
if (!(newLockFile == oldLockFile)) {
|
||||
if (newLockFile != oldLockFile || lockFlags.outputLockFilePath) {
|
||||
|
||||
auto diff = LockFile::diff(oldLockFile, newLockFile);
|
||||
|
||||
if (lockFlags.writeLockFile) {
|
||||
if (auto sourcePath = topRef.input.getSourcePath()) {
|
||||
if (outputLockFilePath) {
|
||||
if (auto unlockedInput = newLockFile.isUnlocked()) {
|
||||
if (fetchSettings.warnDirty)
|
||||
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
||||
|
@ -633,25 +648,24 @@ LockedFlake lockFlake(
|
|||
if (!lockFlags.updateLockFile)
|
||||
throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
|
||||
|
||||
auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
|
||||
|
||||
auto path = *sourcePath + "/" + relPath;
|
||||
|
||||
bool lockFileExists = pathExists(path);
|
||||
bool lockFileExists = pathExists(*outputLockFilePath);
|
||||
|
||||
if (lockFileExists) {
|
||||
auto s = chomp(diff);
|
||||
if (s.empty())
|
||||
warn("updating lock file '%s'", path);
|
||||
warn("updating lock file '%s'", *outputLockFilePath);
|
||||
else
|
||||
warn("updating lock file '%s':\n%s", path, s);
|
||||
warn("updating lock file '%s':\n%s", *outputLockFilePath, s);
|
||||
} else
|
||||
warn("creating lock file '%s'", path);
|
||||
warn("creating lock file '%s'", *outputLockFilePath);
|
||||
|
||||
newLockFile.write(path);
|
||||
newLockFile.write(*outputLockFilePath);
|
||||
|
||||
std::optional<std::string> commitMessage = std::nullopt;
|
||||
if (lockFlags.commitLockFile) {
|
||||
if (lockFlags.outputLockFilePath) {
|
||||
throw Error("--commit-lock-file and --output-lock-file are currently incompatible");
|
||||
}
|
||||
std::string cm;
|
||||
|
||||
cm = fetchSettings.commitLockFileSummary.get();
|
||||
|
|
|
@ -18,7 +18,8 @@ struct FlakeInput;
|
|||
|
||||
typedef std::map<FlakeId, FlakeInput> FlakeInputs;
|
||||
|
||||
/* FlakeInput is the 'Flake'-level parsed form of the "input" entries
|
||||
/**
|
||||
* FlakeInput is the 'Flake'-level parsed form of the "input" entries
|
||||
* in the flake file.
|
||||
*
|
||||
* A FlakeInput is normally constructed by the 'parseFlakeInput'
|
||||
|
@ -42,7 +43,12 @@ typedef std::map<FlakeId, FlakeInput> FlakeInputs;
|
|||
struct FlakeInput
|
||||
{
|
||||
std::optional<FlakeRef> ref;
|
||||
bool isFlake = true; // true = process flake to get outputs, false = (fetched) static source path
|
||||
/**
|
||||
* true = process flake to get outputs
|
||||
*
|
||||
* false = (fetched) static source path
|
||||
*/
|
||||
bool isFlake = true;
|
||||
std::optional<InputPath> follows;
|
||||
FlakeInputs overrides;
|
||||
};
|
||||
|
@ -56,23 +62,42 @@ struct ConfigFile
|
|||
void apply();
|
||||
};
|
||||
|
||||
/* The contents of a flake.nix file. */
|
||||
/**
|
||||
* The contents of a flake.nix file.
|
||||
*/
|
||||
struct Flake
|
||||
{
|
||||
FlakeRef originalRef; // the original flake specification (by the user)
|
||||
FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake
|
||||
FlakeRef lockedRef; // the specific local store result of invoking the fetcher
|
||||
bool forceDirty = false; // pretend that 'lockedRef' is dirty
|
||||
/**
|
||||
* The original flake specification (by the user)
|
||||
*/
|
||||
FlakeRef originalRef;
|
||||
/**
|
||||
* registry references and caching resolved to the specific underlying flake
|
||||
*/
|
||||
FlakeRef resolvedRef;
|
||||
/**
|
||||
* the specific local store result of invoking the fetcher
|
||||
*/
|
||||
FlakeRef lockedRef;
|
||||
/**
|
||||
* pretend that 'lockedRef' is dirty
|
||||
*/
|
||||
bool forceDirty = false;
|
||||
std::optional<std::string> description;
|
||||
std::shared_ptr<const fetchers::Tree> sourceInfo;
|
||||
FlakeInputs inputs;
|
||||
ConfigFile config; // 'nixConfig' attribute
|
||||
/**
|
||||
* 'nixConfig' attribute
|
||||
*/
|
||||
ConfigFile config;
|
||||
~Flake();
|
||||
};
|
||||
|
||||
Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool allowLookup);
|
||||
|
||||
/* Fingerprint of a locked flake; used as a cache key. */
|
||||
/**
|
||||
* Fingerprint of a locked flake; used as a cache key.
|
||||
*/
|
||||
typedef Hash Fingerprint;
|
||||
|
||||
struct LockedFlake
|
||||
|
@ -85,44 +110,72 @@ struct LockedFlake
|
|||
|
||||
struct LockFlags
|
||||
{
|
||||
/* Whether to ignore the existing lock file, creating a new one
|
||||
from scratch. */
|
||||
/**
|
||||
* Whether to ignore the existing lock file, creating a new one
|
||||
* from scratch.
|
||||
*/
|
||||
bool recreateLockFile = false;
|
||||
|
||||
/* Whether to update the lock file at all. If set to false, if any
|
||||
change to the lock file is needed (e.g. when an input has been
|
||||
added to flake.nix), you get a fatal error. */
|
||||
/**
|
||||
* Whether to update the lock file at all. If set to false, if any
|
||||
* change to the lock file is needed (e.g. when an input has been
|
||||
* added to flake.nix), you get a fatal error.
|
||||
*/
|
||||
bool updateLockFile = true;
|
||||
|
||||
/* Whether to write the lock file to disk. If set to true, if the
|
||||
any changes to the lock file are needed and the flake is not
|
||||
writable (i.e. is not a local Git working tree or similar), you
|
||||
get a fatal error. If set to false, Nix will use the modified
|
||||
lock file in memory only, without writing it to disk. */
|
||||
/**
|
||||
* Whether to write the lock file to disk. If set to true, if the
|
||||
* any changes to the lock file are needed and the flake is not
|
||||
* writable (i.e. is not a local Git working tree or similar), you
|
||||
* get a fatal error. If set to false, Nix will use the modified
|
||||
* lock file in memory only, without writing it to disk.
|
||||
*/
|
||||
bool writeLockFile = true;
|
||||
|
||||
/* Whether to use the registries to lookup indirect flake
|
||||
references like 'nixpkgs'. */
|
||||
/**
|
||||
* Whether to use the registries to lookup indirect flake
|
||||
* references like 'nixpkgs'.
|
||||
*/
|
||||
std::optional<bool> useRegistries = std::nullopt;
|
||||
|
||||
/* Whether to apply flake's nixConfig attribute to the configuration */
|
||||
/**
|
||||
* Whether to apply flake's nixConfig attribute to the configuration
|
||||
*/
|
||||
|
||||
bool applyNixConfig = false;
|
||||
|
||||
/* Whether unlocked flake references (i.e. those without a Git
|
||||
revision or similar) without a corresponding lock are
|
||||
allowed. Unlocked flake references with a lock are always
|
||||
allowed. */
|
||||
/**
|
||||
* Whether unlocked flake references (i.e. those without a Git
|
||||
* revision or similar) without a corresponding lock are
|
||||
* allowed. Unlocked flake references with a lock are always
|
||||
* allowed.
|
||||
*/
|
||||
bool allowUnlocked = true;
|
||||
|
||||
/* Whether to commit changes to flake.lock. */
|
||||
/**
|
||||
* Whether to commit changes to flake.lock.
|
||||
*/
|
||||
bool commitLockFile = false;
|
||||
|
||||
/* Flake inputs to be overridden. */
|
||||
/**
|
||||
* The path to a lock file to read instead of the `flake.lock` file in the top-level flake
|
||||
*/
|
||||
std::optional<std::string> referenceLockFilePath;
|
||||
|
||||
/**
|
||||
* The path to a lock file to write to instead of the `flake.lock` file in the top-level flake
|
||||
*/
|
||||
std::optional<Path> outputLockFilePath;
|
||||
|
||||
/**
|
||||
* Flake inputs to be overridden.
|
||||
*/
|
||||
std::map<InputPath, FlakeRef> inputOverrides;
|
||||
|
||||
/* Flake inputs to be updated. This means that any existing lock
|
||||
for those inputs will be ignored. */
|
||||
/**
|
||||
* Flake inputs to be updated. This means that any existing lock
|
||||
* for those inputs will be ignored.
|
||||
*/
|
||||
std::set<InputPath> inputUpdates;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ class Store;
|
|||
|
||||
typedef std::string FlakeId;
|
||||
|
||||
/* A flake reference specifies how to fetch a flake or raw source
|
||||
/**
|
||||
* A flake reference specifies how to fetch a flake or raw source
|
||||
* (e.g. from a Git repository). It is created from a URL-like syntax
|
||||
* (e.g. 'github:NixOS/patchelf'), an attrset representation (e.g. '{
|
||||
* type="github"; owner = "NixOS"; repo = "patchelf"; }'), or a local
|
||||
|
@ -33,14 +34,17 @@ typedef std::string FlakeId;
|
|||
* be lazy), but the fetcher can be invoked at any time via the
|
||||
* FlakeRef to ensure the store is populated with this input.
|
||||
*/
|
||||
|
||||
struct FlakeRef
|
||||
{
|
||||
/* Fetcher-specific representation of the input, sufficient to
|
||||
perform the fetch operation. */
|
||||
/**
|
||||
* Fetcher-specific representation of the input, sufficient to
|
||||
* perform the fetch operation.
|
||||
*/
|
||||
fetchers::Input input;
|
||||
|
||||
/* sub-path within the fetched input that represents this input */
|
||||
/**
|
||||
* sub-path within the fetched input that represents this input
|
||||
*/
|
||||
Path subdir;
|
||||
|
||||
bool operator==(const FlakeRef & other) const;
|
||||
|
|
|
@ -234,6 +234,11 @@ bool LockFile::operator ==(const LockFile & other) const
|
|||
return toJSON() == other.toJSON();
|
||||
}
|
||||
|
||||
bool LockFile::operator !=(const LockFile & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
InputPath parseInputPath(std::string_view s)
|
||||
{
|
||||
InputPath path;
|
||||
|
|
|
@ -16,9 +16,11 @@ typedef std::vector<FlakeId> InputPath;
|
|||
|
||||
struct LockedNode;
|
||||
|
||||
/* A node in the lock file. It has outgoing edges to other nodes (its
|
||||
inputs). Only the root node has this type; all other nodes have
|
||||
type LockedNode. */
|
||||
/**
|
||||
* A node in the lock file. It has outgoing edges to other nodes (its
|
||||
* inputs). Only the root node has this type; all other nodes have
|
||||
* type LockedNode.
|
||||
*/
|
||||
struct Node : std::enable_shared_from_this<Node>
|
||||
{
|
||||
typedef std::variant<ref<LockedNode>, InputPath> Edge;
|
||||
|
@ -28,7 +30,9 @@ struct Node : std::enable_shared_from_this<Node>
|
|||
virtual ~Node() { }
|
||||
};
|
||||
|
||||
/* A non-root node in the lock file. */
|
||||
/**
|
||||
* A non-root node in the lock file.
|
||||
*/
|
||||
struct LockedNode : Node
|
||||
{
|
||||
FlakeRef lockedRef, originalRef;
|
||||
|
@ -63,10 +67,15 @@ struct LockFile
|
|||
|
||||
void write(const Path & path) const;
|
||||
|
||||
/* Check whether this lock file has any unlocked inputs. */
|
||||
/**
|
||||
* Check whether this lock file has any unlocked inputs.
|
||||
*/
|
||||
std::optional<FlakeRef> isUnlocked() const;
|
||||
|
||||
bool operator ==(const LockFile & other) const;
|
||||
// Needed for old gcc versions that don't synthesize it (like gcc 8.2.2
|
||||
// that is still the default on aarch64-linux)
|
||||
bool operator !=(const LockFile & other) const;
|
||||
|
||||
std::shared_ptr<Node> findInput(const InputPath & path);
|
||||
|
||||
|
@ -74,7 +83,9 @@ struct LockFile
|
|||
|
||||
static std::string diff(const LockFile & oldLocks, const LockFile & newLocks);
|
||||
|
||||
/* Check that every 'follows' input target exists. */
|
||||
/**
|
||||
* Check that every 'follows' input target exists.
|
||||
*/
|
||||
void check();
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue