about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShea Levy <shea@shealevy.com>2017-03-31T15·22-0400
committerShea Levy <shea@shealevy.com>2017-03-31T15·22-0400
commitd299bd710a5c47b54a6f166c7e26608c10f41456 (patch)
treea795c3dcacb6db330e56f57ab9d9ddc068437353
parentb9b8b8a63ba49dc027b08950bd3cf30cc8f09ec5 (diff)
parent0bb8db257d98a32abde759f4d07d28b5178bd3bf (diff)
Merge branch 'builtins.exec'
-rw-r--r--src/libexpr/primops.cc56
-rw-r--r--src/libstore/globals.cc4
-rw-r--r--src/libstore/globals.hh4
3 files changed, 59 insertions, 5 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 93097f3d1bf3..a98da737e4a4 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -178,6 +178,58 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args
 }
 
 
+/* Execute a program and parse its output */
+static void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+    state.forceAttrs(*args[0], pos);
+    auto sProgram = state.symbols.create("program");
+    auto sArguments = state.symbols.create("arguments");
+    PathSet context;
+    string program;
+    bool programSet = false;
+    Strings commandArgs;
+    for (auto & attr : *args[0]->attrs) {
+        if (attr.name == sProgram) {
+            program = state.coerceToString(*attr.pos, *attr.value, context, false, false);
+            programSet = true;
+        } else if (attr.name == sArguments) {
+            state.forceList(*attr.value, *attr.pos);
+            auto elems = attr.value->listElems();
+            for (unsigned int i = 0; i < attr.value->listSize(); ++i) {
+                commandArgs.emplace_back(state.coerceToString(*attr.pos, *elems[i], context, false, false));
+            }
+        } else {
+            throw EvalError(format("unexpected attribute ‘%1%’ in argument to builtins.exec, at %2%")
+                % attr.name % pos);
+        }
+    }
+    if (!programSet) {
+        throw EvalError(format("attribute ‘programSet’ required, at %1%") % pos);
+    }
+    try {
+        state.realiseContext(context);
+    } catch (InvalidPathError & e) {
+        throw EvalError(format("cannot execute ‘%1%’, since path ‘%2%’ is not valid, at %3%")
+            % program % e.path % pos);
+    }
+
+    auto output = runProgram(program, true, commandArgs);
+    Expr * parsed;
+    try {
+        parsed = state.parseExprFromString(output, pos.file);
+    } catch (Error & e) {
+        e.addPrefix(format("While parsing the output from ‘%1%’, at %2%\n") % program % pos);
+        throw;
+    }
+    try {
+        state.eval(parsed, v);
+    } catch (Error & e) {
+        e.addPrefix(format("While evaluating the output from ‘%1%’, at %2%\n") % program % pos);
+        throw;
+    }
+}
+
+
 /* Return a string representing the type of the expression. */
 static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
@@ -1903,8 +1955,10 @@ void EvalState::createBaseEnv()
     mkApp(v, *baseEnv.values[baseEnvDispl - 1], *v2);
     forceValue(v);
     addConstant("import", v);
-    if (settings.enableImportNative)
+    if (settings.enableNativeCode) {
         addPrimOp("__importNative", 2, prim_importNative);
+        addPrimOp("__exec", 1, prim_exec);
+    }
     addPrimOp("__typeOf", 1, prim_typeOf);
     addPrimOp("isNull", 1, prim_isNull);
     addPrimOp("__isFunction", 1, prim_isFunction);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 012b3d5b8b98..8c900be77b8f 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -67,7 +67,7 @@ Settings::Settings()
     envKeepDerivations = false;
     lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
     showTrace = false;
-    enableImportNative = false;
+    enableNativeCode = false;
     netrcFile = fmt("%s/%s", nixConfDir, "netrc");
     caFile = getEnv("NIX_SSL_CERT_FILE", getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt"));
     enableImportFromDerivation = true;
@@ -179,7 +179,7 @@ void Settings::update()
     _get(envKeepDerivations, "env-keep-derivations");
     _get(sshSubstituterHosts, "ssh-substituter-hosts");
     _get(useSshSubstituter, "use-ssh-substituter");
-    _get(enableImportNative, "allow-unsafe-native-code-during-evaluation");
+    _get(enableNativeCode, "allow-unsafe-native-code-during-evaluation");
     _get(useCaseHack, "use-case-hack");
     _get(preBuildHook, "pre-build-hook");
     _get(keepGoing, "keep-going");
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 462721681912..ccec300f776e 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -181,8 +181,8 @@ struct Settings {
     /* Whether to show a stack trace if Nix evaluation fails. */
     bool showTrace;
 
-    /* Whether the importNative primop should be enabled */
-    bool enableImportNative;
+    /* Whether native-code enabling primops should be enabled */
+    bool enableNativeCode;
 
     /* The hook to run just before a build to set derivation-specific
        build settings */