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
{
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.accessor.lstat(path2.path.resolveSymlinks());
} 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->mkPath(path2);
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,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;
if (stat(path.c_str(), &st) == -1)
throw SysError("getting information about '%1%'", path);
auto st = path.accessor.lstat(path.path.resolveSymlinks());
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
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
~/.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,7 +409,7 @@ 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, state.rootPath(absPath(".")));
@ -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);
@ -1015,7 +1017,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);
@ -1374,23 +1376,24 @@ static int main_nix_env(int argc, char * * argv)
Operation op = 0;
RepairFlag repair = NoRepair;
std::string file;
Path nixExprPath;
Globals globals;
globals.instSource.type = srcUnknown;
globals.instSource.nixExprPath = getHome() + "/.nix-defexpr";
nixExprPath = getHome() + "/.nix-defexpr";
globals.instSource.systemFilter = "*";
if (!pathExists(globals.instSource.nixExprPath)) {
if (!pathExists(nixExprPath)) {
try {
createDirs(globals.instSource.nixExprPath);
createDirs(nixExprPath);
replaceSymlink(
fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName()),
globals.instSource.nixExprPath + "/channels");
nixExprPath + "/channels");
if (getuid() != 0)
replaceSymlink(
fmt("%s/profiles/per-user/root/channels", settings.nixStateDir),
globals.instSource.nixExprPath + "/channels_root");
nixExprPath + "/channels_root");
} 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->repair = repair;
if (file != "")
// FIXME: check that the accessor returned by
// lookupFileArg() is the root FS.
globals.instSource.nixExprPath = lookupFileArg(*globals.state, file).path.abs();
globals.instSource.nixExprPath = std::make_shared<SourcePath>(
file != ""
? lookupFileArg(*globals.state, file)
: globals.state->rootPath(nixExprPath));
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);