aboutsummaryrefslogtreecommitdiff
path: root/src/nix-env
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2023-04-06 13:15:50 +0200
committerEelco Dolstra <edolstra@gmail.com>2023-04-06 13:15:50 +0200
commit94812cca98fbb157e5f64a15a85a2b852d289feb (patch)
tree2f02c31fc42c7286f3c35dfd3ff1a88f235ab65b /src/nix-env
parent5256ba6d87403f2b58ec4586c26d8fb14027252f (diff)
Backport SourcePath from the lazy-trees branch
This introduces the SourcePath type from lazy-trees as an abstraction for accessing files from inputs that may not be materialized in the real filesystem (e.g. Git repositories). Currently, however, it's just a wrapper around CanonPath, so it shouldn't change any behaviour. (On lazy-trees, SourcePath is a <InputAccessor, CanonPath> tuple.)
Diffstat (limited to 'src/nix-env')
-rw-r--r--src/nix-env/nix-env.cc70
-rw-r--r--src/nix-env/user-env.cc6
2 files changed, 39 insertions, 37 deletions
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index f076ffdb0..0081bab25 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -44,7 +44,7 @@ typedef enum {
struct InstallSourceInfo
{
InstallSourceType type;
- Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
+ std::shared_ptr<SourcePath> nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
Path profile; /* for srcProfile */
std::string systemFilter; /* for srcNixExprDrvs */
Bindings * autoArgs;
@@ -92,9 +92,11 @@ static bool parseInstallSourceOptions(Globals & globals,
}
-static bool isNixExpr(const Path & path, struct stat & st)
+static bool isNixExpr(const SourcePath & path, struct InputAccessor::Stat & st)
{
- return S_ISREG(st.st_mode) || (S_ISDIR(st.st_mode) && pathExists(path + "/default.nix"));
+ return
+ st.type == InputAccessor::tRegular
+ || (st.type == InputAccessor::tDirectory && (path + "default.nix").pathExists());
}
@@ -102,10 +104,10 @@ static constexpr size_t maxAttrs = 1024;
static void getAllExprs(EvalState & state,
- const Path & path, StringSet & seen, BindingsBuilder & attrs)
+ const SourcePath & path, StringSet & seen, BindingsBuilder & attrs)
{
StringSet namesSorted;
- for (auto & i : readDirectory(path)) namesSorted.insert(i.name);
+ for (auto & [name, _] : path.readDirectory()) namesSorted.insert(name);
for (auto & i : namesSorted) {
/* Ignore the manifest.nix used by profiles. This is
@@ -113,13 +115,16 @@ static void getAllExprs(EvalState & state,
are implemented using profiles). */
if (i == "manifest.nix") continue;
- Path path2 = path + "/" + i;
+ SourcePath path2 = path + i;
- struct stat st;
- if (stat(path2.c_str(), &st) == -1)
+ InputAccessor::Stat st;
+ try {
+ st = path2.resolveSymlinks().lstat();
+ } catch (Error &) {
continue; // ignore dangling symlinks in ~/.nix-defexpr
+ }
- if (isNixExpr(path2, st) && (!S_ISREG(st.st_mode) || hasSuffix(path2, ".nix"))) {
+ if (isNixExpr(path2, st) && (st.type != InputAccessor::tRegular || hasSuffix(path2.baseName(), ".nix"))) {
/* Strip off the `.nix' filename suffix (if applicable),
otherwise the attribute cannot be selected with the
`-A' option. Useful if you want to stick a Nix
@@ -129,21 +134,20 @@ static void getAllExprs(EvalState & state,
attrName = std::string(attrName, 0, attrName.size() - 4);
if (!seen.insert(attrName).second) {
std::string suggestionMessage = "";
- if (path2.find("channels") != std::string::npos && path.find("channels") != std::string::npos) {
+ if (path2.path.abs().find("channels") != std::string::npos && path.path.abs().find("channels") != std::string::npos)
suggestionMessage = fmt("\nsuggestion: remove '%s' from either the root channels or the user channels", attrName);
- }
printError("warning: name collision in input Nix expressions, skipping '%1%'"
"%2%", path2, suggestionMessage);
continue;
}
/* Load the expression on demand. */
auto vArg = state.allocValue();
- vArg->mkString(path2);
+ vArg->mkString(path2.path.abs());
if (seen.size() == maxAttrs)
throw Error("too many Nix expressions in directory '%1%'", path);
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg);
}
- else if (S_ISDIR(st.st_mode))
+ else if (st.type == InputAccessor::tDirectory)
/* `path2' is a directory (with no default.nix in it);
recurse into it. */
getAllExprs(state, path2, seen, attrs);
@@ -152,11 +156,9 @@ static void getAllExprs(EvalState & state,
-static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
+static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v)
{
- struct stat st;
- if (stat(path.c_str(), &st) == -1)
- throw SysError("getting information about '%1%'", path);
+ auto st = path.resolveSymlinks().lstat();
if (isNixExpr(path, st))
state.evalFile(path, v);
@@ -167,7 +169,7 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
set flat, not nested, to make it easier for a user to have a
~/.nix-defexpr directory that includes some system-wide
directory). */
- else if (S_ISDIR(st.st_mode)) {
+ else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.buildBindings(maxAttrs);
attrs.alloc("_combineChannels").mkList(0);
StringSet seen;
@@ -179,7 +181,7 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
}
-static void loadDerivations(EvalState & state, Path nixExprPath,
+static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
std::string systemFilter, Bindings & autoArgs,
const std::string & pathPrefix, DrvInfos & elems)
{
@@ -390,7 +392,7 @@ static void queryInstSources(EvalState & state,
/* Load the derivations from the (default or specified)
Nix expression. */
DrvInfos allElems;
- loadDerivations(state, instSource.nixExprPath,
+ loadDerivations(state, *instSource.nixExprPath,
instSource.systemFilter, *instSource.autoArgs, "", allElems);
elems = filterBySelector(state, allElems, args, newestOnly);
@@ -407,10 +409,10 @@ static void queryInstSources(EvalState & state,
case srcNixExprs: {
Value vArg;
- loadSourceExpr(state, instSource.nixExprPath, vArg);
+ loadSourceExpr(state, *instSource.nixExprPath, vArg);
for (auto & i : args) {
- Expr * eFun = state.parseExprFromString(i, absPath("."));
+ Expr * eFun = state.parseExprFromString(i, state.rootPath(CanonPath::fromCwd()));
Value vFun, vTmp;
state.eval(eFun, vFun);
vTmp.mkApp(&vFun, &vArg);
@@ -462,7 +464,7 @@ static void queryInstSources(EvalState & state,
case srcAttrPath: {
Value vRoot;
- loadSourceExpr(state, instSource.nixExprPath, vRoot);
+ loadSourceExpr(state, *instSource.nixExprPath, vRoot);
for (auto & i : args) {
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
@@ -1030,7 +1032,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
installedElems = queryInstalled(*globals.state, globals.profile);
if (source == sAvailable || compareVersions)
- loadDerivations(*globals.state, globals.instSource.nixExprPath,
+ loadDerivations(*globals.state, *globals.instSource.nixExprPath,
globals.instSource.systemFilter, *globals.instSource.autoArgs,
attrPath, availElems);
@@ -1395,22 +1397,20 @@ static int main_nix_env(int argc, char * * argv)
Globals globals;
globals.instSource.type = srcUnknown;
- {
- Path nixExprPath = settings.useXDGBaseDirectories ? createNixStateDir() + "/defexpr" : getHome() + "/.nix-defexpr";
- globals.instSource.nixExprPath = nixExprPath;
- }
globals.instSource.systemFilter = "*";
- if (!pathExists(globals.instSource.nixExprPath)) {
+ Path nixExprPath = settings.useXDGBaseDirectories ? createNixStateDir() + "/defexpr" : getHome() + "/.nix-defexpr";
+
+ if (!pathExists(nixExprPath)) {
try {
- createDirs(globals.instSource.nixExprPath);
+ createDirs(nixExprPath);
replaceSymlink(
defaultChannelsDir(),
- globals.instSource.nixExprPath + "/channels");
+ nixExprPath + "/channels");
if (getuid() != 0)
replaceSymlink(
rootChannelsDir(),
- globals.instSource.nixExprPath + "/channels_root");
+ nixExprPath + "/channels_root");
} catch (Error &) { }
}
@@ -1517,8 +1517,10 @@ static int main_nix_env(int argc, char * * argv)
globals.state = std::shared_ptr<EvalState>(new EvalState(myArgs.searchPath, store));
globals.state->repair = repair;
- if (file != "")
- globals.instSource.nixExprPath = lookupFileArg(*globals.state, file);
+ globals.instSource.nixExprPath = std::make_shared<SourcePath>(
+ file != ""
+ ? lookupFileArg(*globals.state, file)
+ : globals.state->rootPath(CanonPath(nixExprPath)));
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index 745e9e174..f70381bf2 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -19,10 +19,10 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
DrvInfos elems;
if (pathExists(userEnv + "/manifest.json"))
throw Error("profile '%s' is incompatible with 'nix-env'; please use 'nix profile' instead", userEnv);
- Path manifestFile = userEnv + "/manifest.nix";
+ auto manifestFile = userEnv + "/manifest.nix";
if (pathExists(manifestFile)) {
Value v;
- state.evalFile(manifestFile, v);
+ state.evalFile(state.rootPath(CanonPath(manifestFile)), v);
Bindings & bindings(*state.allocBindings(0));
getDerivations(state, v, "", bindings, elems, false);
}
@@ -114,7 +114,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
Value envBuilder;
state.eval(state.parseExprFromString(
#include "buildenv.nix.gen.hh"
- , "/"), envBuilder);
+ , state.rootPath(CanonPath::root)), envBuilder);
/* Construct a Nix expression that calls the user environment
builder with the manifest as argument. */