about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-01-05T16·26+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-01-05T16·26+0000
commit4a373a3e9ac07a2d4c43d495c0a44883106ecfde (patch)
tree27f4e22f8d3573bfe1ebba1acfa2e46a735fecee
parentf83c5e3e5f3e6b33c095d6559a4b3cd5922e88ce (diff)
* 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.

-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 aecfa43487..b9e79e13d5 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 2bea44131e..2daf4d4f4d 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 f605e8b619..90a039164b 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 60b86b162c..28e276a329 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 4126381d9e..5d27ac1bdd 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 3f15e6a8e2..823f5213ac 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 64ae6d4120..f0877b0586 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] == '-')