aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/parser.cc18
-rw-r--r--src/libstore/references.cc8
-rw-r--r--src/libutil/archive.cc5
-rw-r--r--src/libutil/util.cc14
-rw-r--r--src/libutil/util.hh4
-rw-r--r--src/nix-env/help.txt10
-rw-r--r--src/nix-env/main.cc69
7 files changed, 86 insertions, 42 deletions
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc
index aecfa4348..b9e79e13d 100644
--- a/src/libexpr/parser.cc
+++ b/src/libexpr/parser.cc
@@ -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))
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 2bea44131..2daf4d4f4 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -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);
}
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index f605e8b61..90a039164 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -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);
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 60b86b162..28e276a32 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -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;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 4126381d9..5d27ac1bd 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -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);
diff --git a/src/nix-env/help.txt b/src/nix-env/help.txt
index 3f15e6a8e..823f5213a 100644
--- a/src/nix-env/help.txt
+++ b/src/nix-env/help.txt
@@ -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
+ --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
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
index 64ae6d412..f0877b058 100644
--- a/src/nix-env/main.cc
+++ b/src/nix-env/main.cc
@@ -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,17 +620,28 @@ 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();
+ Path linkPathFinal = getHomeDir() + "/.nix-userenv";
- string homeDir(getenv("HOME"));
- if (homeDir == "") throw Error("HOME environment variable not set");
+ switchLink(linkPathFinal, linkPath);
+}
- string linkPathFinal = homeDir + "/.nix-userenv";
+
+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(linkPathFinal, linkPath);
+ switchLink(defNixExprLink, defNixExpr);
}
@@ -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] == '-')