aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/src/language/advanced-attributes.md6
-rw-r--r--doc/manual/src/release-notes/rl-next.md12
-rw-r--r--src/libexpr/eval.cc36
-rw-r--r--src/libexpr/eval.hh13
-rw-r--r--src/libstore/build/local-derivation-goal.cc27
-rw-r--r--src/libstore/local-store.cc16
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/profiles.cc18
-rw-r--r--src/libstore/profiles.hh4
-rw-r--r--src/libstore/store-api.cc8
-rw-r--r--src/libstore/store-api.hh3
-rw-r--r--src/libutil/experimental-features.cc1
-rw-r--r--src/libutil/experimental-features.hh1
-rw-r--r--src/libutil/tests/url.cc21
-rw-r--r--src/libutil/url.cc6
-rw-r--r--src/libutil/util.cc18
-rw-r--r--src/libutil/util.hh3
-rwxr-xr-xsrc/nix-channel/nix-channel.cc4
-rw-r--r--src/nix/daemon.cc1
-rw-r--r--src/nix/flake.cc29
-rw-r--r--src/nix/verify.cc6
-rw-r--r--tests/check-refs.nix7
-rw-r--r--tests/check-refs.sh9
-rw-r--r--tests/common.sh.in2
-rw-r--r--tests/flakes/common.sh6
-rw-r--r--tests/flakes/init.sh4
-rw-r--r--tests/flakes/show.sh39
-rw-r--r--tests/local.mk2
-rw-r--r--tests/nix_path.sh5
-rw-r--r--tests/remote-store.sh4
-rw-r--r--tests/restricted.sh3
-rw-r--r--tests/user-envs-migration.sh35
32 files changed, 268 insertions, 83 deletions
diff --git a/doc/manual/src/language/advanced-attributes.md b/doc/manual/src/language/advanced-attributes.md
index 2e7e80ed0..f02425b13 100644
--- a/doc/manual/src/language/advanced-attributes.md
+++ b/doc/manual/src/language/advanced-attributes.md
@@ -207,13 +207,13 @@ Derivations can declare some infrequently used optional attributes.
the hash in either hexadecimal or base-32 notation. (See the
[`nix-hash` command](../command-ref/nix-hash.md) for information
about converting to and from base-32 notation.)
-
+
- [`__contentAddressed`]{#adv-attr-__contentAddressed}
If this **experimental** attribute is set to true, then the derivation
outputs will be stored in a content-addressed location rather than the
traditional input-addressed one.
- This only has an effect if the `ca-derivation` experimental feature is enabled.
-
+ This only has an effect if the `ca-derivations` experimental feature is enabled.
+
Setting this attribute also requires setting `outputHashMode` and `outputHashAlgo` like for *fixed-output derivations* (see above).
- [`passAsFile`]{#adv-attr-passAsFile}\
diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
index 8a79703ab..7e8344e63 100644
--- a/doc/manual/src/release-notes/rl-next.md
+++ b/doc/manual/src/release-notes/rl-next.md
@@ -8,3 +8,15 @@
discovered by making multiple syscalls. This change makes these operations
lazy such that these lookups will only be performed if the attribute is used.
This optimization affects a minority of filesystems and operating systems.
+
+* In derivations that use structured attributes, you can now use `unsafeDiscardReferences`
+ to disable scanning a given output for runtime dependencies:
+ ```nix
+ __structuredAttrs = true;
+ unsafeDiscardReferences.out = true;
+ ```
+ This is useful e.g. when generating self-contained filesystem images with
+ their own embedded Nix store: hashes found inside such an image refer
+ to the embedded store and not to the host's Nix store.
+
+ This requires the `discard-references` experimental feature.
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 1828b8c2e..a48968656 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -519,6 +519,7 @@ EvalState::EvalState(
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
/* Initialise the Nix expression search path. */
+ evalSettings.nixPath.setDefault(evalSettings.getDefaultNixPath());
if (!evalSettings.pureEval) {
for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : evalSettings.nixPath.get()) addToSearchPath(i);
@@ -2472,30 +2473,35 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
EvalSettings::EvalSettings()
{
- auto var = getEnv("NIX_PATH");
- if (var) nixPath = parseNixPath(*var);
}
+/* impure => NIX_PATH or a default path
+ * restrict-eval => NIX_PATH
+ * pure-eval => empty
+ */
Strings EvalSettings::getDefaultNixPath()
{
- Strings res;
- auto add = [&](const Path & p, const std::string & s = std::string()) {
- if (pathExists(p)) {
- if (s.empty()) {
- res.push_back(p);
- } else {
- res.push_back(s + "=" + p);
- }
- }
- };
+ if (pureEval)
+ return {};
+
+ auto var = getEnv("NIX_PATH");
+ if (var) {
+ return parseNixPath(*var);
+ } else if (restrictEval) {
+ return {};
+ } else {
+ Strings res;
+ auto add = [&](const Path & p, const std::optional<std::string> & s = std::nullopt) {
+ if (pathExists(p))
+ res.push_back(s ? *s + "=" + p : p);
+ };
- if (!evalSettings.restrictEval && !evalSettings.pureEval) {
add(getHome() + "/.nix-defexpr/channels");
add(settings.nixStateDir + "/profiles/per-user/root/channels/nixpkgs", "nixpkgs");
add(settings.nixStateDir + "/profiles/per-user/root/channels");
- }
- return res;
+ return res;
+ }
}
bool EvalSettings::isPseudoUrl(std::string_view s)
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index e4d5906bd..2340ef67b 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -570,7 +570,7 @@ struct EvalSettings : Config
{
EvalSettings();
- static Strings getDefaultNixPath();
+ Strings getDefaultNixPath();
static bool isPseudoUrl(std::string_view s);
@@ -580,8 +580,15 @@ struct EvalSettings : Config
"Whether builtin functions that allow executing native code should be enabled."};
Setting<Strings> nixPath{
- this, getDefaultNixPath(), "nix-path",
- "List of directories to be searched for `<...>` file references."};
+ this, {}, "nix-path",
+ R"(
+ List of directories to be searched for `<...>` file references.
+
+ If [pure evaluation](#conf-pure-eval) is disabled,
+ this is initialised using the [`NIX_PATH`](@docroot@/command-ref/env-common.md#env-NIX_PATH)
+ environment variable, or, if it is unset and [restricted evaluation](#conf-restrict-eval)
+ is disabled, a default search path including the user's and `root`'s channels.
+ )"};
Setting<bool> restrictEval{
this, false, "restrict-eval",
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 9ab9b17fe..572f71045 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -1517,7 +1517,7 @@ void LocalDerivationGoal::startDaemon()
try {
daemon::processConnection(store, from, to,
daemon::NotTrusted, daemon::Recursive,
- [&](Store & store) { store.createUser("nobody", 65535); });
+ [&](Store & store) {});
debug("terminated daemon connection");
} catch (SysError &) {
ignoreException();
@@ -2323,11 +2323,28 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
buildUser ? std::optional(buildUser->getUIDRange()) : std::nullopt,
inodesSeen);
- debug("scanning for references for output '%s' in temp location '%s'", outputName, actualPath);
+ bool discardReferences = false;
+ if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
+ if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
+ settings.requireExperimentalFeature(Xp::DiscardReferences);
+ if (auto output = get(*udr, outputName)) {
+ if (!output->is_boolean())
+ throw Error("attribute 'unsafeDiscardReferences.\"%s\"' of derivation '%s' must be a Boolean", outputName, drvPath.to_string());
+ discardReferences = output->get<bool>();
+ }
+ }
+ }
- /* Pass blank Sink as we are not ready to hash data at this stage. */
- NullSink blank;
- auto references = scanForReferences(blank, actualPath, referenceablePaths);
+ StorePathSet references;
+ if (discardReferences)
+ debug("discarding references of output '%s'", outputName);
+ else {
+ debug("scanning for references for output '%s' in temp location '%s'", outputName, actualPath);
+
+ /* Pass blank Sink as we are not ready to hash data at this stage. */
+ NullSink blank;
+ references = scanForReferences(blank, actualPath, referenceablePaths);
+ }
outputReferencesIfUnregistered.insert_or_assign(
outputName,
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index be21e3ca0..82edaa9bf 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -201,8 +201,6 @@ LocalStore::LocalStore(const Params & params)
throw SysError("could not set permissions on '%s' to 755", perUserDir);
}
- createUser(getUserName(), getuid());
-
/* Optionally, create directories and set permissions for a
multi-user install. */
if (getuid() == 0 && settings.buildUsersGroup != "") {
@@ -1824,20 +1822,6 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
}
-void LocalStore::createUser(const std::string & userName, uid_t userId)
-{
- for (auto & dir : {
- fmt("%s/profiles/per-user/%s", stateDir, userName),
- fmt("%s/gcroots/per-user/%s", stateDir, userName)
- }) {
- createDirs(dir);
- if (chmod(dir.c_str(), 0755) == -1)
- throw SysError("changing permissions of directory '%s'", dir);
- if (chown(dir.c_str(), userId, getgid()) == -1)
- throw SysError("changing owner of directory '%s'", dir);
- }
-}
-
std::optional<std::pair<int64_t, Realisation>> LocalStore::queryRealisationCore_(
LocalStore::State & state,
const DrvOutput & id)
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 06d36a7d5..a84eb7c26 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -281,8 +281,6 @@ private:
void signPathInfo(ValidPathInfo & info);
void signRealisation(Realisation &);
- void createUser(const std::string & userName, uid_t userId) override;
-
// XXX: Make a generic `Store` method
FixedOutputHash hashCAPath(
const FileIngestionMethod & method,
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index 3e4188188..b202351ce 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -280,16 +280,24 @@ std::string optimisticLockProfile(const Path & profile)
}
+Path profilesDir()
+{
+ auto profileRoot = getDataDir() + "/nix/profiles";
+ createDirs(profileRoot);
+ return profileRoot;
+}
+
+
Path getDefaultProfile()
{
Path profileLink = getHome() + "/.nix-profile";
try {
+ auto profile =
+ getuid() == 0
+ ? settings.nixStateDir + "/profiles/default"
+ : profilesDir() + "/profile";
if (!pathExists(profileLink)) {
- replaceSymlink(
- getuid() == 0
- ? settings.nixStateDir + "/profiles/default"
- : fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()),
- profileLink);
+ replaceSymlink(profile, profileLink);
}
return absPath(readLink(profileLink), dirOf(profileLink));
} catch (Error &) {
diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh
index 408ca039c..73667a798 100644
--- a/src/libstore/profiles.hh
+++ b/src/libstore/profiles.hh
@@ -68,6 +68,10 @@ void lockProfile(PathLocks & lock, const Path & profile);
rebuilt. */
std::string optimisticLockProfile(const Path & profile);
+/* Creates and returns the path to a directory suitable for storing the user’s
+ profiles. */
+Path profilesDir();
+
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
it. */
Path getDefaultProfile();
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 5130409d4..31bd9318f 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -742,13 +742,13 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
std::condition_variable wakeup;
ThreadPool pool;
- auto doQuery = [&](const Path & path) {
+ auto doQuery = [&](const StorePath & path) {
checkInterrupt();
- queryPathInfo(parseStorePath(path), {[path, this, &state_, &wakeup](std::future<ref<const ValidPathInfo>> fut) {
+ queryPathInfo(path, {[path, this, &state_, &wakeup](std::future<ref<const ValidPathInfo>> fut) {
auto state(state_.lock());
try {
auto info = fut.get();
- state->valid.insert(parseStorePath(path));
+ state->valid.insert(path);
} catch (InvalidPath &) {
} catch (...) {
state->exc = std::current_exception();
@@ -760,7 +760,7 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
};
for (auto & path : paths)
- pool.enqueue(std::bind(doQuery, printStorePath(path))); // FIXME
+ pool.enqueue(std::bind(doQuery, path));
pool.process();
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 9eab4b4e5..5807392a7 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -657,9 +657,6 @@ public:
return toRealPath(printStorePath(storePath));
}
- virtual void createUser(const std::string & userName, uid_t userId)
- { }
-
/*
* Synchronises the options of the client with those of the daemon
* (a no-op when there’s no daemon)
diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc
index e0902971e..58d762ebb 100644
--- a/src/libutil/experimental-features.cc
+++ b/src/libutil/experimental-features.cc
@@ -16,6 +16,7 @@ std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = {
{ Xp::ReplFlake, "repl-flake" },
{ Xp::AutoAllocateUids, "auto-allocate-uids" },
{ Xp::Cgroups, "cgroups" },
+ { Xp::DiscardReferences, "discard-references" },
};
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh
index af775feb0..ac372e03e 100644
--- a/src/libutil/experimental-features.hh
+++ b/src/libutil/experimental-features.hh
@@ -25,6 +25,7 @@ enum struct ExperimentalFeature
ReplFlake,
AutoAllocateUids,
Cgroups,
+ DiscardReferences,
};
/**
diff --git a/src/libutil/tests/url.cc b/src/libutil/tests/url.cc
index c3b233797..e0c438b4d 100644
--- a/src/libutil/tests/url.cc
+++ b/src/libutil/tests/url.cc
@@ -99,6 +99,27 @@ namespace nix {
ASSERT_EQ(parsed, expected);
}
+ TEST(parseURL, parsesFilePlusHttpsUrl) {
+ auto s = "file+https://www.example.org/video.mp4";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "file+https://www.example.org/video.mp4",
+ .base = "https://www.example.org/video.mp4",
+ .scheme = "file+https",
+ .authority = "www.example.org",
+ .path = "/video.mp4",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, rejectsAuthorityInUrlsWithFileTransportation) {
+ auto s = "file://www.example.org/video.mp4";
+ ASSERT_THROW(parseURL(s), Error);
+ }
TEST(parseURL, parseIPv4Address) {
auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello";
diff --git a/src/libutil/url.cc b/src/libutil/url.cc
index 5b7abeb49..4e43455e1 100644
--- a/src/libutil/url.cc
+++ b/src/libutil/url.cc
@@ -30,13 +30,13 @@ ParsedURL parseURL(const std::string & url)
auto & query = match[6];
auto & fragment = match[7];
- auto isFile = scheme.find("file") != std::string::npos;
+ auto transportIsFile = parseUrlScheme(scheme).transport == "file";
- if (authority && *authority != "" && isFile)
+ if (authority && *authority != "" && transportIsFile)
throw BadURL("file:// URL '%s' has unexpected authority '%s'",
url, *authority);
- if (isFile && path.empty())
+ if (transportIsFile && path.empty())
path = "/";
return ParsedURL{
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 993dc1cb6..40faa4bf2 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -537,6 +537,16 @@ std::string getUserName()
return name;
}
+Path getHomeOf(uid_t userId)
+{
+ std::vector<char> buf(16384);
+ struct passwd pwbuf;
+ struct passwd * pw;
+ if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0
+ || !pw || !pw->pw_dir || !pw->pw_dir[0])
+ throw Error("cannot determine user's home directory");
+ return pw->pw_dir;
+}
Path getHome()
{
@@ -558,13 +568,7 @@ Path getHome()
}
}
if (!homeDir) {
- std::vector<char> buf(16384);
- struct passwd pwbuf;
- struct passwd * pw;
- if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
- || !pw || !pw->pw_dir || !pw->pw_dir[0])
- throw Error("cannot determine user's home directory");
- homeDir = pw->pw_dir;
+ homeDir = getHomeOf(geteuid());
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 9b149de80..266da0ae3 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -137,6 +137,9 @@ void deletePath(const Path & path, uint64_t & bytesFreed);
std::string getUserName();
+/* Return the given user's home directory from /etc/passwd. */
+Path getHomeOf(uid_t userId);
+
/* Return $HOME or the user's home directory from /etc/passwd. */
Path getHome();
diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc
index cf52b03b4..263d85eea 100755
--- a/src/nix-channel/nix-channel.cc
+++ b/src/nix-channel/nix-channel.cc
@@ -1,9 +1,11 @@
+#include "profiles.hh"
#include "shared.hh"
#include "globals.hh"
#include "filetransfer.hh"
#include "store-api.hh"
#include "legacy.hh"
#include "fetchers.hh"
+#include "util.hh"
#include <fcntl.h>
#include <regex>
@@ -166,7 +168,7 @@ static int main_nix_channel(int argc, char ** argv)
nixDefExpr = home + "/.nix-defexpr";
// Figure out the name of the channels profile.
- profile = fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName());
+ profile = profilesDir() + "/channels";
enum {
cNone,
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index c527fdb0a..19fbbf155 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -248,7 +248,6 @@ static void daemonLoop()
querySetting("build-users-group", "") == "")
throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!");
#endif
- store.createUser(user, peer.uid);
});
exit(0);
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 020c1b182..d2f68c37c 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -966,6 +966,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
struct CmdFlakeShow : FlakeCommand, MixJSON
{
bool showLegacy = false;
+ bool showAllSystems = false;
CmdFlakeShow()
{
@@ -974,6 +975,11 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
.description = "Show the contents of the `legacyPackages` output.",
.handler = {&showLegacy, true}
});
+ addFlag({
+ .longName = "all-systems",
+ .description = "Show the contents of outputs for all systems.",
+ .handler = {&showAllSystems, true}
+ });
}
std::string description() override
@@ -994,6 +1000,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
auto state = getEvalState();
auto flake = std::make_shared<LockedFlake>(lockFlake());
+ auto localSystem = std::string(settings.thisSystem.get());
std::function<nlohmann::json(
eval_cache::AttrCursor & visitor,
@@ -1084,10 +1091,18 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|| (attrPath.size() == 3 && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells"))
)
{
- if (visitor.isDerivation())
- showDerivation();
- else
- throw Error("expected a derivation");
+ if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
+ if (!json)
+ logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
+ else {
+ logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
+ }
+ } else {
+ if (visitor.isDerivation())
+ showDerivation();
+ else
+ throw Error("expected a derivation");
+ }
}
else if (attrPath.size() > 0 && attrPathS[0] == "hydraJobs") {
@@ -1106,6 +1121,12 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
else {
logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPathS)));
}
+ } else if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
+ if (!json)
+ logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
+ else {
+ logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
+ }
} else {
if (visitor.isDerivation())
showDerivation();
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index efa2434dc..0b306cc11 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -81,14 +81,14 @@ struct CmdVerify : StorePathsCommand
ThreadPool pool;
- auto doPath = [&](const Path & storePath) {
+ auto doPath = [&](const StorePath & storePath) {
try {
checkInterrupt();
MaintainCount<std::atomic<size_t>> mcActive(active);
update();
- auto info = store->queryPathInfo(store->parseStorePath(storePath));
+ auto info = store->queryPathInfo(storePath);
// Note: info->path can be different from storePath
// for binary cache stores when using --all (since we
@@ -173,7 +173,7 @@ struct CmdVerify : StorePathsCommand
};
for (auto & storePath : storePaths)
- pool.enqueue(std::bind(doPath, store->printStorePath(storePath)));
+ pool.enqueue(std::bind(doPath, storePath));
pool.process();
diff --git a/tests/check-refs.nix b/tests/check-refs.nix
index 9d90b0920..99d69a226 100644
--- a/tests/check-refs.nix
+++ b/tests/check-refs.nix
@@ -67,4 +67,11 @@ rec {
disallowedReferences = [test5];
};
+ test11 = makeTest 11 {
+ __structuredAttrs = true;
+ unsafeDiscardReferences.out = true;
+ outputChecks.out.allowedReferences = [];
+ buildCommand = ''echo ${dep} > "''${outputs[out]}"'';
+ };
+
}
diff --git a/tests/check-refs.sh b/tests/check-refs.sh
index 16bbabc40..65a72552a 100644
--- a/tests/check-refs.sh
+++ b/tests/check-refs.sh
@@ -40,3 +40,12 @@ nix-build -o $RESULT check-refs.nix -A test7
# test10 should succeed (no disallowed references).
nix-build -o $RESULT check-refs.nix -A test10
+
+if isDaemonNewer 2.12pre20230103; then
+ enableFeatures discard-references
+ restartDaemon
+
+ # test11 should succeed.
+ test11=$(nix-build -o $RESULT check-refs.nix -A test11)
+ [[ -z $(nix-store -q --references "$test11") ]]
+fi
diff --git a/tests/common.sh.in b/tests/common.sh.in
index 73c2d2309..74bbbc8ca 100644
--- a/tests/common.sh.in
+++ b/tests/common.sh.in
@@ -62,7 +62,7 @@ readLink() {
}
clearProfiles() {
- profiles="$NIX_STATE_DIR"/profiles
+ profiles="$HOME"/.local/share/nix/profiles
rm -rf $profiles
}
diff --git a/tests/flakes/common.sh b/tests/flakes/common.sh
index c333733c2..9d79080cd 100644
--- a/tests/flakes/common.sh
+++ b/tests/flakes/common.sh
@@ -20,9 +20,13 @@ writeSimpleFlake() {
foo = import ./simple.nix;
default = foo;
};
+ packages.someOtherSystem = rec {
+ foo = import ./simple.nix;
+ default = foo;
+ };
# To test "nix flake init".
- legacyPackages.x86_64-linux.hello = import ./simple.nix;
+ legacyPackages.$system.hello = import ./simple.nix;
};
}
EOF
diff --git a/tests/flakes/init.sh b/tests/flakes/init.sh
index 36cb9956a..2d4c77ba1 100644
--- a/tests/flakes/init.sh
+++ b/tests/flakes/init.sh
@@ -41,8 +41,8 @@ cat > $templatesDir/trivial/flake.nix <<EOF
description = "A flake for building Hello World";
outputs = { self, nixpkgs }: {
- packages.x86_64-linux = rec {
- hello = nixpkgs.legacyPackages.x86_64-linux.hello;
+ packages.$system = rec {
+ hello = nixpkgs.legacyPackages.$system.hello;
default = hello;
};
};
diff --git a/tests/flakes/show.sh b/tests/flakes/show.sh
new file mode 100644
index 000000000..995de8dc3
--- /dev/null
+++ b/tests/flakes/show.sh
@@ -0,0 +1,39 @@
+source ./common.sh
+
+flakeDir=$TEST_ROOT/flake
+mkdir -p "$flakeDir"
+
+writeSimpleFlake "$flakeDir"
+cd "$flakeDir"
+
+
+# By default: Only show the packages content for the current system and no
+# legacyPackages at all
+nix flake show --json > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.packages.someOtherSystem.default == {};
+assert show_output.packages.${builtins.currentSystem}.default.name == "simple";
+assert show_output.legacyPackages.${builtins.currentSystem} == {};
+true
+'
+
+# With `--all-systems`, show the packages for all systems
+nix flake show --json --all-systems > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.packages.someOtherSystem.default.name == "simple";
+assert show_output.legacyPackages.${builtins.currentSystem} == {};
+true
+'
+
+# With `--legacy`, show the legacy packages
+nix flake show --json --legacy > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.legacyPackages.${builtins.currentSystem}.hello.name == "simple";
+true
+'
diff --git a/tests/local.mk b/tests/local.mk
index 5ac1ede32..2aaaa67f9 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -17,6 +17,7 @@ nix_tests = \
fetchMercurial.sh \
gc-auto.sh \
user-envs.sh \
+ user-envs-migration.sh \
binary-cache.sh \
multiple-outputs.sh \
ca/build.sh \
@@ -113,6 +114,7 @@ nix_tests = \
store-ping.sh \
fetchClosure.sh \
completions.sh \
+ flakes/show.sh \
impure-derivations.sh \
path-from-hash-part.sh \
toString-path.sh
diff --git a/tests/nix_path.sh b/tests/nix_path.sh
index 2b222b4a1..d16fb4bb2 100644
--- a/tests/nix_path.sh
+++ b/tests/nix_path.sh
@@ -12,3 +12,8 @@ nix-instantiate --eval -E '<by-relative-path/simple.nix>' --restrict-eval
[[ $(nix-instantiate --find-file by-absolute-path/simple.nix) = $PWD/simple.nix ]]
[[ $(nix-instantiate --find-file by-relative-path/simple.nix) = $PWD/simple.nix ]]
+
+unset NIX_PATH
+
+[[ $(nix-instantiate --option nix-path by-relative-path=. --find-file by-relative-path/simple.nix) = "$PWD/simple.nix" ]]
+[[ $(NIX_PATH= nix-instantiate --option nix-path by-relative-path=. --find-file by-relative-path/simple.nix) = "$PWD/simple.nix" ]]
diff --git a/tests/remote-store.sh b/tests/remote-store.sh
index 31210ab47..1ae126794 100644
--- a/tests/remote-store.sh
+++ b/tests/remote-store.sh
@@ -30,7 +30,3 @@ NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2
cmp $TEST_ROOT/d1 $TEST_ROOT/d2
killDaemon
-
-user=$(whoami)
-[ -e $NIX_STATE_DIR/gcroots/per-user/$user ]
-[ -e $NIX_STATE_DIR/profiles/per-user/$user ]
diff --git a/tests/restricted.sh b/tests/restricted.sh
index 9bd16cf51..3b6ee2af1 100644
--- a/tests/restricted.sh
+++ b/tests/restricted.sh
@@ -17,6 +17,9 @@ nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel'
(! nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>')
nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>' -I src=.
+# no default NIX_PATH
+(unset NIX_PATH; ! nix-instantiate --restrict-eval --find-file .)
+
p=$(nix eval --raw --expr "builtins.fetchurl file://$(pwd)/restricted.sh" --impure --restrict-eval --allowed-uris "file://$(pwd)")
cmp $p restricted.sh
diff --git a/tests/user-envs-migration.sh b/tests/user-envs-migration.sh
new file mode 100644
index 000000000..467c28fbb
--- /dev/null
+++ b/tests/user-envs-migration.sh
@@ -0,0 +1,35 @@
+# Test that the migration of user environments
+# (https://github.com/NixOS/nix/pull/5226) does preserve everything
+
+source common.sh
+
+if isDaemonNewer "2.4pre20211005"; then
+ exit 99
+fi
+
+
+killDaemon
+unset NIX_REMOTE
+
+clearStore
+clearProfiles
+rm -rf ~/.nix-profile
+
+# Fill the environment using the older Nix
+PATH_WITH_NEW_NIX="$PATH"
+export PATH="$NIX_DAEMON_PACKAGE/bin:$PATH"
+
+nix-env -f user-envs.nix -i foo-1.0
+nix-env -f user-envs.nix -i bar-0.1
+
+# Migrate to the new profile dir, and ensure that everything’s there
+export PATH="$PATH_WITH_NEW_NIX"
+nix-env -q # Trigger the migration
+( [[ -L ~/.nix-profile ]] && \
+ [[ $(readlink ~/.nix-profile) == ~/.local/share/nix/profiles/profile ]] ) || \
+ fail "The nix profile should point to the new location"
+
+(nix-env -q | grep foo && nix-env -q | grep bar && \
+ [[ -e ~/.nix-profile/bin/foo ]] && \
+ [[ $(nix-env --list-generations | wc -l) == 2 ]]) ||
+ fail "The nix profile should have the same content as before the migration"