mirror of
https://github.com/NixOS/nix.git
synced 2025-11-23 18:59:35 +01:00
Merge commit '6636202356' into progress-bar
This commit is contained in:
commit
5109b5e467
81 changed files with 870 additions and 590 deletions
|
|
@ -14,9 +14,27 @@ if [ -t 1 ]; then
|
|||
yellow="[33;1m"
|
||||
normal="[m"
|
||||
fi
|
||||
|
||||
run_test () {
|
||||
(cd tests && env ${TESTS_ENVIRONMENT} init.sh 2>/dev/null > /dev/null)
|
||||
log="$(cd $(dirname $1) && env ${TESTS_ENVIRONMENT} $(basename $1) 2>&1)"
|
||||
status=$?
|
||||
}
|
||||
|
||||
run_test "$1"
|
||||
|
||||
# Hack: Retry the test if it fails with “unexpected EOF reading a line” as these
|
||||
# appear randomly without anyone knowing why.
|
||||
# See https://github.com/NixOS/nix/issues/3605 for more info
|
||||
if [[ $status -ne 0 && $status -ne 99 && \
|
||||
"$(uname)" == "Darwin" && \
|
||||
"$log" =~ "unexpected EOF reading a line" \
|
||||
]]; then
|
||||
echo "$post_run_msg [${yellow}FAIL$normal] (possibly flaky, so will be retried)"
|
||||
echo "$log" | sed 's/^/ /'
|
||||
run_test "$1"
|
||||
fi
|
||||
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "$post_run_msg [${green}PASS$normal]"
|
||||
elif [ $status -eq 99 ]; then
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ get_volume_pass() {
|
|||
verify_volume_pass() {
|
||||
local volume_special="$1" # (i.e., disk1s7)
|
||||
local volume_uuid="$2"
|
||||
_sudo "to confirm the password actually unlocks the volume" \
|
||||
/usr/sbin/diskutil apfs unlockVolume "$volume_special" -verify -stdinpassphrase -user "$volume_uuid"
|
||||
}
|
||||
|
||||
|
|
@ -685,11 +686,15 @@ encrypt_volume() {
|
|||
local volume_uuid="$1"
|
||||
local volume_label="$2"
|
||||
local password
|
||||
|
||||
task "Encrypt the Nix volume" >&2
|
||||
|
||||
# Note: mount/unmount are late additions to support the right order
|
||||
# of operations for creating the volume and then baking its uuid into
|
||||
# other artifacts; not as well-trod wrt to potential errors, race
|
||||
# conditions, etc.
|
||||
|
||||
_sudo "to mount your Nix volume for encrypting" \
|
||||
/usr/sbin/diskutil mount "$volume_label"
|
||||
|
||||
password="$(/usr/bin/xxd -l 32 -p -c 256 /dev/random)"
|
||||
|
|
@ -697,9 +702,10 @@ encrypt_volume() {
|
|||
/usr/bin/security -i <<EOF
|
||||
add-generic-password -a "$volume_label" -s "$volume_uuid" -l "$volume_label encryption password" -D "Encrypted volume password" -j "Added automatically by the Nix installer for use by $NIX_VOLUME_MOUNTD_DEST" -w "$password" -T /System/Library/CoreServices/APFSUserAgent -T /System/Library/CoreServices/CSUserAgent -T /usr/bin/security "/Library/Keychains/System.keychain"
|
||||
EOF
|
||||
builtin printf "%s" "$password" | _sudo "to encrypt your Nix volume" \
|
||||
builtin printf "%s" "$password" | _sudo "to actually encrypt your Nix volume" \
|
||||
/usr/sbin/diskutil apfs encryptVolume "$volume_label" -user disk -stdinpassphrase
|
||||
|
||||
_sudo "to unmount the encrypted volume" \
|
||||
/usr/sbin/diskutil unmount force "$volume_label"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ readonly RED='\033[31m'
|
|||
# installer allows overriding build user count to speed up installation
|
||||
# as creating each user takes non-trivial amount of time on macos
|
||||
readonly NIX_USER_COUNT=${NIX_USER_COUNT:-32}
|
||||
readonly NIX_BUILD_GROUP_ID="30000"
|
||||
readonly NIX_BUILD_GROUP_ID="${NIX_BUILD_GROUP_ID:-30000}"
|
||||
readonly NIX_BUILD_GROUP_NAME="nixbld"
|
||||
# darwin installer needs to override these
|
||||
NIX_FIRST_BUILD_UID="30001"
|
||||
NIX_FIRST_BUILD_UID="${NIX_FIRST_BUILD_UID:-30001}"
|
||||
NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d"
|
||||
# Please don't change this. We don't support it, because the
|
||||
# default shell profile that comes with Nix doesn't support it.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "pathlocks.hh"
|
||||
#include "globals.hh"
|
||||
#include "serialise.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-api.hh"
|
||||
#include "derivations.hh"
|
||||
#include "local-store.hh"
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ void BuiltPathsCommand::run(ref<Store> store)
|
|||
for (auto & p : store->queryAllValidPaths())
|
||||
paths.push_back(BuiltPath::Opaque{p});
|
||||
} else {
|
||||
paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
if (recursive) {
|
||||
// XXX: This only computes the store path closure, ignoring
|
||||
// intermediate realisations
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include "common-eval-args.hh"
|
||||
#include "path.hh"
|
||||
#include "flake/lockfile.hh"
|
||||
#include "store-api.hh"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -82,14 +81,6 @@ struct MixFlakeOptions : virtual Args, EvalCommand
|
|||
{ return {}; }
|
||||
};
|
||||
|
||||
/* How to handle derivations in commands that operate on store paths. */
|
||||
enum class OperateOn {
|
||||
/* Operate on the output path. */
|
||||
Output,
|
||||
/* Operate on the .drv path. */
|
||||
Derivation
|
||||
};
|
||||
|
||||
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||
{
|
||||
std::optional<Path> file;
|
||||
|
|
@ -113,19 +104,6 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
|
|||
void completeInstallable(std::string_view prefix);
|
||||
};
|
||||
|
||||
enum class Realise {
|
||||
/* Build the derivation. Postcondition: the
|
||||
derivation outputs exist. */
|
||||
Outputs,
|
||||
/* Don't build the derivation. Postcondition: the store derivation
|
||||
exists. */
|
||||
Derivation,
|
||||
/* Evaluate in dry-run mode. Postcondition: nothing. */
|
||||
// FIXME: currently unused, but could be revived if we can
|
||||
// evaluate derivations in-memory.
|
||||
Nothing
|
||||
};
|
||||
|
||||
/* A command that operates on a list of "installables", which can be
|
||||
store paths, attribute paths, Nix expressions, etc. */
|
||||
struct InstallablesCommand : virtual Args, SourceExprCommand
|
||||
|
|
@ -238,38 +216,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
|
|||
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
||||
}
|
||||
|
||||
BuiltPaths build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store, Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
std::set<StorePath> toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
StorePath toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
std::shared_ptr<Installable> installable);
|
||||
|
||||
std::set<StorePath> toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver = false);
|
||||
|
||||
BuiltPaths toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
/* Helper function to generate args that invoke $EDITOR on
|
||||
filename:lineno. */
|
||||
Strings editorFor(const Pos & pos);
|
||||
|
|
|
|||
|
|
@ -468,11 +468,10 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations
|
|||
|
||||
std::vector<DerivationInfo> res;
|
||||
for (auto & drvInfo : drvInfos) {
|
||||
res.push_back({
|
||||
state->store->parseStorePath(drvInfo.queryDrvPath()),
|
||||
state->store->maybeParseStorePath(drvInfo.queryOutPath()),
|
||||
drvInfo.queryOutputName()
|
||||
});
|
||||
auto drvPath = drvInfo.queryDrvPath();
|
||||
if (!drvPath)
|
||||
throw Error("'%s' is not a derivation", what());
|
||||
res.push_back({ *drvPath, drvInfo.queryOutputName() });
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
@ -588,7 +587,6 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
|||
|
||||
auto drvInfo = DerivationInfo {
|
||||
std::move(drvPath),
|
||||
state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()),
|
||||
attr->getAttr(state->sOutputName)->getString()
|
||||
};
|
||||
|
||||
|
|
@ -789,7 +787,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
|
|||
return res;
|
||||
}
|
||||
|
||||
BuiltPaths build(
|
||||
BuiltPaths Installable::build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
|
|
@ -814,7 +812,7 @@ BuiltPaths build(
|
|||
return getBuiltPaths(evalStore, store, pathsToBuild);
|
||||
}
|
||||
|
||||
BuiltPaths toBuiltPaths(
|
||||
BuiltPaths Installable::toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
|
|
@ -822,19 +820,19 @@ BuiltPaths toBuiltPaths(
|
|||
const std::vector<std::shared_ptr<Installable>> & installables)
|
||||
{
|
||||
if (operateOn == OperateOn::Output)
|
||||
return build(evalStore, store, mode, installables);
|
||||
return Installable::build(evalStore, store, mode, installables);
|
||||
else {
|
||||
if (mode == Realise::Nothing)
|
||||
settings.readOnlyMode = true;
|
||||
|
||||
BuiltPaths res;
|
||||
for (auto & drvPath : toDerivations(store, installables, true))
|
||||
for (auto & drvPath : Installable::toDerivations(store, installables, true))
|
||||
res.push_back(BuiltPath::Opaque{drvPath});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
StorePathSet toStorePaths(
|
||||
StorePathSet Installable::toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
|
|
@ -848,7 +846,7 @@ StorePathSet toStorePaths(
|
|||
return outPaths;
|
||||
}
|
||||
|
||||
StorePath toStorePath(
|
||||
StorePath Installable::toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
|
|
@ -862,7 +860,7 @@ StorePath toStorePath(
|
|||
return *paths.begin();
|
||||
}
|
||||
|
||||
StorePathSet toDerivations(
|
||||
StorePathSet Installable::toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "path-with-outputs.hh"
|
||||
#include "derived-path.hh"
|
||||
#include "eval.hh"
|
||||
#include "store-api.hh"
|
||||
#include "flake/flake.hh"
|
||||
|
||||
#include <optional>
|
||||
|
|
@ -29,6 +30,27 @@ struct UnresolvedApp
|
|||
App resolve(ref<Store> evalStore, ref<Store> store);
|
||||
};
|
||||
|
||||
enum class Realise {
|
||||
/* Build the derivation. Postcondition: the
|
||||
derivation outputs exist. */
|
||||
Outputs,
|
||||
/* Don't build the derivation. Postcondition: the store derivation
|
||||
exists. */
|
||||
Derivation,
|
||||
/* Evaluate in dry-run mode. Postcondition: nothing. */
|
||||
// FIXME: currently unused, but could be revived if we can
|
||||
// evaluate derivations in-memory.
|
||||
Nothing
|
||||
};
|
||||
|
||||
/* How to handle derivations in commands that operate on store paths. */
|
||||
enum class OperateOn {
|
||||
/* Operate on the output path. */
|
||||
Output,
|
||||
/* Operate on the .drv path. */
|
||||
Derivation
|
||||
};
|
||||
|
||||
struct Installable
|
||||
{
|
||||
virtual ~Installable() { }
|
||||
|
|
@ -68,6 +90,39 @@ struct Installable
|
|||
{
|
||||
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
|
||||
}
|
||||
|
||||
static BuiltPaths build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
static std::set<StorePath> toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
static StorePath toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
std::shared_ptr<Installable> installable);
|
||||
|
||||
static std::set<StorePath> toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver = false);
|
||||
|
||||
static BuiltPaths toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
};
|
||||
|
||||
struct InstallableValue : Installable
|
||||
|
|
@ -79,7 +134,6 @@ struct InstallableValue : Installable
|
|||
struct DerivationInfo
|
||||
{
|
||||
StorePath drvPath;
|
||||
std::optional<StorePath> outPath;
|
||||
std::string outputName;
|
||||
};
|
||||
|
||||
|
|
@ -131,4 +185,9 @@ ref<eval_cache::EvalCache> openEvalCache(
|
|||
EvalState & state,
|
||||
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
||||
|
||||
BuiltPaths getBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
const DerivedPaths & hopefullyBuiltPaths);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,15 +86,10 @@ RootValue allocRootValue(Value * v)
|
|||
}
|
||||
|
||||
|
||||
void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
|
||||
void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
if (!active.insert(&v).second) {
|
||||
str << "<CYCLE>";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (v.internalType) {
|
||||
case tInt:
|
||||
str << v.integer;
|
||||
|
|
@ -120,24 +115,32 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
|
|||
str << "null";
|
||||
break;
|
||||
case tAttrs: {
|
||||
if (!v.attrs->empty() && !seen.insert(v.attrs).second)
|
||||
str << "<REPEAT>";
|
||||
else {
|
||||
str << "{ ";
|
||||
for (auto & i : v.attrs->lexicographicOrder()) {
|
||||
str << i->name << " = ";
|
||||
printValue(str, active, *i->value);
|
||||
printValue(str, seen, *i->value);
|
||||
str << "; ";
|
||||
}
|
||||
str << "}";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tList1:
|
||||
case tList2:
|
||||
case tListN:
|
||||
if (v.listSize() && !seen.insert(v.listElems()).second)
|
||||
str << "<REPEAT>";
|
||||
else {
|
||||
str << "[ ";
|
||||
for (auto v2 : v.listItems()) {
|
||||
printValue(str, active, *v2);
|
||||
printValue(str, seen, *v2);
|
||||
str << " ";
|
||||
}
|
||||
str << "]";
|
||||
}
|
||||
break;
|
||||
case tThunk:
|
||||
case tApp:
|
||||
|
|
@ -161,15 +164,13 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
|
|||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
active.erase(&v);
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Value & v)
|
||||
{
|
||||
std::set<const Value *> active;
|
||||
printValue(str, active, v);
|
||||
std::set<const void *> seen;
|
||||
printValue(str, seen, v);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
@ -517,6 +518,14 @@ void EvalState::allowPath(const StorePath & storePath)
|
|||
allowedPaths->insert(store->toRealPath(storePath));
|
||||
}
|
||||
|
||||
void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v)
|
||||
{
|
||||
allowPath(storePath);
|
||||
|
||||
auto path = store->printStorePath(storePath);
|
||||
v.mkString(path, PathSet({path}));
|
||||
}
|
||||
|
||||
Path EvalState::checkSourcePath(const Path & path_)
|
||||
{
|
||||
if (!allowedPaths) return path_;
|
||||
|
|
@ -2050,6 +2059,18 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
|
|||
}
|
||||
|
||||
|
||||
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context)
|
||||
{
|
||||
auto path = coerceToString(pos, v, context, false, false).toOwned();
|
||||
if (auto storePath = store->maybeParseStorePath(path))
|
||||
return *storePath;
|
||||
throw EvalError({
|
||||
.msg = hintfmt("path '%1%' is not in the Nix store", path),
|
||||
.errPos = pos
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool EvalState::eqValues(Value & v1, Value & v2)
|
||||
{
|
||||
forceValue(v1, noPos);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,9 @@ public:
|
|||
the real store path if `store` is a chroot store. */
|
||||
void allowPath(const StorePath & storePath);
|
||||
|
||||
/* Allow access to a store path and return it as a string. */
|
||||
void allowAndSetStorePathString(const StorePath & storePath, Value & v);
|
||||
|
||||
/* Check whether access to a path is allowed and throw an error if
|
||||
not. Otherwise return the canonicalised path. */
|
||||
Path checkSourcePath(const Path & path);
|
||||
|
|
@ -269,6 +272,9 @@ public:
|
|||
path. Nothing is copied to the store. */
|
||||
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
|
||||
|
||||
/* Like coerceToPath, but the result must be a store path. */
|
||||
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
|
||||
|
||||
public:
|
||||
|
||||
/* The base environment, containing the builtin functions and
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "flake.hh"
|
||||
#include "globals.hh"
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ void ConfigFile::apply()
|
|||
auto trustedList = readTrustedList();
|
||||
|
||||
bool trusted = false;
|
||||
if (nix::settings.acceptFlakeConfig){
|
||||
if (nix::fetchSettings.acceptFlakeConfig){
|
||||
trusted = true;
|
||||
} else if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
|
||||
trusted = *saved;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "store-api.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "finally.hh"
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
@ -317,7 +318,7 @@ LockedFlake lockFlake(
|
|||
|
||||
FlakeCache flakeCache;
|
||||
|
||||
auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries);
|
||||
auto useRegistries = lockFlags.useRegistries.value_or(fetchSettings.useRegistries);
|
||||
|
||||
auto flake = getFlake(state, topRef, useRegistries, flakeCache);
|
||||
|
||||
|
|
@ -593,7 +594,7 @@ LockedFlake lockFlake(
|
|||
if (lockFlags.writeLockFile) {
|
||||
if (auto sourcePath = topRef.input.getSourcePath()) {
|
||||
if (!newLockFile.isImmutable()) {
|
||||
if (settings.warnDirty)
|
||||
if (fetchSettings.warnDirty)
|
||||
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
|
||||
} else {
|
||||
if (!lockFlags.updateLockFile)
|
||||
|
|
@ -620,7 +621,7 @@ LockedFlake lockFlake(
|
|||
if (lockFlags.commitLockFile) {
|
||||
std::string cm;
|
||||
|
||||
cm = settings.commitLockFileSummary.get();
|
||||
cm = fetchSettings.commitLockFileSummary.get();
|
||||
|
||||
if (cm == "") {
|
||||
cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add");
|
||||
|
|
@ -718,7 +719,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
lockFlake(state, flakeRef,
|
||||
LockFlags {
|
||||
.updateLockFile = false,
|
||||
.useRegistries = !evalSettings.pureEval && settings.useRegistries,
|
||||
.useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries,
|
||||
.allowMutable = !evalSettings.pureEval,
|
||||
}),
|
||||
v);
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
|
|||
if (std::regex_match(url, match, flakeRegex)) {
|
||||
auto parsedURL = ParsedURL{
|
||||
.url = url,
|
||||
.base = "flake:" + std::string(match[1]),
|
||||
.base = "flake:" + match.str(1),
|
||||
.scheme = "flake",
|
||||
.authority = "",
|
||||
.path = match[1],
|
||||
|
|
@ -106,12 +106,12 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
|
|||
|
||||
return std::make_pair(
|
||||
FlakeRef(Input::fromURL(parsedURL), ""),
|
||||
percentDecode(std::string(match[6])));
|
||||
percentDecode(match.str(6)));
|
||||
}
|
||||
|
||||
else if (std::regex_match(url, match, pathUrlRegex)) {
|
||||
std::string path = match[1];
|
||||
std::string fragment = percentDecode(std::string(match[3]));
|
||||
std::string fragment = percentDecode(match.str(3));
|
||||
|
||||
if (baseDir) {
|
||||
/* Check if 'url' is a path (either absolute or relative
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
|
|||
{
|
||||
auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs);
|
||||
|
||||
this->drvPath = store->printStorePath(drvPath);
|
||||
this->drvPath = drvPath;
|
||||
|
||||
auto drv = store->derivationFromPath(drvPath);
|
||||
|
||||
|
|
@ -41,9 +41,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
|
|||
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
|
||||
auto & [outputName, output] = *i;
|
||||
|
||||
auto optStorePath = output.path(*store, drv.name, outputName);
|
||||
if (optStorePath)
|
||||
outPath = store->printStorePath(*optStorePath);
|
||||
outPath = {output.path(*store, drv.name, outputName)};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -68,24 +66,35 @@ std::string DrvInfo::querySystem() const
|
|||
}
|
||||
|
||||
|
||||
std::string DrvInfo::queryDrvPath() const
|
||||
std::optional<StorePath> DrvInfo::queryDrvPath() const
|
||||
{
|
||||
if (drvPath == "" && attrs) {
|
||||
if (!drvPath && attrs) {
|
||||
Bindings::iterator i = attrs->find(state->sDrvPath);
|
||||
PathSet context;
|
||||
drvPath = i != attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "";
|
||||
if (i == attrs->end())
|
||||
drvPath = {std::nullopt};
|
||||
else
|
||||
drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)};
|
||||
}
|
||||
return drvPath;
|
||||
return drvPath.value_or(std::nullopt);
|
||||
}
|
||||
|
||||
|
||||
std::string DrvInfo::queryOutPath() const
|
||||
StorePath DrvInfo::requireDrvPath() const
|
||||
{
|
||||
if (auto drvPath = queryDrvPath())
|
||||
return *drvPath;
|
||||
throw Error("derivation does not contain a 'drvPath' attribute");
|
||||
}
|
||||
|
||||
|
||||
StorePath DrvInfo::queryOutPath() const
|
||||
{
|
||||
if (!outPath && attrs) {
|
||||
Bindings::iterator i = attrs->find(state->sOutPath);
|
||||
PathSet context;
|
||||
if (i != attrs->end())
|
||||
outPath = state->coerceToPath(*i->pos, *i->value, context);
|
||||
outPath = state->coerceToStorePath(*i->pos, *i->value, context);
|
||||
}
|
||||
if (!outPath)
|
||||
throw UnimplementedError("CA derivations are not yet supported");
|
||||
|
|
@ -113,10 +122,10 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
|||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
||||
PathSet context;
|
||||
outputs[name] = state->coerceToPath(*outPath->pos, *outPath->value, context);
|
||||
outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
|
||||
}
|
||||
} else
|
||||
outputs["out"] = queryOutPath();
|
||||
outputs.emplace("out", queryOutPath());
|
||||
}
|
||||
if (!onlyOutputsToInstall || !attrs)
|
||||
return outputs;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "eval.hh"
|
||||
#include "path.hh"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
|
@ -12,15 +13,15 @@ namespace nix {
|
|||
struct DrvInfo
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, Path> Outputs;
|
||||
typedef std::map<std::string, StorePath> Outputs;
|
||||
|
||||
private:
|
||||
EvalState * state;
|
||||
|
||||
mutable std::string name;
|
||||
mutable std::string system;
|
||||
mutable std::string drvPath;
|
||||
mutable std::optional<std::string> outPath;
|
||||
mutable std::optional<std::optional<StorePath>> drvPath;
|
||||
mutable std::optional<StorePath> outPath;
|
||||
mutable std::string outputName;
|
||||
Outputs outputs;
|
||||
|
||||
|
|
@ -41,8 +42,9 @@ public:
|
|||
|
||||
std::string queryName() const;
|
||||
std::string querySystem() const;
|
||||
std::string queryDrvPath() const;
|
||||
std::string queryOutPath() const;
|
||||
std::optional<StorePath> queryDrvPath() const;
|
||||
StorePath requireDrvPath() const;
|
||||
StorePath queryOutPath() const;
|
||||
std::string queryOutputName() const;
|
||||
/** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */
|
||||
Outputs queryOutputs(bool onlyOutputsToInstall = false);
|
||||
|
|
@ -61,8 +63,8 @@ public:
|
|||
*/
|
||||
|
||||
void setName(const std::string & s) { name = s; }
|
||||
void setDrvPath(const std::string & s) { drvPath = s; }
|
||||
void setOutPath(const std::string & s) { outPath = s; }
|
||||
void setDrvPath(StorePath path) { drvPath = {{std::move(path)}}; }
|
||||
void setOutPath(StorePath path) { outPath = {{std::move(path)}}; }
|
||||
|
||||
void setFailed() { failed = true; };
|
||||
bool hasFailed() { return failed; };
|
||||
|
|
|
|||
|
|
@ -1919,20 +1919,15 @@ static void addPath(
|
|||
if (expectedHash)
|
||||
expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name);
|
||||
|
||||
Path dstPath;
|
||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||
dstPath = state.store->printStorePath(settings.readOnlyMode
|
||||
StorePath dstPath = settings.readOnlyMode
|
||||
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
|
||||
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs));
|
||||
if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath))
|
||||
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs);
|
||||
if (expectedHash && expectedStorePath != dstPath)
|
||||
throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
|
||||
state.allowAndSetStorePathString(dstPath, v);
|
||||
} else
|
||||
dstPath = state.store->printStorePath(*expectedStorePath);
|
||||
|
||||
v.mkString(dstPath, {dstPath});
|
||||
|
||||
state.allowPath(dstPath);
|
||||
|
||||
state.allowAndSetStorePathString(*expectedStorePath, v);
|
||||
} catch (Error & e) {
|
||||
e.addTrace(pos, "while adding path '%s'", path);
|
||||
throw;
|
||||
|
|
|
|||
|
|
@ -230,6 +230,21 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
|||
if (evalSettings.pureEval && !expectedHash)
|
||||
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
|
||||
|
||||
// early exit if pinned and already in the store
|
||||
if (expectedHash && expectedHash->type == htSHA256) {
|
||||
auto expectedPath =
|
||||
unpack
|
||||
? state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {})
|
||||
: state.store->makeFixedOutputPath(FileIngestionMethod::Flat, *expectedHash, name, {});
|
||||
|
||||
if (state.store->isValidPath(expectedPath)) {
|
||||
state.allowAndSetStorePathString(expectedPath, v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fetching may fail, yet the path may be substitutable.
|
||||
// https://github.com/NixOS/nix/issues/4313
|
||||
auto storePath =
|
||||
unpack
|
||||
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath
|
||||
|
|
@ -244,10 +259,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
|||
*url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true));
|
||||
}
|
||||
|
||||
state.allowPath(storePath);
|
||||
|
||||
auto path = state.store->printStorePath(storePath);
|
||||
v.mkString(path, PathSet({path}));
|
||||
state.allowAndSetStorePathString(storePath, v);
|
||||
}
|
||||
|
||||
static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ private:
|
|||
InternalType internalType;
|
||||
|
||||
friend std::string showType(const Value & v);
|
||||
friend void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v);
|
||||
friend void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
13
src/libfetchers/fetch-settings.cc
Normal file
13
src/libfetchers/fetch-settings.cc
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "fetch-settings.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
FetchSettings::FetchSettings()
|
||||
{
|
||||
}
|
||||
|
||||
FetchSettings fetchSettings;
|
||||
|
||||
static GlobalConfig::Register rFetchSettings(&fetchSettings);
|
||||
|
||||
}
|
||||
93
src/libfetchers/fetch-settings.hh
Normal file
93
src/libfetchers/fetch-settings.hh
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.hh"
|
||||
#include "config.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include <map>
|
||||
#include <limits>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct FetchSettings : public Config
|
||||
{
|
||||
FetchSettings();
|
||||
|
||||
Setting<StringMap> accessTokens{this, {}, "access-tokens",
|
||||
R"(
|
||||
Access tokens used to access protected GitHub, GitLab, or
|
||||
other locations requiring token-based authentication.
|
||||
|
||||
Access tokens are specified as a string made up of
|
||||
space-separated `host=token` values. The specific token
|
||||
used is selected by matching the `host` portion against the
|
||||
"host" specification of the input. The actual use of the
|
||||
`token` value is determined by the type of resource being
|
||||
accessed:
|
||||
|
||||
* Github: the token value is the OAUTH-TOKEN string obtained
|
||||
as the Personal Access Token from the Github server (see
|
||||
https://docs.github.com/en/developers/apps/authorizing-oath-apps).
|
||||
|
||||
* Gitlab: the token value is either the OAuth2 token or the
|
||||
Personal Access Token (these are different types tokens
|
||||
for gitlab, see
|
||||
https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
|
||||
The `token` value should be `type:tokenstring` where
|
||||
`type` is either `OAuth2` or `PAT` to indicate which type
|
||||
of token is being specified.
|
||||
|
||||
Example `~/.config/nix/nix.conf`:
|
||||
|
||||
```
|
||||
access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
|
||||
```
|
||||
|
||||
Example `~/code/flake.nix`:
|
||||
|
||||
```nix
|
||||
input.foo = {
|
||||
type = "gitlab";
|
||||
host = "gitlab.mycompany.com";
|
||||
owner = "mycompany";
|
||||
repo = "pro";
|
||||
};
|
||||
```
|
||||
|
||||
This example specifies three tokens, one each for accessing
|
||||
github.com, gitlab.mycompany.com, and sourceforge.net.
|
||||
|
||||
The `input.foo` uses the "gitlab" fetcher, which might
|
||||
requires specifying the token type along with the token
|
||||
value.
|
||||
)"};
|
||||
|
||||
Setting<bool> allowDirty{this, true, "allow-dirty",
|
||||
"Whether to allow dirty Git/Mercurial trees."};
|
||||
|
||||
Setting<bool> warnDirty{this, true, "warn-dirty",
|
||||
"Whether to warn about dirty Git/Mercurial trees."};
|
||||
|
||||
Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
|
||||
"Path or URI of the global flake registry."};
|
||||
|
||||
Setting<bool> useRegistries{this, true, "use-registries",
|
||||
"Whether to use flake registries to resolve flake references."};
|
||||
|
||||
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
|
||||
"Whether to accept nix configuration from a flake without prompting."};
|
||||
|
||||
Setting<std::string> commitLockFileSummary{
|
||||
this, "", "commit-lockfile-summary",
|
||||
R"(
|
||||
The commit summary to use when committing changed flake lock files. If
|
||||
empty, the summary is generated based on the action performed.
|
||||
)"};
|
||||
};
|
||||
|
||||
// FIXME: don't use a global variable.
|
||||
extern FetchSettings fetchSettings;
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@
|
|||
#include "url-parts.hh"
|
||||
#include "pathlocks.hh"
|
||||
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
|
@ -246,10 +248,10 @@ struct GitInputScheme : InputScheme
|
|||
|
||||
/* This is an unclean working tree. So copy all tracked files. */
|
||||
|
||||
if (!settings.allowDirty)
|
||||
if (!fetchSettings.allowDirty)
|
||||
throw Error("Git tree '%s' is dirty", actualUrl);
|
||||
|
||||
if (settings.warnDirty)
|
||||
if (fetchSettings.warnDirty)
|
||||
warn("Git tree '%s' is dirty", actualUrl);
|
||||
|
||||
auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" });
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#include "filetransfer.hh"
|
||||
#include "cache.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "types.hh"
|
||||
#include "url-parts.hh"
|
||||
|
||||
#include "fetchers.hh"
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
#include <optional>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <fstream>
|
||||
|
|
@ -157,7 +159,7 @@ struct GitArchiveInputScheme : InputScheme
|
|||
|
||||
std::optional<std::string> getAccessToken(const std::string & host) const
|
||||
{
|
||||
auto tokens = settings.accessTokens.get();
|
||||
auto tokens = fetchSettings.accessTokens.get();
|
||||
if (auto token = get(tokens, host))
|
||||
return *token;
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include "store-api.hh"
|
||||
#include "url-parts.hh"
|
||||
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
|
@ -165,10 +167,10 @@ struct MercurialInputScheme : InputScheme
|
|||
/* This is an unclean working tree. So copy all tracked
|
||||
files. */
|
||||
|
||||
if (!settings.allowDirty)
|
||||
if (!fetchSettings.allowDirty)
|
||||
throw Error("Mercurial tree '%s' is unclean", actualUrl);
|
||||
|
||||
if (settings.warnDirty)
|
||||
if (fetchSettings.warnDirty)
|
||||
warn("Mercurial tree '%s' is unclean", actualUrl);
|
||||
|
||||
input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl })));
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
|
||||
#include "fetch-settings.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nix::fetchers {
|
||||
|
|
@ -150,7 +152,7 @@ void overrideRegistry(
|
|||
static std::shared_ptr<Registry> getGlobalRegistry(ref<Store> store)
|
||||
{
|
||||
static auto reg = [&]() {
|
||||
auto path = settings.flakeRegistry.get();
|
||||
auto path = fetchSettings.flakeRegistry.get();
|
||||
|
||||
if (!hasPrefix(path, "/")) {
|
||||
auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "globals.hh"
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "util.hh"
|
||||
#include "loggers.hh"
|
||||
|
||||
|
|
@ -227,8 +228,6 @@ LegacyArgs::LegacyArgs(const std::string & programName,
|
|||
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
|
||||
: MixCommonArgs(programName), parseArg(parseArg)
|
||||
{
|
||||
printError("FOO %s", programName);
|
||||
|
||||
addFlag({
|
||||
.longName = "no-build-output",
|
||||
.shortName = 'Q',
|
||||
|
|
|
|||
77
src/libstore/build-result.hh
Normal file
77
src/libstore/build-result.hh
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "realisation.hh"
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct BuildResult
|
||||
{
|
||||
/* Note: don't remove status codes, and only add new status codes
|
||||
at the end of the list, to prevent client/server
|
||||
incompatibilities in the nix-store --serve protocol. */
|
||||
enum Status {
|
||||
Built = 0,
|
||||
Substituted,
|
||||
AlreadyValid,
|
||||
PermanentFailure,
|
||||
InputRejected,
|
||||
OutputRejected,
|
||||
TransientFailure, // possibly transient
|
||||
CachedFailure, // no longer used
|
||||
TimedOut,
|
||||
MiscFailure,
|
||||
DependencyFailed,
|
||||
LogLimitExceeded,
|
||||
NotDeterministic,
|
||||
ResolvesToAlreadyValid,
|
||||
} status = MiscFailure;
|
||||
std::string errorMsg;
|
||||
|
||||
std::string toString() const {
|
||||
auto strStatus = [&]() {
|
||||
switch (status) {
|
||||
case Built: return "Built";
|
||||
case Substituted: return "Substituted";
|
||||
case AlreadyValid: return "AlreadyValid";
|
||||
case PermanentFailure: return "PermanentFailure";
|
||||
case InputRejected: return "InputRejected";
|
||||
case OutputRejected: return "OutputRejected";
|
||||
case TransientFailure: return "TransientFailure";
|
||||
case CachedFailure: return "CachedFailure";
|
||||
case TimedOut: return "TimedOut";
|
||||
case MiscFailure: return "MiscFailure";
|
||||
case DependencyFailed: return "DependencyFailed";
|
||||
case LogLimitExceeded: return "LogLimitExceeded";
|
||||
case NotDeterministic: return "NotDeterministic";
|
||||
case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
|
||||
default: return "Unknown";
|
||||
};
|
||||
}();
|
||||
return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
|
||||
}
|
||||
|
||||
/* How many times this build was performed. */
|
||||
unsigned int timesBuilt = 0;
|
||||
|
||||
/* If timesBuilt > 1, whether some builds did not produce the same
|
||||
result. (Note that 'isNonDeterministic = false' does not mean
|
||||
the build is deterministic, just that we don't have evidence of
|
||||
non-determinism.) */
|
||||
bool isNonDeterministic = false;
|
||||
|
||||
DrvOutputs builtOutputs;
|
||||
|
||||
/* The start/stop times of the build (or one of the rounds, if it
|
||||
was repeated). */
|
||||
time_t startTime = 0, stopTime = 0;
|
||||
|
||||
bool success() {
|
||||
return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "parsed-derivations.hh"
|
||||
#include "lock.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-api.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "goal.hh"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "local-derivation-goal.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "hook-instance.hh"
|
||||
#include "worker.hh"
|
||||
#include "builtins.hh"
|
||||
|
|
@ -1128,7 +1129,7 @@ struct RestrictedStoreConfig : virtual LocalFSStoreConfig
|
|||
/* A wrapper around LocalStore that only allows building/querying of
|
||||
paths that are in the input closures of the build or were added via
|
||||
recursive Nix calls. */
|
||||
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore
|
||||
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore, public virtual GcStore
|
||||
{
|
||||
ref<LocalStore> next;
|
||||
|
||||
|
|
@ -1934,7 +1935,7 @@ void LocalDerivationGoal::runChild()
|
|||
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
|
||||
i.first, i.second.source);
|
||||
|
||||
string path = i.first;
|
||||
std::string path = i.first;
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st)) {
|
||||
if (i.second.optional && errno == ENOENT)
|
||||
|
|
@ -1986,7 +1987,7 @@ void LocalDerivationGoal::runChild()
|
|||
args.push_back("IMPORT_DIR=" + settings.nixDataDir + "/nix/sandbox/");
|
||||
if (allowLocalNetworking) {
|
||||
args.push_back("-D");
|
||||
args.push_back(string("_ALLOW_LOCAL_NETWORKING=1"));
|
||||
args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1"));
|
||||
}
|
||||
args.push_back(drv->builder);
|
||||
} else {
|
||||
|
|
@ -2384,14 +2385,10 @@ void LocalDerivationGoal::registerOutputs()
|
|||
[&](DerivationOutputCAFloating dof) {
|
||||
return newInfoFromCA(dof);
|
||||
},
|
||||
[&](DerivationOutputDeferred) {
|
||||
[&](DerivationOutputDeferred) -> ValidPathInfo {
|
||||
// No derivation should reach that point without having been
|
||||
// rewritten first
|
||||
assert(false);
|
||||
// Ugly, but the compiler insists on having this return a value
|
||||
// of type `ValidPathInfo` despite the `assert(false)`, so
|
||||
// let's provide it
|
||||
return *(ValidPathInfo*)0;
|
||||
},
|
||||
}, output.output);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ struct LocalDerivationGoal : public DerivationGoal
|
|||
Environment env;
|
||||
|
||||
#if __APPLE__
|
||||
typedef string SandboxProfile;
|
||||
typedef std::string SandboxProfile;
|
||||
SandboxProfile additionalSandboxProfile;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include "daemon.hh"
|
||||
#include "monitor-fd.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "finally.hh"
|
||||
#include "archive.hh"
|
||||
|
|
@ -622,9 +624,12 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
|
||||
case wopAddIndirectRoot: {
|
||||
Path path = absPath(readString(from));
|
||||
|
||||
logger->startWork();
|
||||
store->addIndirectRoot(path);
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
gcStore.addIndirectRoot(path);
|
||||
logger->stopWork();
|
||||
|
||||
to << 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -639,7 +644,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
|
||||
case wopFindRoots: {
|
||||
logger->startWork();
|
||||
Roots roots = store->findRoots(!trusted);
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
Roots roots = gcStore.findRoots(!trusted);
|
||||
logger->stopWork();
|
||||
|
||||
size_t size = 0;
|
||||
|
|
@ -670,7 +676,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
logger->startWork();
|
||||
if (options.ignoreLiveness)
|
||||
throw Error("you are not allowed to ignore liveness");
|
||||
store->collectGarbage(options, results);
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
gcStore.collectGarbage(options, results);
|
||||
logger->stopWork();
|
||||
|
||||
to << results.paths << results.bytesFreed << 0 /* obsolete */;
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ struct curlFileTransfer : public FileTransfer
|
|||
result.etag = "";
|
||||
result.data.clear();
|
||||
result.bodySize = 0;
|
||||
statusMsg = trim((std::string &) match[1]);
|
||||
statusMsg = trim(match.str(1));
|
||||
acceptRanges = false;
|
||||
encoding = "";
|
||||
} else {
|
||||
|
|
|
|||
13
src/libstore/gc-store.cc
Normal file
13
src/libstore/gc-store.cc
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "gc-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
GcStore & requireGcStore(Store & store)
|
||||
{
|
||||
auto * gcStore = dynamic_cast<GcStore *>(&store);
|
||||
if (!gcStore)
|
||||
throw UsageError("Garbage collection not supported by this store");
|
||||
return *gcStore;
|
||||
}
|
||||
|
||||
}
|
||||
84
src/libstore/gc-store.hh
Normal file
84
src/libstore/gc-store.hh
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
#include "store-api.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
|
||||
|
||||
|
||||
struct GCOptions
|
||||
{
|
||||
/* Garbage collector operation:
|
||||
|
||||
- `gcReturnLive': return the set of paths reachable from
|
||||
(i.e. in the closure of) the roots.
|
||||
|
||||
- `gcReturnDead': return the set of paths not reachable from
|
||||
the roots.
|
||||
|
||||
- `gcDeleteDead': actually delete the latter set.
|
||||
|
||||
- `gcDeleteSpecific': delete the paths listed in
|
||||
`pathsToDelete', insofar as they are not reachable.
|
||||
*/
|
||||
typedef enum {
|
||||
gcReturnLive,
|
||||
gcReturnDead,
|
||||
gcDeleteDead,
|
||||
gcDeleteSpecific,
|
||||
} GCAction;
|
||||
|
||||
GCAction action{gcDeleteDead};
|
||||
|
||||
/* If `ignoreLiveness' is set, then reachability from the roots is
|
||||
ignored (dangerous!). However, the paths must still be
|
||||
unreferenced *within* the store (i.e., there can be no other
|
||||
store paths that depend on them). */
|
||||
bool ignoreLiveness{false};
|
||||
|
||||
/* For `gcDeleteSpecific', the paths to delete. */
|
||||
StorePathSet pathsToDelete;
|
||||
|
||||
/* Stop after at least `maxFreed' bytes have been freed. */
|
||||
uint64_t maxFreed{std::numeric_limits<uint64_t>::max()};
|
||||
};
|
||||
|
||||
|
||||
struct GCResults
|
||||
{
|
||||
/* Depending on the action, the GC roots, or the paths that would
|
||||
be or have been deleted. */
|
||||
PathSet paths;
|
||||
|
||||
/* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
|
||||
number of bytes that would be or was freed. */
|
||||
uint64_t bytesFreed = 0;
|
||||
};
|
||||
|
||||
|
||||
struct GcStore : public virtual Store
|
||||
{
|
||||
/* Add an indirect root, which is merely a symlink to `path' from
|
||||
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
|
||||
to be a symlink to a store path. The garbage collector will
|
||||
automatically remove the indirect root when it finds that
|
||||
`path' has disappeared. */
|
||||
virtual void addIndirectRoot(const Path & path) = 0;
|
||||
|
||||
/* Find the roots of the garbage collector. Each root is a pair
|
||||
(link, storepath) where `link' is the path of the symlink
|
||||
outside of the Nix store that point to `storePath'. If
|
||||
'censor' is true, privacy-sensitive information about roots
|
||||
found in /proc is censored. */
|
||||
virtual Roots findRoots(bool censor) = 0;
|
||||
|
||||
/* Perform a garbage collection. */
|
||||
virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
|
||||
};
|
||||
|
||||
GcStore & requireGcStore(Store & store);
|
||||
|
||||
}
|
||||
|
|
@ -413,7 +413,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
|||
try {
|
||||
std::regex lsofRegex(R"(^n(/.*)$)");
|
||||
auto lsofLines =
|
||||
tokenizeString<std::vector<string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
|
||||
tokenizeString<std::vector<std::string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
|
||||
for (const auto & line : lsofLines) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(line, match, lsofRegex))
|
||||
|
|
|
|||
|
|
@ -880,55 +880,6 @@ public:
|
|||
are loaded as plugins (non-recursively).
|
||||
)"};
|
||||
|
||||
Setting<StringMap> accessTokens{this, {}, "access-tokens",
|
||||
R"(
|
||||
Access tokens used to access protected GitHub, GitLab, or
|
||||
other locations requiring token-based authentication.
|
||||
|
||||
Access tokens are specified as a string made up of
|
||||
space-separated `host=token` values. The specific token
|
||||
used is selected by matching the `host` portion against the
|
||||
"host" specification of the input. The actual use of the
|
||||
`token` value is determined by the type of resource being
|
||||
accessed:
|
||||
|
||||
* Github: the token value is the OAUTH-TOKEN string obtained
|
||||
as the Personal Access Token from the Github server (see
|
||||
https://docs.github.com/en/developers/apps/authorizing-oath-apps).
|
||||
|
||||
* Gitlab: the token value is either the OAuth2 token or the
|
||||
Personal Access Token (these are different types tokens
|
||||
for gitlab, see
|
||||
https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
|
||||
The `token` value should be `type:tokenstring` where
|
||||
`type` is either `OAuth2` or `PAT` to indicate which type
|
||||
of token is being specified.
|
||||
|
||||
Example `~/.config/nix/nix.conf`:
|
||||
|
||||
```
|
||||
access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
|
||||
```
|
||||
|
||||
Example `~/code/flake.nix`:
|
||||
|
||||
```nix
|
||||
input.foo = {
|
||||
type = "gitlab";
|
||||
host = "gitlab.mycompany.com";
|
||||
owner = "mycompany";
|
||||
repo = "pro";
|
||||
};
|
||||
```
|
||||
|
||||
This example specifies three tokens, one each for accessing
|
||||
github.com, gitlab.mycompany.com, and sourceforge.net.
|
||||
|
||||
The `input.foo` uses the "gitlab" fetcher, which might
|
||||
requires specifying the token type along with the token
|
||||
value.
|
||||
)"};
|
||||
|
||||
Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
|
||||
"Experimental Nix features to enable."};
|
||||
|
||||
|
|
@ -936,18 +887,9 @@ public:
|
|||
|
||||
void requireExperimentalFeature(const ExperimentalFeature &);
|
||||
|
||||
Setting<bool> allowDirty{this, true, "allow-dirty",
|
||||
"Whether to allow dirty Git/Mercurial trees."};
|
||||
|
||||
Setting<bool> warnDirty{this, true, "warn-dirty",
|
||||
"Whether to warn about dirty Git/Mercurial trees."};
|
||||
|
||||
Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
|
||||
"Maximum size of NARs before spilling them to disk."};
|
||||
|
||||
Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
|
||||
"Path or URI of the global flake registry."};
|
||||
|
||||
Setting<bool> allowSymlinkedStore{
|
||||
this, false, "allow-symlinked-store",
|
||||
R"(
|
||||
|
|
@ -960,19 +902,6 @@ public:
|
|||
resolves to a different location from that of the build machine. You
|
||||
can enable this setting if you are sure you're not going to do that.
|
||||
)"};
|
||||
|
||||
Setting<bool> useRegistries{this, true, "use-registries",
|
||||
"Whether to use flake registries to resolve flake references."};
|
||||
|
||||
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
|
||||
"Whether to accept nix configuration from a flake without prompting."};
|
||||
|
||||
Setting<std::string> commitLockFileSummary{
|
||||
this, "", "commit-lockfile-summary",
|
||||
R"(
|
||||
The commit summary to use when committing changed flake lock files. If
|
||||
empty, the summary is generated based on the action performed.
|
||||
)"};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "pool.hh"
|
||||
#include "remote-store.hh"
|
||||
#include "serve-protocol.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-api.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "worker-protocol.hh"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ struct LocalFSStoreConfig : virtual StoreConfig
|
|||
"physical path to the Nix store"};
|
||||
};
|
||||
|
||||
class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store
|
||||
class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store, virtual GcStore
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "pathlocks.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "sync.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
|
|||
};
|
||||
|
||||
|
||||
class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore
|
||||
class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore
|
||||
{
|
||||
private:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include "serialise.hh"
|
||||
#include "util.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "remote-fs-accessor.hh"
|
||||
#include "build-result.hh"
|
||||
#include "remote-store.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "archive.hh"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
|
@ -29,7 +30,7 @@ struct RemoteStoreConfig : virtual StoreConfig
|
|||
|
||||
/* FIXME: RemoteStore is a misnomer - should be something like
|
||||
DaemonStore. */
|
||||
class RemoteStore : public virtual RemoteStoreConfig, public virtual Store
|
||||
class RemoteStore : public virtual RemoteStoreConfig, public virtual Store, public virtual GcStore
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -76,127 +76,10 @@ enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true };
|
|||
const uint32_t exportMagic = 0x4558494e;
|
||||
|
||||
|
||||
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
|
||||
|
||||
|
||||
struct GCOptions
|
||||
{
|
||||
/* Garbage collector operation:
|
||||
|
||||
- `gcReturnLive': return the set of paths reachable from
|
||||
(i.e. in the closure of) the roots.
|
||||
|
||||
- `gcReturnDead': return the set of paths not reachable from
|
||||
the roots.
|
||||
|
||||
- `gcDeleteDead': actually delete the latter set.
|
||||
|
||||
- `gcDeleteSpecific': delete the paths listed in
|
||||
`pathsToDelete', insofar as they are not reachable.
|
||||
*/
|
||||
typedef enum {
|
||||
gcReturnLive,
|
||||
gcReturnDead,
|
||||
gcDeleteDead,
|
||||
gcDeleteSpecific,
|
||||
} GCAction;
|
||||
|
||||
GCAction action{gcDeleteDead};
|
||||
|
||||
/* If `ignoreLiveness' is set, then reachability from the roots is
|
||||
ignored (dangerous!). However, the paths must still be
|
||||
unreferenced *within* the store (i.e., there can be no other
|
||||
store paths that depend on them). */
|
||||
bool ignoreLiveness{false};
|
||||
|
||||
/* For `gcDeleteSpecific', the paths to delete. */
|
||||
StorePathSet pathsToDelete;
|
||||
|
||||
/* Stop after at least `maxFreed' bytes have been freed. */
|
||||
uint64_t maxFreed{std::numeric_limits<uint64_t>::max()};
|
||||
};
|
||||
|
||||
|
||||
struct GCResults
|
||||
{
|
||||
/* Depending on the action, the GC roots, or the paths that would
|
||||
be or have been deleted. */
|
||||
PathSet paths;
|
||||
|
||||
/* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
|
||||
number of bytes that would be or was freed. */
|
||||
uint64_t bytesFreed = 0;
|
||||
};
|
||||
|
||||
|
||||
enum BuildMode { bmNormal, bmRepair, bmCheck };
|
||||
|
||||
struct BuildResult;
|
||||
|
||||
struct BuildResult
|
||||
{
|
||||
/* Note: don't remove status codes, and only add new status codes
|
||||
at the end of the list, to prevent client/server
|
||||
incompatibilities in the nix-store --serve protocol. */
|
||||
enum Status {
|
||||
Built = 0,
|
||||
Substituted,
|
||||
AlreadyValid,
|
||||
PermanentFailure,
|
||||
InputRejected,
|
||||
OutputRejected,
|
||||
TransientFailure, // possibly transient
|
||||
CachedFailure, // no longer used
|
||||
TimedOut,
|
||||
MiscFailure,
|
||||
DependencyFailed,
|
||||
LogLimitExceeded,
|
||||
NotDeterministic,
|
||||
ResolvesToAlreadyValid,
|
||||
} status = MiscFailure;
|
||||
std::string errorMsg;
|
||||
|
||||
std::string toString() const {
|
||||
auto strStatus = [&]() {
|
||||
switch (status) {
|
||||
case Built: return "Built";
|
||||
case Substituted: return "Substituted";
|
||||
case AlreadyValid: return "AlreadyValid";
|
||||
case PermanentFailure: return "PermanentFailure";
|
||||
case InputRejected: return "InputRejected";
|
||||
case OutputRejected: return "OutputRejected";
|
||||
case TransientFailure: return "TransientFailure";
|
||||
case CachedFailure: return "CachedFailure";
|
||||
case TimedOut: return "TimedOut";
|
||||
case MiscFailure: return "MiscFailure";
|
||||
case DependencyFailed: return "DependencyFailed";
|
||||
case LogLimitExceeded: return "LogLimitExceeded";
|
||||
case NotDeterministic: return "NotDeterministic";
|
||||
case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
|
||||
default: return "Unknown";
|
||||
};
|
||||
}();
|
||||
return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
|
||||
}
|
||||
|
||||
/* How many times this build was performed. */
|
||||
unsigned int timesBuilt = 0;
|
||||
|
||||
/* If timesBuilt > 1, whether some builds did not produce the same
|
||||
result. (Note that 'isNonDeterministic = false' does not mean
|
||||
the build is deterministic, just that we don't have evidence of
|
||||
non-determinism.) */
|
||||
bool isNonDeterministic = false;
|
||||
|
||||
DrvOutputs builtOutputs;
|
||||
|
||||
/* The start/stop times of the build (or one of the rounds, if it
|
||||
was repeated). */
|
||||
time_t startTime = 0, stopTime = 0;
|
||||
|
||||
bool success() {
|
||||
return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
|
||||
}
|
||||
};
|
||||
|
||||
struct StoreConfig : public Config
|
||||
{
|
||||
|
|
@ -595,26 +478,6 @@ public:
|
|||
virtual void addTempRoot(const StorePath & path)
|
||||
{ debug("not creating temporary root, store doesn't support GC"); }
|
||||
|
||||
/* Add an indirect root, which is merely a symlink to `path' from
|
||||
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
|
||||
to be a symlink to a store path. The garbage collector will
|
||||
automatically remove the indirect root when it finds that
|
||||
`path' has disappeared. */
|
||||
virtual void addIndirectRoot(const Path & path)
|
||||
{ unsupported("addIndirectRoot"); }
|
||||
|
||||
/* Find the roots of the garbage collector. Each root is a pair
|
||||
(link, storepath) where `link' is the path of the symlink
|
||||
outside of the Nix store that point to `storePath'. If
|
||||
'censor' is true, privacy-sensitive information about roots
|
||||
found in /proc is censored. */
|
||||
virtual Roots findRoots(bool censor)
|
||||
{ unsupported("findRoots"); }
|
||||
|
||||
/* Perform a garbage collection. */
|
||||
virtual void collectGarbage(const GCOptions & options, GCResults & results)
|
||||
{ unsupported("collectGarbage"); }
|
||||
|
||||
/* Return a string representing information about the path that
|
||||
can be loaded into the database using `nix-store --load-db' or
|
||||
`nix-store --register-validity'. */
|
||||
|
|
|
|||
|
|
@ -1263,9 +1263,9 @@ std::string chomp(std::string_view s)
|
|||
std::string trim(std::string_view s, std::string_view whitespace)
|
||||
{
|
||||
auto i = s.find_first_not_of(whitespace);
|
||||
if (i == std::string_view::npos) return "";
|
||||
if (i == s.npos) return "";
|
||||
auto j = s.find_last_not_of(whitespace);
|
||||
return std::string(s, i, j == std::string::npos ? j : j - i + 1);
|
||||
return std::string(s, i, j == s.npos ? j : j - i + 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1412,7 +1412,7 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in
|
|||
}
|
||||
}
|
||||
|
||||
else if (*i == '\r')
|
||||
else if (*i == '\r' || *i == '\a')
|
||||
// do nothing for now
|
||||
i++;
|
||||
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
throw UsageError("nix-shell requires a single derivation");
|
||||
|
||||
auto & drvInfo = drvs.front();
|
||||
auto drv = evalStore->derivationFromPath(evalStore->parseStorePath(drvInfo.queryDrvPath()));
|
||||
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath());
|
||||
|
||||
std::vector<StorePathWithOutputs> pathsToBuild;
|
||||
RealisedPath::Set pathsToCopy;
|
||||
|
|
@ -369,7 +369,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
if (!drv)
|
||||
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
|
||||
|
||||
auto bashDrv = store->parseStorePath(drv->queryDrvPath());
|
||||
auto bashDrv = drv->requireDrvPath();
|
||||
pathsToBuild.push_back({bashDrv});
|
||||
pathsToCopy.insert(bashDrv);
|
||||
shellDrv = bashDrv;
|
||||
|
|
@ -458,10 +458,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
}
|
||||
}
|
||||
|
||||
ParsedDerivation parsedDrv(
|
||||
StorePath(store->parseStorePath(drvInfo.queryDrvPath())),
|
||||
drv
|
||||
);
|
||||
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(), drv);
|
||||
|
||||
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
|
||||
auto json = structAttrs.value();
|
||||
|
|
@ -553,7 +550,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
std::map<StorePath, std::pair<size_t, StringSet>> drvMap;
|
||||
|
||||
for (auto & drvInfo : drvs) {
|
||||
auto drvPath = store->parseStorePath(drvInfo.queryDrvPath());
|
||||
auto drvPath = drvInfo.requireDrvPath();
|
||||
|
||||
auto outputName = drvInfo.queryOutputName();
|
||||
if (outputName == "")
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ static void update(const StringSet & channelNames)
|
|||
std::smatch match;
|
||||
auto urlBase = std::string(baseNameOf(url));
|
||||
if (std::regex_search(urlBase, match, std::regex("(-\\d.*)$")))
|
||||
cname = cname + (std::string) match[1];
|
||||
cname = cname + match.str(1);
|
||||
|
||||
std::string extraAttrs;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "profiles.hh"
|
||||
#include "shared.hh"
|
||||
#include "globals.hh"
|
||||
|
|
@ -80,10 +81,11 @@ static int main_nix_collect_garbage(int argc, char * * argv)
|
|||
// Run the actual garbage collector.
|
||||
if (!dryRun) {
|
||||
auto store = openStore();
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
options.action = GCOptions::gcDeleteDead;
|
||||
GCResults results;
|
||||
PrintFreed freed(true, results);
|
||||
store->collectGarbage(options, results);
|
||||
gcStore.collectGarbage(options, results);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ static long comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2)
|
|||
// at a time.
|
||||
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
||||
{
|
||||
auto path = state.store->parseStorePath(elem.queryOutPath());
|
||||
auto path = elem.queryOutPath();
|
||||
if (state.store->isValidPath(path)) return true;
|
||||
return state.store->querySubstitutablePaths({path}).count(path);
|
||||
}
|
||||
|
|
@ -429,14 +429,15 @@ static void queryInstSources(EvalState & state,
|
|||
elem.setName(name);
|
||||
|
||||
if (path.isDerivation()) {
|
||||
elem.setDrvPath(state.store->printStorePath(path));
|
||||
elem.setDrvPath(path);
|
||||
auto outputs = state.store->queryDerivationOutputMap(path);
|
||||
elem.setOutPath(state.store->printStorePath(outputs.at("out")));
|
||||
elem.setOutPath(outputs.at("out"));
|
||||
if (name.size() >= drvExtension.size() &&
|
||||
std::string(name, name.size() - drvExtension.size()) == drvExtension)
|
||||
name = name.substr(0, name.size() - drvExtension.size());
|
||||
}
|
||||
else elem.setOutPath(state.store->printStorePath(path));
|
||||
else
|
||||
elem.setOutPath(path);
|
||||
|
||||
elems.push_back(elem);
|
||||
}
|
||||
|
|
@ -470,13 +471,11 @@ static void queryInstSources(EvalState & state,
|
|||
static void printMissing(EvalState & state, DrvInfos & elems)
|
||||
{
|
||||
std::vector<DerivedPath> targets;
|
||||
for (auto & i : elems) {
|
||||
Path drvPath = i.queryDrvPath();
|
||||
if (drvPath != "")
|
||||
targets.push_back(DerivedPath::Built{state.store->parseStorePath(drvPath)});
|
||||
for (auto & i : elems)
|
||||
if (auto drvPath = i.queryDrvPath())
|
||||
targets.push_back(DerivedPath::Built{*drvPath});
|
||||
else
|
||||
targets.push_back(DerivedPath::Opaque{state.store->parseStorePath(i.queryOutPath())});
|
||||
}
|
||||
targets.push_back(DerivedPath::Opaque{i.queryOutPath()});
|
||||
|
||||
printMissing(state.store, targets);
|
||||
}
|
||||
|
|
@ -744,14 +743,11 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
if (globals.forceName != "")
|
||||
drv.setName(globals.forceName);
|
||||
|
||||
auto drvPath = drv.queryDrvPath();
|
||||
std::vector<DerivedPath> paths {
|
||||
(drv.queryDrvPath() != "")
|
||||
? (DerivedPath) (DerivedPath::Built {
|
||||
globals.state->store->parseStorePath(drv.queryDrvPath())
|
||||
})
|
||||
: (DerivedPath) (DerivedPath::Opaque {
|
||||
globals.state->store->parseStorePath(drv.queryOutPath())
|
||||
}),
|
||||
drvPath
|
||||
? (DerivedPath) (DerivedPath::Built { *drvPath })
|
||||
: (DerivedPath) (DerivedPath::Opaque { drv.queryOutPath() }),
|
||||
};
|
||||
printMissing(globals.state->store, paths);
|
||||
if (globals.dryRun) return;
|
||||
|
|
@ -759,8 +755,9 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
|
||||
debug(format("switching to new user environment"));
|
||||
Path generation = createGeneration(
|
||||
ref<LocalFSStore>(store2), globals.profile,
|
||||
store2->parseStorePath(drv.queryOutPath()));
|
||||
ref<LocalFSStore>(store2),
|
||||
globals.profile,
|
||||
drv.queryOutPath());
|
||||
switchLink(globals.profile, generation);
|
||||
}
|
||||
|
||||
|
|
@ -780,7 +777,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
|||
split = std::partition(
|
||||
workingElems.begin(), workingElems.end(),
|
||||
[&selectorStorePath, globals](auto &elem) {
|
||||
return selectorStorePath != globals.state->store->parseStorePath(elem.queryOutPath());
|
||||
return selectorStorePath != elem.queryOutPath();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
@ -925,9 +922,8 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
|||
if (printOutPath) {
|
||||
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||
JSONObject outputObj = pkgObj.object("outputs");
|
||||
for (auto & j : outputs) {
|
||||
outputObj.attr(j.first, j.second);
|
||||
}
|
||||
for (auto & j : outputs)
|
||||
outputObj.attr(j.first, globals.state->store->printStorePath(j.second));
|
||||
}
|
||||
|
||||
if (printMeta) {
|
||||
|
|
@ -957,6 +953,8 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
|||
|
||||
static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
{
|
||||
auto & store { *globals.state->store };
|
||||
|
||||
Strings remaining;
|
||||
std::string attrPath;
|
||||
|
||||
|
|
@ -1027,12 +1025,11 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
|
||||
/* We only need to know the installed paths when we are querying
|
||||
the status of the derivation. */
|
||||
PathSet installed; /* installed paths */
|
||||
StorePathSet installed; /* installed paths */
|
||||
|
||||
if (printStatus) {
|
||||
if (printStatus)
|
||||
for (auto & i : installedElems)
|
||||
installed.insert(i.queryOutPath());
|
||||
}
|
||||
|
||||
|
||||
/* Query which paths have substitutes. */
|
||||
|
|
@ -1042,13 +1039,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
StorePathSet paths;
|
||||
for (auto & i : elems)
|
||||
try {
|
||||
paths.insert(globals.state->store->parseStorePath(i.queryOutPath()));
|
||||
paths.insert(i.queryOutPath());
|
||||
} catch (AssertionError & e) {
|
||||
printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName());
|
||||
i.setFailed();
|
||||
}
|
||||
validPaths = globals.state->store->queryValidPaths(paths);
|
||||
substitutablePaths = globals.state->store->querySubstitutablePaths(paths);
|
||||
validPaths = store.queryValidPaths(paths);
|
||||
substitutablePaths = store.querySubstitutablePaths(paths);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1073,8 +1070,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
//Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath);
|
||||
|
||||
if (globals.prebuiltOnly &&
|
||||
!validPaths.count(globals.state->store->parseStorePath(i.queryOutPath())) &&
|
||||
!substitutablePaths.count(globals.state->store->parseStorePath(i.queryOutPath())))
|
||||
!validPaths.count(i.queryOutPath()) &&
|
||||
!substitutablePaths.count(i.queryOutPath()))
|
||||
continue;
|
||||
|
||||
/* For table output. */
|
||||
|
|
@ -1084,10 +1081,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
XMLAttrs attrs;
|
||||
|
||||
if (printStatus) {
|
||||
Path outPath = i.queryOutPath();
|
||||
bool hasSubs = substitutablePaths.count(globals.state->store->parseStorePath(outPath));
|
||||
bool isInstalled = installed.find(outPath) != installed.end();
|
||||
bool isValid = validPaths.count(globals.state->store->parseStorePath(outPath));
|
||||
auto outPath = i.queryOutPath();
|
||||
bool hasSubs = substitutablePaths.count(outPath);
|
||||
bool isInstalled = installed.count(outPath);
|
||||
bool isValid = validPaths.count(outPath);
|
||||
if (xmlOutput) {
|
||||
attrs["installed"] = isInstalled ? "1" : "0";
|
||||
attrs["valid"] = isValid ? "1" : "0";
|
||||
|
|
@ -1152,9 +1149,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
if (printDrvPath) {
|
||||
auto drvPath = i.queryDrvPath();
|
||||
if (xmlOutput) {
|
||||
if (drvPath != "") attrs["drvPath"] = drvPath;
|
||||
if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
|
||||
} else
|
||||
columns.push_back(drvPath == "" ? "-" : drvPath);
|
||||
columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-");
|
||||
}
|
||||
|
||||
if (printOutPath && !xmlOutput) {
|
||||
|
|
@ -1163,7 +1160,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
for (auto & j : outputs) {
|
||||
if (!s.empty()) s += ';';
|
||||
if (j.first != "out") { s += j.first; s += "="; }
|
||||
s += j.second;
|
||||
s += store.printStorePath(j.second);
|
||||
}
|
||||
columns.push_back(s);
|
||||
}
|
||||
|
|
@ -1184,7 +1181,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
for (auto & j : outputs) {
|
||||
XMLAttrs attrs2;
|
||||
attrs2["name"] = j.first;
|
||||
attrs2["path"] = j.second;
|
||||
attrs2["path"] = store.printStorePath(j.second);
|
||||
xml.writeEmptyElement("output", attrs2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
exist already. */
|
||||
std::vector<StorePathWithOutputs> drvsToBuild;
|
||||
for (auto & i : elems)
|
||||
if (i.queryDrvPath() != "")
|
||||
drvsToBuild.push_back({state.store->parseStorePath(i.queryDrvPath())});
|
||||
if (auto drvPath = i.queryDrvPath())
|
||||
drvsToBuild.push_back({*drvPath});
|
||||
|
||||
debug(format("building user environment dependencies"));
|
||||
state.store->buildPaths(
|
||||
|
|
@ -55,7 +55,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
/* Create a pseudo-derivation containing the name, system,
|
||||
output paths, and optionally the derivation path, as well
|
||||
as the meta attributes. */
|
||||
Path drvPath = keepDerivations ? i.queryDrvPath() : "";
|
||||
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt;
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
||||
StringSet metaNames = i.queryMetaNames();
|
||||
|
||||
|
|
@ -66,9 +66,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
auto system = i.querySystem();
|
||||
if (!system.empty())
|
||||
attrs.alloc(state.sSystem).mkString(system);
|
||||
attrs.alloc(state.sOutPath).mkString(i.queryOutPath());
|
||||
if (drvPath != "")
|
||||
attrs.alloc(state.sDrvPath).mkString(i.queryDrvPath());
|
||||
attrs.alloc(state.sOutPath).mkString(state.store->printStorePath(i.queryOutPath()));
|
||||
if (drvPath)
|
||||
attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
|
||||
|
||||
// Copy each output meant for installation.
|
||||
auto & vOutputs = attrs.alloc(state.sOutputs);
|
||||
|
|
@ -76,15 +76,15 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
for (const auto & [m, j] : enumerate(outputs)) {
|
||||
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
||||
auto outputAttrs = state.buildBindings(2);
|
||||
outputAttrs.alloc(state.sOutPath).mkString(j.second);
|
||||
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(j.second));
|
||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||
|
||||
/* This is only necessary when installing store paths, e.g.,
|
||||
`nix-env -i /nix/store/abcd...-foo'. */
|
||||
state.store->addTempRoot(state.store->parseStorePath(j.second));
|
||||
state.store->ensurePath(state.store->parseStorePath(j.second));
|
||||
state.store->addTempRoot(j.second);
|
||||
state.store->ensurePath(j.second);
|
||||
|
||||
references.insert(state.store->parseStorePath(j.second));
|
||||
references.insert(j.second);
|
||||
}
|
||||
|
||||
// Copy the meta attributes.
|
||||
|
|
@ -99,7 +99,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
|
||||
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
||||
|
||||
if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
|
||||
if (drvPath) references.insert(*drvPath);
|
||||
}
|
||||
|
||||
/* Also write a copy of the list of user environment elements to
|
||||
|
|
@ -132,9 +132,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
|
||||
PathSet context;
|
||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
||||
auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context));
|
||||
auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context);
|
||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
||||
Path topLevelOut = state.coerceToPath(*aOutPath.pos, *aOutPath.value, context);
|
||||
auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context);
|
||||
|
||||
/* Realise the resulting store expression. */
|
||||
debug("building user environment");
|
||||
|
|
@ -158,8 +158,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||
}
|
||||
|
||||
debug(format("switching to new user environment"));
|
||||
Path generation = createGeneration(ref<LocalFSStore>(store2), profile,
|
||||
store2->parseStorePath(topLevelOut));
|
||||
Path generation = createGeneration(ref<LocalFSStore>(store2), profile, topLevelOut);
|
||||
switchLink(profile, generation);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,12 +61,13 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||
DrvInfos drvs;
|
||||
getDerivations(state, v, "", autoArgs, drvs, false);
|
||||
for (auto & i : drvs) {
|
||||
Path drvPath = i.queryDrvPath();
|
||||
auto drvPath = i.requireDrvPath();
|
||||
auto drvPathS = state.store->printStorePath(drvPath);
|
||||
|
||||
/* What output do we want? */
|
||||
std::string outputName = i.queryOutputName();
|
||||
if (outputName == "")
|
||||
throw Error("derivation '%1%' lacks an 'outputName' attribute ", drvPath);
|
||||
throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
|
||||
|
||||
if (gcRoot == "")
|
||||
printGCWarning();
|
||||
|
|
@ -75,9 +76,9 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
||||
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
if (store2)
|
||||
drvPath = store2->addPermRoot(store2->parseStorePath(drvPath), rootName);
|
||||
drvPathS = store2->addPermRoot(drvPath, rootName);
|
||||
}
|
||||
std::cout << fmt("%s%s\n", drvPath, (outputName != "out" ? "!" + outputName : ""));
|
||||
std::cout << fmt("%s%s\n", drvPathS, (outputName != "out" ? "!" + outputName : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "derivations.hh"
|
||||
#include "dotgraph.hh"
|
||||
#include "globals.hh"
|
||||
#include "build-result.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "local-store.hh"
|
||||
#include "monitor-fd.hh"
|
||||
#include "serve-protocol.hh"
|
||||
|
|
@ -427,11 +429,12 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||
store->computeFSClosure(
|
||||
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
|
||||
|
||||
Roots roots = store->findRoots(false);
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
Roots roots = gcStore.findRoots(false);
|
||||
for (auto & [target, links] : roots)
|
||||
if (referrers.find(target) != referrers.end())
|
||||
for (auto & link : links)
|
||||
cout << fmt("%1% -> %2%\n", link, store->printStorePath(target));
|
||||
cout << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -587,20 +590,22 @@ static void opGC(Strings opFlags, Strings opArgs)
|
|||
|
||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
|
||||
if (printRoots) {
|
||||
Roots roots = store->findRoots(false);
|
||||
Roots roots = gcStore.findRoots(false);
|
||||
std::set<std::pair<Path, StorePath>> roots2;
|
||||
// Transpose and sort the roots.
|
||||
for (auto & [target, links] : roots)
|
||||
for (auto & link : links)
|
||||
roots2.emplace(link, target);
|
||||
for (auto & [link, target] : roots2)
|
||||
std::cout << link << " -> " << store->printStorePath(target) << "\n";
|
||||
std::cout << link << " -> " << gcStore.printStorePath(target) << "\n";
|
||||
}
|
||||
|
||||
else {
|
||||
PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
|
||||
store->collectGarbage(options, results);
|
||||
gcStore.collectGarbage(options, results);
|
||||
|
||||
if (options.action != GCOptions::gcDeleteDead)
|
||||
for (auto & i : results.paths)
|
||||
|
|
@ -624,9 +629,11 @@ static void opDelete(Strings opFlags, Strings opArgs)
|
|||
for (auto & i : opArgs)
|
||||
options.pathsToDelete.insert(store->followLinksToStorePath(i));
|
||||
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
|
||||
GCResults results;
|
||||
PrintFreed freed(true, results);
|
||||
store->collectGarbage(options, results);
|
||||
gcStore.collectGarbage(options, results);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store)
|
|||
installableContext.push_back(
|
||||
std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath()));
|
||||
|
||||
auto builtContext = build(evalStore, store, Realise::Outputs, installableContext);
|
||||
auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext);
|
||||
res.program = resolveString(*store, unresolved.program, builtContext);
|
||||
if (!store->isInStore(res.program))
|
||||
throw Error("app program '%s' is not in the Nix store", res.program);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
|
|||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto buildables = build(
|
||||
auto buildables = Installable::build(
|
||||
getEvalStore(), store,
|
||||
dryRun ? Realise::Derivation : Realise::Outputs,
|
||||
installables, buildMode);
|
||||
|
|
|
|||
|
|
@ -97,13 +97,13 @@ struct CmdBundle : InstallableCommand
|
|||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||
|
||||
PathSet context2;
|
||||
StorePath drvPath = store->parseStorePath(evalState->coerceToPath(*attr1->pos, *attr1->value, context2));
|
||||
auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2);
|
||||
|
||||
auto attr2 = vRes->attrs->get(evalState->sOutPath);
|
||||
if (!attr2)
|
||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||
|
||||
StorePath outPath = store->parseStorePath(evalState->coerceToPath(*attr2->pos, *attr2->value, context2));
|
||||
auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2);
|
||||
|
||||
store->buildPaths({ DerivedPath::Built { drvPath } });
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ struct Common : InstallableCommand, MixProfile
|
|||
for (auto & [installable_, dir_] : redirects) {
|
||||
auto dir = absPath(dir_);
|
||||
auto installable = parseInstallable(store, installable_);
|
||||
auto builtPaths = toStorePaths(
|
||||
auto builtPaths = Installable::toStorePaths(
|
||||
getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable});
|
||||
for (auto & path: builtPaths) {
|
||||
auto from = store->printStorePath(path);
|
||||
|
|
@ -347,7 +347,7 @@ struct Common : InstallableCommand, MixProfile
|
|||
if (path && hasSuffix(path->to_string(), "-env"))
|
||||
return *path;
|
||||
else {
|
||||
auto drvs = toDerivations(store, {installable});
|
||||
auto drvs = Installable::toDerivations(store, {installable});
|
||||
|
||||
if (drvs.size() != 1)
|
||||
throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations",
|
||||
|
|
@ -511,7 +511,8 @@ struct CmdDevelop : Common, MixEnvironment
|
|||
nixpkgsLockFlags);
|
||||
|
||||
shell = store->printStorePath(
|
||||
toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash";
|
||||
Installable::toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable))
|
||||
+ "/bin/bash";
|
||||
} catch (Error &) {
|
||||
ignoreException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,9 +131,9 @@ struct CmdDiffClosures : SourceExprCommand
|
|||
void run(ref<Store> store) override
|
||||
{
|
||||
auto before = parseInstallable(store, _before);
|
||||
auto beforePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before);
|
||||
auto beforePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before);
|
||||
auto after = parseInstallable(store, _after);
|
||||
auto afterPath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after);
|
||||
auto afterPath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after);
|
||||
printClosureDiff(store, beforePath, afterPath, "");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ struct CmdFlakeCheck : FlakeCommand
|
|||
if (!drvInfo)
|
||||
throw Error("flake attribute '%s' is not a derivation", attrPath);
|
||||
// FIXME: check meta attributes
|
||||
return std::make_optional(store->parseStorePath(drvInfo->queryDrvPath()));
|
||||
return drvInfo->queryDrvPath();
|
||||
} catch (Error & e) {
|
||||
e.addTrace(pos, hintfmt("while checking the derivation '%s'", attrPath));
|
||||
reportError(e);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,27 @@ struct ProfileElement
|
|||
{
|
||||
return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
|
||||
}
|
||||
|
||||
void updateStorePaths(ref<Store> evalStore, ref<Store> store, Installable & installable)
|
||||
{
|
||||
// FIXME: respect meta.outputsToInstall
|
||||
storePaths.clear();
|
||||
for (auto & buildable : getBuiltPaths(evalStore, store, installable.toDerivedPaths())) {
|
||||
std::visit(overloaded {
|
||||
[&](const BuiltPath::Opaque & bo) {
|
||||
storePaths.insert(bo.path);
|
||||
},
|
||||
[&](const BuiltPath::Built & bfd) {
|
||||
// TODO: Why are we querying if we know the output
|
||||
// names already? Is it just to figure out what the
|
||||
// default one is?
|
||||
for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
|
||||
storePaths.insert(output.second);
|
||||
}
|
||||
},
|
||||
}, buildable.raw());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ProfileManifest
|
||||
|
|
@ -105,7 +126,7 @@ struct ProfileManifest
|
|||
|
||||
for (auto & drvInfo : drvInfos) {
|
||||
ProfileElement element;
|
||||
element.storePaths = {state.store->parseStorePath(drvInfo.queryOutPath())};
|
||||
element.storePaths = {drvInfo.queryOutPath()};
|
||||
elements.emplace_back(std::move(element));
|
||||
}
|
||||
}
|
||||
|
|
@ -232,53 +253,25 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
|
|||
{
|
||||
ProfileManifest manifest(*getEvalState(), *profile);
|
||||
|
||||
std::vector<DerivedPath> pathsToBuild;
|
||||
auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
|
||||
|
||||
for (auto & installable : installables) {
|
||||
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
|
||||
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
|
||||
|
||||
ProfileElement element;
|
||||
if (!drv.outPath)
|
||||
throw UnimplementedError("CA derivations are not yet supported by 'nix profile'");
|
||||
element.storePaths = {*drv.outPath}; // FIXME
|
||||
|
||||
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
|
||||
// FIXME: make build() return this?
|
||||
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
|
||||
element.source = ProfileElementSource{
|
||||
installable2->flakeRef,
|
||||
resolvedRef,
|
||||
attrPath,
|
||||
};
|
||||
|
||||
pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, StringSet{drv.outputName}});
|
||||
|
||||
manifest.elements.emplace_back(std::move(element));
|
||||
} else {
|
||||
auto buildables = build(getEvalStore(), store, Realise::Outputs, {installable}, bmNormal);
|
||||
|
||||
for (auto & buildable : buildables) {
|
||||
ProfileElement element;
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](const BuiltPath::Opaque & bo) {
|
||||
pathsToBuild.push_back(bo);
|
||||
element.storePaths.insert(bo.path);
|
||||
},
|
||||
[&](const BuiltPath::Built & bfd) {
|
||||
// TODO: Why are we querying if we know the output
|
||||
// names already? Is it just to figure out what the
|
||||
// default one is?
|
||||
for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
|
||||
pathsToBuild.push_back(DerivedPath::Built{bfd.drvPath, {output.first}});
|
||||
element.storePaths.insert(output.second);
|
||||
}
|
||||
},
|
||||
}, buildable.raw());
|
||||
|
||||
manifest.elements.emplace_back(std::move(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store->buildPaths(pathsToBuild);
|
||||
element.updateStorePaths(getEvalStore(), store, *installable);
|
||||
|
||||
manifest.elements.push_back(std::move(element));
|
||||
}
|
||||
|
||||
updateProfile(manifest.build(store));
|
||||
}
|
||||
|
|
@ -374,14 +367,14 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem
|
|||
if (removedCount == 0) {
|
||||
for (auto matcher: matchers) {
|
||||
if (const size_t * index = std::get_if<size_t>(&matcher)){
|
||||
warn("'%d' is not a valid index in profile", *index);
|
||||
warn("'%d' is not a valid index", *index);
|
||||
} else if (const Path * path = std::get_if<Path>(&matcher)){
|
||||
warn("'%s' does not match any paths in profile", *path);
|
||||
warn("'%s' does not match any paths", *path);
|
||||
} else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){
|
||||
warn("'%s' does not match any packages in profile", regex->pattern);
|
||||
warn("'%s' does not match any packages", regex->pattern);
|
||||
}
|
||||
}
|
||||
warn ("Try `nix profile list` to see the current profile.");
|
||||
warn ("Use 'nix profile list' to see the current profile.");
|
||||
}
|
||||
updateProfile(newManifest.build(store));
|
||||
}
|
||||
|
|
@ -407,8 +400,8 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
|
|||
|
||||
auto matchers = getMatchers(store);
|
||||
|
||||
// FIXME: code duplication
|
||||
std::vector<DerivedPath> pathsToBuild;
|
||||
std::vector<std::shared_ptr<Installable>> installables;
|
||||
std::vector<size_t> indices;
|
||||
|
||||
auto upgradedCount = 0;
|
||||
|
||||
|
|
@ -423,49 +416,53 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
|
|||
Activity act(*logger, lvlChatty, actUnknown,
|
||||
fmt("checking '%s' for updates", element.source->attrPath));
|
||||
|
||||
InstallableFlake installable(
|
||||
auto installable = std::make_shared<InstallableFlake>(
|
||||
this,
|
||||
getEvalState(),
|
||||
FlakeRef(element.source->originalRef),
|
||||
"",
|
||||
{element.source->attrPath},
|
||||
{},
|
||||
Strings{element.source->attrPath},
|
||||
Strings{},
|
||||
lockFlags);
|
||||
|
||||
auto [attrPath, resolvedRef, drv] = installable.toDerivation();
|
||||
auto [attrPath, resolvedRef, drv] = installable->toDerivation();
|
||||
|
||||
if (element.source->resolvedRef == resolvedRef) continue;
|
||||
|
||||
printInfo("upgrading '%s' from flake '%s' to '%s'",
|
||||
element.source->attrPath, element.source->resolvedRef, resolvedRef);
|
||||
|
||||
if (!drv.outPath)
|
||||
throw UnimplementedError("CA derivations are not yet supported by 'nix profile'");
|
||||
element.storePaths = {*drv.outPath}; // FIXME
|
||||
element.source = ProfileElementSource{
|
||||
installable.flakeRef,
|
||||
installable->flakeRef,
|
||||
resolvedRef,
|
||||
attrPath,
|
||||
};
|
||||
|
||||
pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, {drv.outputName}});
|
||||
installables.push_back(installable);
|
||||
indices.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (upgradedCount == 0) {
|
||||
for (auto & matcher : matchers) {
|
||||
if (const size_t * index = std::get_if<size_t>(&matcher)){
|
||||
warn("'%d' is not a valid index in profile", *index);
|
||||
warn("'%d' is not a valid index", *index);
|
||||
} else if (const Path * path = std::get_if<Path>(&matcher)){
|
||||
warn("'%s' does not match any paths in profile", *path);
|
||||
warn("'%s' does not match any paths", *path);
|
||||
} else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){
|
||||
warn("'%s' does not match any packages in profile", regex->pattern);
|
||||
warn("'%s' does not match any packages", regex->pattern);
|
||||
}
|
||||
}
|
||||
warn ("Use 'nix profile list' to see the current profile.");
|
||||
}
|
||||
|
||||
store->buildPaths(pathsToBuild);
|
||||
auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
|
||||
|
||||
for (size_t i = 0; i < installables.size(); ++i) {
|
||||
auto & installable = installables.at(i);
|
||||
auto & element = manifest.elements[indices.at(i)];
|
||||
element.updateStorePaths(getEvalStore(), store, *installable);
|
||||
}
|
||||
|
||||
updateProfile(manifest.build(store));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,13 +384,12 @@ StorePath NixRepl::getDerivationPath(Value & v) {
|
|||
auto drvInfo = getDerivation(*state, v, false);
|
||||
if (!drvInfo)
|
||||
throw Error("expression does not evaluate to a derivation, so I can't build it");
|
||||
Path drvPathRaw = drvInfo->queryDrvPath();
|
||||
if (drvPathRaw == "")
|
||||
throw Error("expression did not evaluate to a valid derivation (no drv path)");
|
||||
StorePath drvPath = state->store->parseStorePath(drvPathRaw);
|
||||
if (!state->store->isValidPath(drvPath))
|
||||
throw Error("expression did not evaluate to a valid derivation (invalid drv path)");
|
||||
return drvPath;
|
||||
auto drvPath = drvInfo->queryDrvPath();
|
||||
if (!drvPath)
|
||||
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
|
||||
if (!state->store->isValidPath(*drvPath))
|
||||
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
|
||||
return *drvPath;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -780,8 +779,11 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
|||
str << "«derivation ";
|
||||
Bindings::iterator i = v.attrs->find(state->sDrvPath);
|
||||
PathSet context;
|
||||
Path drvPath = i != v.attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "???";
|
||||
str << drvPath << "»";
|
||||
if (i != v.attrs->end())
|
||||
str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
|
||||
else
|
||||
str << "???";
|
||||
str << "»";
|
||||
}
|
||||
|
||||
else if (maxDepth > 0) {
|
||||
|
|
@ -798,7 +800,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
|||
else
|
||||
printStringValue(str, i.first.c_str());
|
||||
str << " = ";
|
||||
if (seen.find(i.second) != seen.end())
|
||||
if (seen.count(i.second))
|
||||
str << "«repeated»";
|
||||
else
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
|
|||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto outPaths = toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
|
||||
auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
|
||||
|
||||
auto accessor = store->getFSAccessor();
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct CmdShowDerivation : InstallablesCommand
|
|||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto drvPaths = toDerivations(store, installables, true);
|
||||
auto drvPaths = Installable::toDerivations(store, installables, true);
|
||||
|
||||
if (recursive) {
|
||||
StorePathSet closure;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "common-args.hh"
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
|
|
@ -32,12 +33,14 @@ struct CmdStoreDelete : StorePathsCommand
|
|||
|
||||
void run(ref<Store> store, std::vector<StorePath> && storePaths) override
|
||||
{
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
|
||||
for (auto & path : storePaths)
|
||||
options.pathsToDelete.insert(path);
|
||||
|
||||
GCResults results;
|
||||
PrintFreed freed(true, results);
|
||||
store->collectGarbage(options, results);
|
||||
gcStore.collectGarbage(options, results);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "common-args.hh"
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "gc-store.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
|
|
@ -33,10 +34,12 @@ struct CmdStoreGC : StoreCommand, MixDryRun
|
|||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto & gcStore = requireGcStore(*store);
|
||||
|
||||
options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead;
|
||||
GCResults results;
|
||||
PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
|
||||
store->collectGarbage(options, results);
|
||||
gcStore.collectGarbage(options, results);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
void run(ref<Store> store) override
|
||||
{
|
||||
auto package = parseInstallable(store, _package);
|
||||
auto packagePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
|
||||
auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
|
||||
auto dependency = parseInstallable(store, _dependency);
|
||||
auto dependencyPath = toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
|
||||
auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
|
||||
auto dependencyPathHash = dependencyPath.hashPart();
|
||||
|
||||
StorePathSet closure;
|
||||
|
|
@ -171,12 +171,6 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
node.visited ? "\e[38;5;244m" : "",
|
||||
firstPad != "" ? "→ " : "",
|
||||
pathS);
|
||||
} else {
|
||||
logger->cout("%s%s%s%s" ANSI_NORMAL,
|
||||
firstPad,
|
||||
node.visited ? "\e[38;5;244m" : "",
|
||||
firstPad != "" ? treeLast : "",
|
||||
pathS);
|
||||
}
|
||||
|
||||
if (node.path == dependencyPath && !all
|
||||
|
|
@ -184,7 +178,7 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
throw BailOut();
|
||||
|
||||
if (node.visited) return;
|
||||
node.visited = true;
|
||||
if (precise) node.visited = true;
|
||||
|
||||
/* Sort the references by distance to `dependency` to
|
||||
ensure that the shortest path is printed first. */
|
||||
|
|
@ -267,6 +261,16 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
if (!all) break;
|
||||
}
|
||||
|
||||
if (!precise) {
|
||||
auto pathS = store->printStorePath(ref.second->path);
|
||||
logger->cout("%s%s%s%s" ANSI_NORMAL,
|
||||
firstPad,
|
||||
ref.second->visited ? "\e[38;5;244m" : "",
|
||||
last ? treeLast : treeConn,
|
||||
pathS);
|
||||
node.visited = true;
|
||||
}
|
||||
|
||||
printNode(*ref.second,
|
||||
tailPad + (last ? treeNull : treeLine),
|
||||
tailPad + (last ? treeNull : treeLine));
|
||||
|
|
@ -275,6 +279,9 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
|
||||
RunPager pager;
|
||||
try {
|
||||
if (!precise) {
|
||||
logger->cout("%s", store->printStorePath(graph.at(packagePath).path));
|
||||
}
|
||||
printNode(graph.at(packagePath), "", "");
|
||||
} catch (BailOut & ) { }
|
||||
}
|
||||
|
|
|
|||
9
tests/bash-profile.sh
Normal file
9
tests/bash-profile.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
source common.sh
|
||||
|
||||
sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../scripts/nix-profile.sh.in > $TEST_ROOT/nix-profile.sh
|
||||
|
||||
user=$(whoami)
|
||||
rm -rf $TEST_HOME $TEST_ROOT/profile-var
|
||||
mkdir -p $TEST_HOME
|
||||
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set"
|
||||
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency
|
||||
|
|
@ -2,7 +2,7 @@ source common.sh
|
|||
|
||||
file=build-hook-ca-floating.nix
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations/' "$NIX_CONF_DIR"/nix.conf
|
||||
enableFeatures "ca-derivations ca-references"
|
||||
|
||||
CONTENT_ADDRESSED=true
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ testCutoffFor () {
|
|||
}
|
||||
|
||||
testCutoff () {
|
||||
# Don't directly build depenentCA, that way we'll make sure we dodn't rely on
|
||||
# Don't directly build dependentCA, that way we'll make sure we don't rely on
|
||||
# dependent derivations always being already built.
|
||||
#testDerivation dependentCA
|
||||
testCutoffFor transitivelyDependentCA
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
source ../common.sh
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf
|
||||
enableFeatures "ca-derivations ca-references"
|
||||
|
||||
restartDaemon
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ source ./common.sh
|
|||
|
||||
requireDaemonNewerThan "2.4pre20210625"
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf
|
||||
|
||||
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
|
||||
export REMOTE_STORE="file://$REMOTE_STORE_DIR"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
source common.sh
|
||||
|
||||
# Globally enable the ca derivations experimental flag
|
||||
sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
|
||||
|
||||
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
|
||||
export REMOTE_STORE="file://$REMOTE_STORE_DIR"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
source common.sh
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
|
||||
|
||||
FLAKE_PATH=path:$PWD
|
||||
|
||||
nix run --no-write-lock-file $FLAKE_PATH#runnable
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
source common.sh
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
|
||||
|
||||
CONTENT_ADDRESSED=true
|
||||
cd ..
|
||||
source ./nix-shell.sh
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ source common.sh
|
|||
|
||||
requireDaemonNewerThan "2.4pre20210626"
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
|
||||
|
||||
export NIX_TESTS_CA_BY_DEFAULT=1
|
||||
cd ..
|
||||
source ./post-hook.sh
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ source common.sh
|
|||
|
||||
requireDaemonNewerThan "2.4pre20210623"
|
||||
|
||||
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
|
||||
|
||||
export NIX_TESTS_CA_BY_DEFAULT=1
|
||||
cd ..
|
||||
source ./recursive.sh
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
# Globally enable the ca derivations experimental flag
|
||||
sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
|
||||
|
||||
clearStore
|
||||
clearCache
|
||||
|
||||
|
|
|
|||
|
|
@ -87,15 +87,20 @@ startDaemon() {
|
|||
if [[ "$NIX_REMOTE" == daemon ]]; then
|
||||
return
|
||||
fi
|
||||
# Start the daemon, wait for the socket to appear. !!!
|
||||
# ‘nix-daemon’ should have an option to fork into the background.
|
||||
# Start the daemon, wait for the socket to appear.
|
||||
rm -f $NIX_DAEMON_SOCKET_PATH
|
||||
PATH=$DAEMON_PATH nix daemon &
|
||||
PATH=$DAEMON_PATH nix-daemon&
|
||||
pidDaemon=$!
|
||||
for ((i = 0; i < 300; i++)); do
|
||||
if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then break; fi
|
||||
if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then
|
||||
DAEMON_STARTED=1
|
||||
break;
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
pidDaemon=$!
|
||||
if [[ -z ${DAEMON_STARTED+x} ]]; then
|
||||
fail "Didn’t manage to start the daemon"
|
||||
fi
|
||||
trap "killDaemon" EXIT
|
||||
export NIX_REMOTE=daemon
|
||||
}
|
||||
|
|
@ -103,10 +108,10 @@ startDaemon() {
|
|||
killDaemon() {
|
||||
kill $pidDaemon
|
||||
for i in {0..100}; do
|
||||
kill -0 $pidDaemon || break
|
||||
kill -0 $pidDaemon 2> /dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
kill -9 $pidDaemon || true
|
||||
kill -9 $pidDaemon 2> /dev/null || true
|
||||
wait $pidDaemon || true
|
||||
trap "" EXIT
|
||||
}
|
||||
|
|
@ -171,6 +176,11 @@ buggyNeedLocalStore () {
|
|||
needLocalStore
|
||||
}
|
||||
|
||||
enableFeatures() {
|
||||
local features="$1"
|
||||
sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf
|
||||
}
|
||||
|
||||
set -x
|
||||
|
||||
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:
|
|||
|
||||
cmp $outPath fetchurl.sh
|
||||
|
||||
# Do not re-fetch paths already present.
|
||||
outPath2=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:///does-not-exist/must-remain-unused/fetchurl.sh --argstr sha256 $hash --no-out-link)
|
||||
test "$outPath" == "$outPath2"
|
||||
|
||||
# Now using a base-64 hash.
|
||||
clearStore
|
||||
|
||||
|
|
|
|||
|
|
@ -89,10 +89,11 @@ nix_tests = \
|
|||
build.sh \
|
||||
ca/nix-run.sh \
|
||||
db-migration.sh \
|
||||
nix-profile.sh \
|
||||
bash-profile.sh \
|
||||
pass-as-file.sh \
|
||||
describe-stores.sh \
|
||||
store-ping.sh
|
||||
store-ping.sh \
|
||||
nix-profile.sh
|
||||
|
||||
ifeq ($(HAVE_LIBCPUID), 1)
|
||||
nix_tests += compute-levels.sh
|
||||
|
|
|
|||
|
|
@ -1,9 +1,97 @@
|
|||
source common.sh
|
||||
|
||||
sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../scripts/nix-profile.sh.in > $TEST_ROOT/nix-profile.sh
|
||||
clearStore
|
||||
clearProfiles
|
||||
|
||||
user=$(whoami)
|
||||
rm -rf $TEST_HOME $TEST_ROOT/profile-var
|
||||
mkdir -p $TEST_HOME
|
||||
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set"
|
||||
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency
|
||||
enableFeatures "ca-derivations ca-references"
|
||||
restartDaemon
|
||||
|
||||
# Make a flake.
|
||||
flake1Dir=$TEST_ROOT/flake1
|
||||
mkdir -p $flake1Dir
|
||||
|
||||
cat > $flake1Dir/flake.nix <<EOF
|
||||
{
|
||||
description = "Bla bla";
|
||||
|
||||
outputs = { self }: with import ./config.nix; rec {
|
||||
packages.$system.default = mkDerivation {
|
||||
name = "profile-test-\${builtins.readFile ./version}";
|
||||
builder = builtins.toFile "builder.sh"
|
||||
''
|
||||
mkdir -p \$out/bin
|
||||
cat > \$out/bin/hello <<EOF
|
||||
#! ${shell}
|
||||
echo Hello \${builtins.readFile ./who}
|
||||
EOF
|
||||
chmod +x \$out/bin/hello
|
||||
echo DONE
|
||||
'';
|
||||
__contentAddressed = import ./ca.nix;
|
||||
outputHashMode = "recursive";
|
||||
outputHashAlgo = "sha256";
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
printf World > $flake1Dir/who
|
||||
printf 1.0 > $flake1Dir/version
|
||||
printf false > $flake1Dir/ca.nix
|
||||
|
||||
cp ./config.nix $flake1Dir/
|
||||
|
||||
# Test upgrading from nix-env.
|
||||
nix-env -f ./user-envs.nix -i foo-1.0
|
||||
nix profile list | grep '0 - - .*-foo-1.0'
|
||||
nix profile install $flake1Dir -L
|
||||
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
|
||||
nix profile history
|
||||
nix profile history | grep "packages.$system.default: ∅ -> 1.0"
|
||||
nix profile diff-closures | grep 'env-manifest.nix: ε → ∅'
|
||||
|
||||
# Test upgrading a package.
|
||||
printf NixOS > $flake1Dir/who
|
||||
printf 2.0 > $flake1Dir/version
|
||||
nix profile upgrade 1
|
||||
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello NixOS" ]]
|
||||
nix profile history | grep "packages.$system.default: 1.0 -> 2.0"
|
||||
|
||||
# Test 'history', 'diff-closures'.
|
||||
nix profile diff-closures
|
||||
|
||||
# Test rollback.
|
||||
nix profile rollback
|
||||
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
|
||||
|
||||
# Test uninstall.
|
||||
[ -e $TEST_HOME/.nix-profile/bin/foo ]
|
||||
nix profile remove 0
|
||||
(! [ -e $TEST_HOME/.nix-profile/bin/foo ])
|
||||
nix profile history | grep 'foo: 1.0 -> ∅'
|
||||
nix profile diff-closures | grep 'Version 3 -> 4'
|
||||
|
||||
# Test installing a non-flake package.
|
||||
nix profile install --file ./simple.nix ''
|
||||
[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
|
||||
nix profile remove 1
|
||||
nix profile install $(nix-build --no-out-link ./simple.nix)
|
||||
[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
|
||||
|
||||
# Test wipe-history.
|
||||
nix profile wipe-history
|
||||
[[ $(nix profile history | grep Version | wc -l) -eq 1 ]]
|
||||
|
||||
# Test upgrade to CA package.
|
||||
printf true > $flake1Dir/ca.nix
|
||||
printf 3.0 > $flake1Dir/version
|
||||
nix profile upgrade 0
|
||||
nix profile history | grep "packages.$system.default: 1.0 -> 3.0"
|
||||
|
||||
# Test new install of CA package.
|
||||
nix profile remove 0
|
||||
printf 4.0 > $flake1Dir/version
|
||||
printf Utrecht > $flake1Dir/who
|
||||
nix profile install $flake1Dir
|
||||
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello Utrecht" ]]
|
||||
[[ $(nix path-info --json $(realpath $TEST_HOME/.nix-profile/bin/hello) | jq -r .[].ca) =~ fixed:r:sha256: ]]
|
||||
|
|
|
|||
|
|
@ -26,10 +26,14 @@ test_tarball() {
|
|||
nix-build -o $TEST_ROOT/result '<foo>' -I foo=file://$tarball
|
||||
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"
|
||||
# Do not re-fetch paths already present
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTarball { url = file:///does-not-exist/must-remain-unused/$tarball; sha256 = \"$hash\"; })"
|
||||
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)"
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })"
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })"
|
||||
# Do not re-fetch paths already present
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file:///does-not-exist/must-remain-unused/$tarball; narHash = \"$hash\"; })"
|
||||
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input'
|
||||
|
||||
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" >&2
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ clearProfiles
|
|||
# Query installed: should be empty.
|
||||
test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 0
|
||||
|
||||
mkdir -p $TEST_HOME
|
||||
nix-env --switch-profile $profiles/test
|
||||
|
||||
# Query available: should contain several.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue