* Implemented Eelco V.'s `nix-env -I' command to specify the default

path of the Nix expression to be used with the import, upgrade, and
  query commands.  For instance,

  $ nix-env -I ~/nixpkgs/pkgs/system/i686-linux.nix

  $ nix-env --query --available   [aka -qa]
  sylpheed-0.9.7
  bison-1.875
  pango-1.2.5
  subversion-0.35.1
  ...

  $ nix-env -i sylpheed

  $ nix-env -u subversion

  There can be only one default at a time.

* If the path to a Nix expression is a symlink, follow the symlink
  prior to resolving relative path references in the expression.
This commit is contained in:
Eelco Dolstra 2004-01-05 16:26:43 +00:00
parent f83c5e3e5f
commit 4a373a3e9a
7 changed files with 87 additions and 43 deletions

View file

@ -29,16 +29,12 @@ struct Cleanup : TermFun
ATMatcher m; ATMatcher m;
string s; string s;
if (atMatch(m, e) >> "Str" >> s) { if (atMatch(m, e) >> "Str" >> s)
return ATmake("Str(<str>)", return ATmake("Str(<str>)",
string(s, 1, s.size() - 2).c_str()); string(s, 1, s.size() - 2).c_str());
}
if (atMatch(m, e) >> "Path" >> s) { if (atMatch(m, e) >> "Path" >> s)
if (s[0] != '/') return ATmake("Path(<str>)", absPath(s, basePath).c_str());
s = basePath + "/" + s;
return ATmake("Path(<str>)", canonPath(s).c_str());
}
if (atMatch(m, e) >> "Int" >> s) { if (atMatch(m, e) >> "Int" >> s) {
istringstream s2(s); istringstream s2(s);
@ -147,8 +143,14 @@ Expr parseExprFromFile(Path path)
if (e) return e; if (e) return e;
#endif #endif
/* If `path' refers to a directory, append `/default.nix'. */ /* If `path' is a symlink, follow it. This is so that relative
path references work. */
struct stat st; struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path);
if (S_ISLNK(st.st_mode)) path = absPath(readLink(path), dirOf(path));
/* If `path' refers to a directory, append `/default.nix'. */
if (stat(path.c_str(), &st)) if (stat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path); throw SysError(format("getting status of `%1%'") % path);
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))

View file

@ -59,12 +59,8 @@ void checkPath(const string & path,
delete buf; /* !!! autodelete */ delete buf; /* !!! autodelete */
} }
else if (S_ISLNK(st.st_mode)) { else if (S_ISLNK(st.st_mode))
char buf[st.st_size]; search(readLink(path), ids, seen);
if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
throw SysError(format("reading symbolic link `%1%'") % path);
search(string(buf, st.st_size), ids, seen);
}
else throw Error(format("unknown file type: %1%") % path); else throw Error(format("unknown file type: %1%") % path);
} }

View file

@ -122,11 +122,8 @@ static void dump(const Path & path, DumpSink & sink)
else if (S_ISLNK(st.st_mode)) { else if (S_ISLNK(st.st_mode)) {
writeString("type", sink); writeString("type", sink);
writeString("symlink", sink); writeString("symlink", sink);
char buf[st.st_size];
if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
throw SysError("reading symbolic link " + path);
writeString("target", sink); writeString("target", sink);
writeString(string(buf, st.st_size), sink); writeString(readLink(path), sink);
} }
else throw Error("unknown file type: " + path); else throw Error("unknown file type: " + path);

View file

@ -109,6 +109,20 @@ bool pathExists(const Path & path)
} }
Path readLink(const Path & path)
{
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path);
if (!S_ISLNK(st.st_mode))
throw Error(format("`%1%' is not a symlink") % path);
char buf[st.st_size];
if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
throw SysError(format("reading symbolic link `%1%'") % path);
return string(buf, st.st_size);
}
Strings readDirectory(const Path & path) Strings readDirectory(const Path & path)
{ {
Strings names; Strings names;

View file

@ -73,6 +73,10 @@ string baseNameOf(const Path & path);
/* Return true iff the given path exists. */ /* Return true iff the given path exists. */
bool pathExists(const Path & path); bool pathExists(const Path & path);
/* Read the contents (target) of a symbolic link. The result is not
in any way canonicalised. */
Path readLink(const Path & path);
/* Read the contents of a directory. The entries `.' and `..' are /* Read the contents of a directory. The entries `.' and `..' are
removed. */ removed. */
Strings readDirectory(const Path & path); Strings readDirectory(const Path & path);

View file

@ -4,15 +4,16 @@ nix-env [OPTIONS...] [ARGUMENTS...]
Operations: Operations:
--install / -i FILE: add derivations to the user environment --install / -i: add derivations to the user environment
--upgrade / -u: upgrade derivation in the user environment
--uninstall / -e: remove derivations from the user environment --uninstall / -e: remove derivations from the user environment
--upgrade / -u FILE: upgrade derivation in the user environment
--query / -q: perform a query on an environment or Nix expression --query / -q: perform a query on an environment or Nix expression
The previous operations take a list of derivation names. The special The previous operations take a list of derivation names. The special
name `*' may be used to indicate all derivations. name `*' may be used to indicate all derivations.
--profile / -p [FILE]: switch to specified user environment --profile / -p [FILE]: switch to specified user environment
--import / -I FILE: set default Nix expression
--version: output version information --version: output version information
--help: display help --help: display help
@ -26,10 +27,11 @@ Query types:
Query sources: Query sources:
--installed: use installed derivations (default) --installed: use installed derivations (default)
--available / -f FILE: use derivations available in expression FILE --available / -a: use derivations available in Nix expression
Options: Options:
--link / -l LINK: use symlink LINK instead of (...)/current --link / -l LINK: use symlink LINK instead of (...)/current
--file / -f FILE: use Nix expression FILE for installation, etc.
--verbose / -v: verbose operation (may be repeated) --verbose / -v: verbose operation (may be repeated)
--keep-failed / -K: keep temporary directories of failed builds --keep-failed / -K: keep temporary directories of failed builds

View file

@ -11,6 +11,7 @@
struct Globals struct Globals
{ {
Path linkPath; Path linkPath;
Path nixExprPath;
EvalState state; EvalState state;
}; };
@ -106,12 +107,26 @@ void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs)
} }
static Path getHomeDir()
{
Path homeDir(getenv("HOME"));
if (homeDir == "") throw Error("HOME environment variable not set");
return homeDir;
}
static Path getLinksDir() static Path getLinksDir()
{ {
return canonPath(nixStateDir + "/links"); return canonPath(nixStateDir + "/links");
} }
static Path getDefNixExprPath()
{
return getHomeDir() + "/.nix-defexpr";
}
void queryInstalled(EvalState & state, DrvInfos & drvs, void queryInstalled(EvalState & state, DrvInfos & drvs,
const Path & userEnv) const Path & userEnv)
{ {
@ -410,13 +425,11 @@ static void opInstall(Globals & globals,
{ {
if (opFlags.size() > 0) if (opFlags.size() > 0)
throw UsageError(format("unknown flags `%1%'") % opFlags.front()); throw UsageError(format("unknown flags `%1%'") % opFlags.front());
if (opArgs.size() < 1) throw UsageError("Nix file expected");
Path nePath = opArgs.front(); DrvNames drvNames = drvNamesFromArgs(opArgs);
DrvNames drvNames = drvNamesFromArgs(
Strings(++opArgs.begin(), opArgs.end()));
installDerivations(globals.state, nePath, drvNames, globals.linkPath); installDerivations(globals.state, globals.nixExprPath,
drvNames, globals.linkPath);
} }
@ -492,11 +505,10 @@ static void opUpgrade(Globals & globals,
throw UsageError(format("unknown flags `%1%'") % opFlags.front()); throw UsageError(format("unknown flags `%1%'") % opFlags.front());
if (opArgs.size() < 1) throw UsageError("Nix file expected"); if (opArgs.size() < 1) throw UsageError("Nix file expected");
Path nePath = opArgs.front(); DrvNames drvNames = drvNamesFromArgs(opArgs);
DrvNames drvNames = drvNamesFromArgs(
Strings(++opArgs.begin(), opArgs.end()));
upgradeDerivations(globals.state, nePath, drvNames, globals.linkPath); upgradeDerivations(globals.state, globals.nixExprPath,
drvNames, globals.linkPath);
} }
@ -547,7 +559,7 @@ static void opQuery(Globals & globals,
else if (*i == "--expr" || *i == "-e") query = qDrvPath; else if (*i == "--expr" || *i == "-e") query = qDrvPath;
else if (*i == "--status" || *i == "-s") query = qStatus; else if (*i == "--status" || *i == "-s") query = qStatus;
else if (*i == "--installed") source = sInstalled; else if (*i == "--installed") source = sInstalled;
else if (*i == "--available" || *i == "-f") source = sAvailable; else if (*i == "--available" || *i == "-a") source = sAvailable;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
/* Obtain derivation information from the specified source. */ /* Obtain derivation information from the specified source. */
@ -560,10 +572,7 @@ static void opQuery(Globals & globals,
break; break;
case sAvailable: { case sAvailable: {
if (opArgs.size() < 1) throw UsageError("Nix file expected"); loadDerivations(globals.state, globals.nixExprPath, drvs);
Path nePath = opArgs.front();
opArgs.pop_front();
loadDerivations(globals.state, nePath, drvs);
break; break;
} }
@ -611,20 +620,31 @@ static void opSwitchProfile(Globals & globals,
if (opFlags.size() > 0) if (opFlags.size() > 0)
throw UsageError(format("unknown flags `%1%'") % opFlags.front()); throw UsageError(format("unknown flags `%1%'") % opFlags.front());
if (opArgs.size() > 1) if (opArgs.size() > 1)
throw UsageError(format("--profile takes at most one argument")); throw UsageError(format("`--profile' takes at most one argument"));
string linkPath = Path linkPath =
opArgs.size() == 0 ? globals.linkPath : opArgs.front(); opArgs.size() == 0 ? globals.linkPath : opArgs.front();
Path linkPathFinal = getHomeDir() + "/.nix-userenv";
string homeDir(getenv("HOME"));
if (homeDir == "") throw Error("HOME environment variable not set");
string linkPathFinal = homeDir + "/.nix-userenv";
switchLink(linkPathFinal, linkPath); switchLink(linkPathFinal, linkPath);
} }
static void opDefaultExpr(Globals & globals,
Strings opFlags, Strings opArgs)
{
if (opFlags.size() > 0)
throw UsageError(format("unknown flags `%1%'") % opFlags.front());
if (opArgs.size() != 1)
throw UsageError(format("`--import' takes exactly one argument"));
Path defNixExpr = opArgs.front();
Path defNixExprLink = getDefNixExprPath();
switchLink(defNixExprLink, defNixExpr);
}
void run(Strings args) void run(Strings args)
{ {
/* Use a higher default verbosity (lvlInfo). */ /* Use a higher default verbosity (lvlInfo). */
@ -635,6 +655,7 @@ void run(Strings args)
Globals globals; Globals globals;
globals.linkPath = getLinksDir() + "/current"; globals.linkPath = getLinksDir() + "/current";
globals.nixExprPath = getDefNixExprPath();
for (Strings::iterator i = args.begin(); i != args.end(); ++i) { for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
string arg = *i; string arg = *i;
@ -649,12 +670,20 @@ void run(Strings args)
op = opUpgrade; op = opUpgrade;
else if (arg == "--query" || arg == "-q") else if (arg == "--query" || arg == "-q")
op = opQuery; op = opQuery;
else if (arg == "--import" || arg == "-I") /* !!! bad name */
op = opDefaultExpr;
else if (arg == "--link" || arg == "-l") { else if (arg == "--link" || arg == "-l") {
++i; ++i;
if (i == args.end()) throw UsageError( if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg); format("`%1%' requires an argument") % arg);
globals.linkPath = absPath(*i); globals.linkPath = absPath(*i);
} }
else if (arg == "--file" || arg == "-f") {
++i;
if (i == args.end()) throw UsageError(
format("`%1%' requires an argument") % arg);
globals.nixExprPath = absPath(*i);
}
else if (arg == "--profile" || arg == "-p") else if (arg == "--profile" || arg == "-p")
op = opSwitchProfile; op = opSwitchProfile;
else if (arg[0] == '-') else if (arg[0] == '-')