about summary refs log tree commit diff
path: root/src/nix-build/nix-build.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-build/nix-build.cc')
-rwxr-xr-xsrc/nix-build/nix-build.cc194
1 files changed, 111 insertions, 83 deletions
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 50fcf16abdf0..08c6793577a4 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -1,30 +1,32 @@
 #include <cstring>
+#include <fstream>
+#include <iostream>
 #include <regex>
-#include "util.hh"
-#include <unistd.h>
-#include "shared.hh"
 #include <sstream>
 #include <vector>
-#include <iostream>
-#include <fstream>
+
+#include <unistd.h>
+
 #include "store-api.hh"
 #include "globals.hh"
 #include "derivations.hh"
+#include "affinity.hh"
+#include "util.hh"
+#include "shared.hh"
 
 using namespace nix;
-using std::stringstream;
 
-extern char ** environ;
+extern char * * environ;
 
 /* Recreate the effect of the perl shellwords function, breaking up a
  * string into arguments like a shell word, including escapes
  */
 std::vector<string> shellwords(const string & s)
 {
-    auto whitespace = std::regex("^(\\s+).*");
+    std::regex whitespace("^(\\s+).*");
     auto begin = s.cbegin();
-    auto res = std::vector<string>{};
-    auto cur = stringstream{};
+    std::vector<string> res;
+    std::string cur;
     enum state {
         sBegin,
         sQuote
@@ -33,36 +35,41 @@ std::vector<string> shellwords(const string & s)
     auto it = begin;
     for (; it != s.cend(); ++it) {
         if (st == sBegin) {
-            auto match = std::smatch{};
+            std::smatch match;
             if (regex_search(it, s.cend(), match, whitespace)) {
-                cur << string(begin, it);
-                res.push_back(cur.str());
-                cur = stringstream{};
+                cur.append(begin, it);
+                res.push_back(cur);
+                cur.clear();
                 it = match[1].second;
                 begin = it;
             }
         }
         switch (*it) {
             case '"':
-                cur << string(begin, it);
+                cur.append(begin, it);
                 begin = it + 1;
                 st = st == sBegin ? sQuote : sBegin;
                 break;
             case '\\':
                 /* perl shellwords mostly just treats the next char as part of the string with no special processing */
-                cur << string(begin, it);
+                cur.append(begin, it);
                 begin = ++it;
                 break;
         }
     }
-    cur << string(begin, it);
-    auto last = cur.str();
-    if (!last.empty()) {
-        res.push_back(std::move(last));
-    }
+    cur.append(begin, it);
+    if (!cur.empty()) res.push_back(cur);
     return res;
 }
 
+static void maybePrintExecError(ExecError & e)
+{
+    if (WIFEXITED(e.status))
+        throw Exit(WEXITSTATUS(e.status));
+    else
+        throw e;
+}
+
 int main(int argc, char ** argv)
 {
     return handleExceptions(argv[0], [&]() {
@@ -76,26 +83,26 @@ int main(int argc, char ** argv)
         auto packages = false;
         auto interactive = true;
 
-        auto instArgs = Strings{};
-        auto buildArgs = Strings{};
-        auto exprs = Strings{};
+        Strings instArgs;
+        Strings buildArgs;
+        Strings exprs;
 
         auto shell = getEnv("SHELL", "/bin/sh");
-        auto envCommand = string{}; // interactive shell
-        auto envExclude = Strings{};
+        std::string envCommand; // interactive shell
+        Strings envExclude;
 
         auto myName = runEnv ? "nix-shell" : "nix-build";
 
         auto inShebang = false;
-        auto script = string{};
-        auto savedArgs = std::vector<string>{};
+        std::string script;
+        std::vector<string> savedArgs;
 
-        auto tmpDir = AutoDelete{createTempDir("", myName)};
+        AutoDelete tmpDir(createTempDir("", myName));
 
-        auto outLink = string("./result");
+        std::string outLink = "./result";
         auto drvLink = (Path) tmpDir + "/derivation";
 
-        auto args = std::vector<string>{};
+        std::vector<string> args;
         for (int i = 1; i < argc; ++i)
             args.push_back(argv[i]);
         // Heuristic to see if we're invoked as a shebang script, namely, if we
@@ -110,7 +117,7 @@ int main(int argc, char ** argv)
                     inShebang = true;
                     for (int i = 2; i < argc - 1; ++i)
                         savedArgs.push_back(argv[i]);
-                    args = std::vector<string>{};
+                    std::vector<string> args;
                     for (auto line : lines) {
                         line = chomp(line);
                         std::smatch match;
@@ -284,7 +291,7 @@ int main(int argc, char ** argv)
                         execArgs = "-a PERL";
                 }
 
-                auto joined = stringstream{};
+                std::ostringstream joined;
                 for (const auto & i : savedArgs)
                     joined << shellEscape(i) << ' ';
 
@@ -320,7 +327,7 @@ int main(int argc, char ** argv)
 
         if (packages) {
             instArgs.push_back("--expr");
-            auto joined = stringstream{};
+            std::ostringstream joined;
             joined << "with import <nixpkgs> { }; runCommand \"shell\" { buildInputs = [ ";
             for (const auto & i : exprs)
                 joined << '(' << i << ") ";
@@ -338,19 +345,23 @@ int main(int argc, char ** argv)
 
         for (auto & expr : exprs) {
             // Instantiate.
-            auto drvPaths = std::vector<string>{};
+            std::vector<string> drvPaths;
             if (!std::regex_match(expr, std::regex("^/.*\\.drv$"))) {
                 // If we're in a #! script, interpret filenames relative to the
                 // script.
                 if (inShebang && !packages)
                     expr = absPath(expr, dirOf(script));
 
-                auto instantiateArgs = Strings{"--add-root", drvLink, "--indirect"};
+                Strings instantiateArgs{"--add-root", drvLink, "--indirect"};
                 for (const auto & arg : instArgs)
                     instantiateArgs.push_back(arg);
                 instantiateArgs.push_back(expr);
-                auto instOutput = runProgram(settings.nixBinDir + "/nix-instantiate", false, instantiateArgs);
-                drvPaths = tokenizeString<std::vector<string>>(instOutput);
+                try {
+                    auto instOutput = runProgram(settings.nixBinDir + "/nix-instantiate", false, instantiateArgs);
+                    drvPaths = tokenizeString<std::vector<string>>(instOutput);
+                } catch (ExecError & e) {
+                    maybePrintExecError(e);
+                }
             } else {
                 drvPaths.push_back(expr);
             }
@@ -365,7 +376,7 @@ int main(int argc, char ** argv)
                 auto drv = store->derivationFromPath(drvPath);
 
                 // Build or fetch all dependencies of the derivation.
-                auto nixStoreArgs = Strings{"-r", "--no-output", "--no-gc-warning"};
+                Strings nixStoreArgs{"-r", "--no-output", "--no-gc-warning"};
                 for (const auto & arg : buildArgs)
                     nixStoreArgs.push_back(arg);
                 for (const auto & input : drv.inputDrvs)
@@ -373,35 +384,36 @@ int main(int argc, char ** argv)
                         nixStoreArgs.push_back(input.first);
                 for (const auto & src : drv.inputSrcs)
                     nixStoreArgs.push_back(src);
-                runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
+
+                try {
+                    runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
+                } catch (ExecError & e) {
+                    maybePrintExecError(e);
+                }
 
                 // Set the environment.
+                auto env = getEnv();
+
                 auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp"));
+
                 if (pure) {
-                    auto skippedEnv = std::vector<string>{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
-                    auto removed = std::vector<string>{};
-                    for (auto i = size_t{0}; environ[i]; ++i) {
-                        auto eq = strchr(environ[i], '=');
-                        if (!eq)
-                            // invalid env, just keep going
-                            continue;
-                        auto name = string(environ[i], eq);
-                        if (find(skippedEnv.begin(), skippedEnv.end(), name) == skippedEnv.end())
-                            removed.emplace_back(std::move(name));
-                    }
-                    for (const auto & name : removed)
-                        unsetenv(name.c_str());
+                    std::set<string> keepVars{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
+                    decltype(env) newEnv;
+                    for (auto & i : env)
+                        if (keepVars.count(i.first))
+                            newEnv.emplace(i);
+                    env = newEnv;
                     // NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
-                    setenv("__ETC_PROFILE_SOURCED", "1", 1);
+                    env["__ETC_PROFILE_SOURCED"] = "1";
                 }
-                setenv("NIX_BUILD_TOP", tmp.c_str(), 1);
-                setenv("TMPDIR", tmp.c_str(), 1);
-                setenv("TEMPDIR", tmp.c_str(), 1);
-                setenv("TMP", tmp.c_str(), 1);
-                setenv("TEMP", tmp.c_str(), 1);
-                setenv("NIX_STORE", store->storeDir.c_str(), 1);
-                for (const auto & env : drv.env)
-                    setenv(env.first.c_str(), env.second.c_str(), 1);
+
+                env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
+                env["NIX_STORE"] = store->storeDir;
+
+                for (auto & var : drv.env)
+                    env.emplace(var);
+
+                restoreAffinity();
 
                 // Run a shell using the derivation's environment.  For
                 // convenience, source $stdenv/setup to setup additional
@@ -410,7 +422,6 @@ int main(int argc, char ** argv)
                 auto rcfile = (Path) tmpDir + "/rc";
                 writeFile(rcfile, (format(
                         "rm -rf '%1%'; "
-                        "unset BASH_ENV; "
                         "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc; "
                         "%2%"
                         "dontAddDisableDepTrack=1; "
@@ -424,12 +435,26 @@ int main(int argc, char ** argv)
                         "shopt -u nullglob; "
                         "unset TZ; %4%"
                         "%5%"
-                        ) % (Path) tmpDir % (pure ? "" : "p=$PATH") % (pure ? "" : "PATH=$PATH:$p; unset p; ") % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "") % envCommand).str());
-                setenv("BASH_ENV", rcfile.c_str(), 1);
-                if (interactive)
-                    execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", "--rcfile", rcfile.c_str(), NULL);
-                else
-                    execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", rcfile.c_str(), NULL);
+                        )
+                        % (Path) tmpDir
+                        % (pure ? "" : "p=$PATH; ")
+                        % (pure ? "" : "PATH=$PATH:$p; unset p; ")
+                        % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "")
+                        % envCommand).str());
+
+                Strings envStrs;
+                for (auto & i : env)
+                    envStrs.push_back(i.first + "=" + i.second);
+
+                auto args = interactive
+                    ? Strings{"bash", "--rcfile", rcfile}
+                    : Strings{"bash", rcfile};
+
+                environ = stringsToCharPtrs(envStrs).data();
+
+                execvp(getEnv("NIX_BUILD_SHELL", "bash").c_str(),
+                    stringsToCharPtrs(args).data());
+
                 throw SysError("executing shell");
             }
 
@@ -437,11 +462,11 @@ int main(int argc, char ** argv)
             // ./result, ./result-dev, and so on, rather than ./result,
             // ./result-2-dev, and so on.  This combines multiple derivation
             // paths into one "/nix/store/drv-path!out1,out2,..." argument.
-            auto prevDrvPath = string{};
-            auto drvPaths2 = Strings{};
+            std::string prevDrvPath;
+            Strings drvPaths2;
             for (const auto & drvPath : drvPaths) {
                 auto p = drvPath;
-                auto output = string{"out"};
+                std::string output = "out";
                 std::smatch match;
                 if (std::regex_match(drvPath, match, std::regex("(.*)!(.*)"))) {
                     p = match[1].str();
@@ -460,25 +485,28 @@ int main(int argc, char ** argv)
                 }
             }
             // Build.
-            auto outPaths = Strings{};
-            auto nixStoreArgs = Strings{"--add-root", outLink, "--indirect", "-r"};
+            Strings outPaths;
+            Strings nixStoreArgs{"--add-root", outLink, "--indirect", "-r"};
             for (const auto & arg : buildArgs)
                 nixStoreArgs.push_back(arg);
             for (const auto & path : drvPaths2)
                 nixStoreArgs.push_back(path);
-            auto nixStoreRes = runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
-            for (const auto & outpath : tokenizeString<std::vector<string>>(nixStoreRes)) {
-                outPaths.push_back(chomp(outpath));
+
+            std::string nixStoreRes;
+            try {
+                nixStoreRes = runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
+            } catch (ExecError & e) {
+                maybePrintExecError(e);
             }
 
+            for (const auto & outpath : tokenizeString<std::vector<string>>(nixStoreRes))
+                outPaths.push_back(chomp(outpath));
+
             if (dryRun)
                 continue;
-            for (const auto & outPath : outPaths) {
-                auto target = readLink(outPath);
-                std::cout << target << '\n';
-            }
+
+            for (const auto & outPath : outPaths)
+                std::cout << readLink(outPath) << '\n';
         }
-        return;
     });
 }
-