diff options
-rw-r--r-- | src/libexpr/parser.cc | 18 | ||||
-rw-r--r-- | src/libstore/references.cc | 8 | ||||
-rw-r--r-- | src/libutil/archive.cc | 5 | ||||
-rw-r--r-- | src/libutil/util.cc | 14 | ||||
-rw-r--r-- | src/libutil/util.hh | 4 | ||||
-rw-r--r-- | src/nix-env/help.txt | 10 | ||||
-rw-r--r-- | src/nix-env/main.cc | 69 |
7 files changed, 86 insertions, 42 deletions
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index aecfa434878a..b9e79e13d5f1 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 2bea44131ec0..2daf4d4f4d0a 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 f605e8b61954..90a039164b58 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 60b86b162c9c..28e276a329b3 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 4126381d9e96..5d27ac1bddb4 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 3f15e6a8e2de..823f5213acf9 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 64ae6d4120b3..f0877b058624 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] == '-') |