* 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;
string s;
if (atMatch(m, e) >> "Str" >> s) {
if (atMatch(m, e) >> "Str" >> s)
return ATmake("Str(<str>)",
string(s, 1, s.size() - 2).c_str());
}
if (atMatch(m, e) >> "Path" >> s) {
if (s[0] != '/')
s = basePath + "/" + s;
return ATmake("Path(<str>)", canonPath(s).c_str());
}
if (atMatch(m, e) >> "Path" >> s)
return ATmake("Path(<str>)", absPath(s, basePath).c_str());
if (atMatch(m, e) >> "Int" >> s) {
istringstream s2(s);
@ -147,8 +143,14 @@ Expr parseExprFromFile(Path path)
if (e) return e;
#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;
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))
throw SysError(format("getting status of `%1%'") % path);
if (S_ISDIR(st.st_mode))

View file

@ -59,12 +59,8 @@ void checkPath(const string & path,
delete buf; /* !!! autodelete */
}
else if (S_ISLNK(st.st_mode)) {
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);
search(string(buf, st.st_size), ids, seen);
}
else if (S_ISLNK(st.st_mode))
search(readLink(path), ids, seen);
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)) {
writeString("type", 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(string(buf, st.st_size), sink);
writeString(readLink(path), sink);
}
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 names;

View file

@ -73,6 +73,10 @@ string baseNameOf(const Path & path);
/* Return true iff the given path exists. */
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
removed. */
Strings readDirectory(const Path & path);

View file

@ -4,15 +4,16 @@ nix-env [OPTIONS...] [ARGUMENTS...]
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
--upgrade / -u FILE: upgrade derivation in the user environment
--query / -q: perform a query on an environment or Nix expression
The previous operations take a list of derivation names. The special
name `*' may be used to indicate all derivations.
--profile / -p [FILE]: switch to specified user environment
--import / -I FILE: set default Nix expression
--version: output version information
--help: display help
@ -26,10 +27,11 @@ Query types:
Query sources:
--installed: use installed derivations (default)
--available / -f FILE: use derivations available in expression FILE
--available / -a: use derivations available in Nix expression
Options:
--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)
--keep-failed / -K: keep temporary directories of failed builds

View file

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