nix-env: Use SourcePath

This commit is contained in:
Eelco Dolstra 2022-05-17 00:04:04 +02:00
parent 7617d15458
commit 65e1e49cf7
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -44,7 +44,7 @@ typedef enum {
struct InstallSourceInfo struct InstallSourceInfo
{ {
InstallSourceType type; InstallSourceType type;
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ std::shared_ptr<SourcePath> nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
Path profile; /* for srcProfile */ Path profile; /* for srcProfile */
std::string systemFilter; /* for srcNixExprDrvs */ std::string systemFilter; /* for srcNixExprDrvs */
Bindings * autoArgs; 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, static void getAllExprs(EvalState & state,
const Path & path, StringSet & seen, BindingsBuilder & attrs) const SourcePath & path, StringSet & seen, BindingsBuilder & attrs)
{ {
StringSet namesSorted; StringSet namesSorted;
for (auto & i : readDirectory(path)) namesSorted.insert(i.name); for (auto & [name, _] : path.readDirectory()) namesSorted.insert(name);
for (auto & i : namesSorted) { for (auto & i : namesSorted) {
/* Ignore the manifest.nix used by profiles. This is /* Ignore the manifest.nix used by profiles. This is
@ -113,13 +115,16 @@ static void getAllExprs(EvalState & state,
are implemented using profiles). */ are implemented using profiles). */
if (i == "manifest.nix") continue; if (i == "manifest.nix") continue;
Path path2 = path + "/" + i; SourcePath path2 = path + i;
struct stat st; InputAccessor::Stat st;
if (stat(path2.c_str(), &st) == -1) try {
st = path2.accessor.lstat(path2.path.resolveSymlinks());
} catch (Error &) {
continue; // ignore dangling symlinks in ~/.nix-defexpr 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), /* Strip off the `.nix' filename suffix (if applicable),
otherwise the attribute cannot be selected with the otherwise the attribute cannot be selected with the
`-A' option. Useful if you want to stick a Nix `-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); attrName = std::string(attrName, 0, attrName.size() - 4);
if (!seen.insert(attrName).second) { if (!seen.insert(attrName).second) {
std::string suggestionMessage = ""; 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); 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%'" printError("warning: name collision in input Nix expressions, skipping '%1%'"
"%2%", path2, suggestionMessage); "%2%", path2, suggestionMessage);
continue; continue;
} }
/* Load the expression on demand. */ /* Load the expression on demand. */
auto vArg = state.allocValue(); auto vArg = state.allocValue();
vArg->mkString(path2); vArg->mkPath(path2);
if (seen.size() == maxAttrs) if (seen.size() == maxAttrs)
throw Error("too many Nix expressions in directory '%1%'", path); throw Error("too many Nix expressions in directory '%1%'", path);
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg); 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); /* `path2' is a directory (with no default.nix in it);
recurse into it. */ recurse into it. */
getAllExprs(state, path2, seen, attrs); getAllExprs(state, path2, seen, attrs);
@ -152,14 +156,12 @@ 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; auto st = path.accessor.lstat(path.path.resolveSymlinks());
if (stat(path.c_str(), &st) == -1)
throw SysError("getting information about '%1%'", path);
if (isNixExpr(path, st)) if (isNixExpr(path, st))
state.evalFile(state.rootPath(path), v); state.evalFile(path, v);
/* The path is a directory. Put the Nix expressions in the /* The path is a directory. Put the Nix expressions in the
directory in a set, with the file name of each expression as directory in a set, with the file name of each expression as
@ -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 set flat, not nested, to make it easier for a user to have a
~/.nix-defexpr directory that includes some system-wide ~/.nix-defexpr directory that includes some system-wide
directory). */ directory). */
else if (S_ISDIR(st.st_mode)) { else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.buildBindings(maxAttrs); auto attrs = state.buildBindings(maxAttrs);
attrs.alloc("_combineChannels").mkList(0); attrs.alloc("_combineChannels").mkList(0);
StringSet seen; 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, std::string systemFilter, Bindings & autoArgs,
const std::string & pathPrefix, DrvInfos & elems) const std::string & pathPrefix, DrvInfos & elems)
{ {
@ -390,7 +392,7 @@ static void queryInstSources(EvalState & state,
/* Load the derivations from the (default or specified) /* Load the derivations from the (default or specified)
Nix expression. */ Nix expression. */
DrvInfos allElems; DrvInfos allElems;
loadDerivations(state, instSource.nixExprPath, loadDerivations(state, *instSource.nixExprPath,
instSource.systemFilter, *instSource.autoArgs, "", allElems); instSource.systemFilter, *instSource.autoArgs, "", allElems);
elems = filterBySelector(state, allElems, args, newestOnly); elems = filterBySelector(state, allElems, args, newestOnly);
@ -407,7 +409,7 @@ static void queryInstSources(EvalState & state,
case srcNixExprs: { case srcNixExprs: {
Value vArg; Value vArg;
loadSourceExpr(state, instSource.nixExprPath, vArg); loadSourceExpr(state, *instSource.nixExprPath, vArg);
for (auto & i : args) { for (auto & i : args) {
Expr * eFun = state.parseExprFromString(i, state.rootPath(absPath("."))); Expr * eFun = state.parseExprFromString(i, state.rootPath(absPath(".")));
@ -462,7 +464,7 @@ static void queryInstSources(EvalState & state,
case srcAttrPath: { case srcAttrPath: {
Value vRoot; Value vRoot;
loadSourceExpr(state, instSource.nixExprPath, vRoot); loadSourceExpr(state, *instSource.nixExprPath, vRoot);
for (auto & i : args) { for (auto & i : args) {
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first); Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
getDerivations(state, v, "", *instSource.autoArgs, elems, true); getDerivations(state, v, "", *instSource.autoArgs, elems, true);
@ -1015,7 +1017,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
installedElems = queryInstalled(*globals.state, globals.profile); installedElems = queryInstalled(*globals.state, globals.profile);
if (source == sAvailable || compareVersions) if (source == sAvailable || compareVersions)
loadDerivations(*globals.state, globals.instSource.nixExprPath, loadDerivations(*globals.state, *globals.instSource.nixExprPath,
globals.instSource.systemFilter, *globals.instSource.autoArgs, globals.instSource.systemFilter, *globals.instSource.autoArgs,
attrPath, availElems); attrPath, availElems);
@ -1374,23 +1376,24 @@ static int main_nix_env(int argc, char * * argv)
Operation op = 0; Operation op = 0;
RepairFlag repair = NoRepair; RepairFlag repair = NoRepair;
std::string file; std::string file;
Path nixExprPath;
Globals globals; Globals globals;
globals.instSource.type = srcUnknown; globals.instSource.type = srcUnknown;
globals.instSource.nixExprPath = getHome() + "/.nix-defexpr"; nixExprPath = getHome() + "/.nix-defexpr";
globals.instSource.systemFilter = "*"; globals.instSource.systemFilter = "*";
if (!pathExists(globals.instSource.nixExprPath)) { if (!pathExists(nixExprPath)) {
try { try {
createDirs(globals.instSource.nixExprPath); createDirs(nixExprPath);
replaceSymlink( replaceSymlink(
fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName()), fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName()),
globals.instSource.nixExprPath + "/channels"); nixExprPath + "/channels");
if (getuid() != 0) if (getuid() != 0)
replaceSymlink( replaceSymlink(
fmt("%s/profiles/per-user/root/channels", settings.nixStateDir), fmt("%s/profiles/per-user/root/channels", settings.nixStateDir),
globals.instSource.nixExprPath + "/channels_root"); nixExprPath + "/channels_root");
} catch (Error &) { } } catch (Error &) { }
} }
@ -1474,10 +1477,10 @@ static int main_nix_env(int argc, char * * argv)
globals.state = std::shared_ptr<EvalState>(new EvalState(myArgs.searchPath, store)); globals.state = std::shared_ptr<EvalState>(new EvalState(myArgs.searchPath, store));
globals.state->repair = repair; globals.state->repair = repair;
if (file != "") globals.instSource.nixExprPath = std::make_shared<SourcePath>(
// FIXME: check that the accessor returned by file != ""
// lookupFileArg() is the root FS. ? lookupFileArg(*globals.state, file)
globals.instSource.nixExprPath = lookupFileArg(*globals.state, file).path.abs(); : globals.state->rootPath(nixExprPath));
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state); globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);