about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-09-06T14·03+0200
committerEelco Dolstra <edolstra@gmail.com>2017-09-06T14·03+0200
commitdf4342bc175a153986ebcf5bce2a758d5353adeb (patch)
treed491cac5bd1c4d45c689fd1a19c98958c32e9674
parent1277aab219c83beae856024eea6e868677f7523b (diff)
nix build: Create result symlinks
-rw-r--r--src/nix/build.cc15
-rw-r--r--src/nix/command.hh19
-rw-r--r--src/nix/installables.cc87
-rw-r--r--src/nix/log.cc26
4 files changed, 105 insertions, 42 deletions
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 4239dd3fff9d..64bcafd2d934 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -23,9 +23,20 @@ struct CmdBuild : MixDryRun, InstallablesCommand
 
     void run(ref<Store> store) override
     {
-        auto paths = toStorePaths(store, dryRun ? DryRun : Build);
+        auto buildables = toBuildables(store, dryRun ? DryRun : Build);
 
-        printError("build result: %s", showPaths(paths));
+        for (size_t i = 0; i < buildables.size(); ++i) {
+            auto & b(buildables[i]);
+
+            for (auto & output : b.outputs) {
+                if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) {
+                    std::string symlink = "result";
+                    if (i) symlink += fmt("-%d", i);
+                    if (output.first != "out") symlink += fmt("-%s", output.first);
+                    store2->addPermRoot(output.second, absPath(symlink), true);
+                }
+            }
+        }
     }
 };
 
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 479e6fd3742f..b052c42b1de7 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -44,18 +44,25 @@ private:
     std::shared_ptr<Store> _store;
 };
 
-struct Whence { std::string outputName; Path drvPath; };
-typedef std::map<Path, Whence> Buildables;
+struct Buildable
+{
+    Path drvPath; // may be empty
+    std::map<std::string, Path> outputs;
+};
+
+typedef std::vector<Buildable> Buildables;
 
 struct Installable
 {
     virtual std::string what() = 0;
 
-    virtual Buildables toBuildable(bool singular = false)
+    virtual Buildables toBuildables()
     {
         throw Error("argument '%s' cannot be built", what());
     }
 
+    Buildable toBuildable();
+
     virtual Value * toValue(EvalState & state)
     {
         throw Error("argument '%s' cannot be evaluated", what());
@@ -97,9 +104,11 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
         expectArgs("installables", &_installables);
     }
 
-    enum ToStorePathsMode { Build, NoBuild, DryRun };
+    enum RealiseMode { Build, NoBuild, DryRun };
+
+    Buildables toBuildables(ref<Store> store, RealiseMode mode);
 
-    PathSet toStorePaths(ref<Store> store, ToStorePathsMode mode);
+    PathSet toStorePaths(ref<Store> store, RealiseMode mode);
 
     void prepare() override;
 
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index fdb6004fb31d..f3c7d3075fe8 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -70,17 +70,27 @@ ref<EvalState> SourceExprCommand::getEvalState()
     return ref<EvalState>(evalState);
 }
 
+Buildable Installable::toBuildable()
+{
+    auto buildables = toBuildables();
+    if (buildables.size() != 1)
+        throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
+    return std::move(buildables[0]);
+}
+
 struct InstallableStoreDrv : Installable
 {
-    Path storePath;
+    Path drvPath;
 
-    InstallableStoreDrv(const Path & storePath) : storePath(storePath) { }
+    InstallableStoreDrv(const Path & drvPath) : drvPath(drvPath) { }
 
-    std::string what() override { return storePath; }
+    std::string what() override { return drvPath; }
 
-    Buildables toBuildable(bool singular) override
+    Buildables toBuildables() override
     {
-        return {{storePath, {}}};
+        Buildable b = {drvPath};
+        // FIXME: add outputs?
+        return {b};
     }
 };
 
@@ -92,9 +102,9 @@ struct InstallableStorePath : Installable
 
     std::string what() override { return storePath; }
 
-    Buildables toBuildable(bool singular) override
+    Buildables toBuildables() override
     {
-        return {{storePath, {}}};
+        return {{"", {{"out", storePath}}}};
     }
 };
 
@@ -104,7 +114,7 @@ struct InstallableValue : Installable
 
     InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }
 
-    Buildables toBuildable(bool singular) override
+    Buildables toBuildables() override
     {
         auto state = cmd.getEvalState();
 
@@ -117,16 +127,32 @@ struct InstallableValue : Installable
         DrvInfos drvs;
         getDerivations(*state, *v, "", autoArgs, drvs, false);
 
-        if (singular && drvs.size() != 1)
-            throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), drvs.size());
-
         Buildables res;
 
-        for (auto & drv : drvs)
-            for (auto & output : drv.queryOutputs())
-                res.emplace(output.second, Whence{output.first, drv.queryDrvPath()});
+        PathSet drvPaths;
+
+        for (auto & drv : drvs) {
+            Buildable b{drv.queryDrvPath()};
+            drvPaths.insert(b.drvPath);
+
+            auto outputName = drv.queryOutputName();
+            if (outputName == "")
+                throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);
+
+            b.outputs.emplace(outputName, drv.queryOutPath());
 
-        return res;
+            res.push_back(std::move(b));
+        }
+
+        // Hack to recognize .all: if all drvs have the same drvPath,
+        // merge the buildables.
+        if (drvPaths.size() == 1) {
+            Buildable b{*drvPaths.begin()};
+            for (auto & b2 : res)
+                b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
+            return {b};
+        } else
+            return res;
     }
 };
 
@@ -214,23 +240,38 @@ static std::vector<std::shared_ptr<Installable>> parseInstallables(
     return result;
 }
 
-PathSet InstallablesCommand::toStorePaths(ref<Store> store, ToStorePathsMode mode)
+Buildables InstallablesCommand::toBuildables(ref<Store> store, RealiseMode mode)
 {
     if (mode != Build)
         settings.readOnlyMode = true;
 
-    PathSet outPaths, buildables;
+    Buildables buildables;
+
+    PathSet pathsToBuild;
 
-    for (auto & i : installables)
-        for (auto & b : i->toBuildable()) {
-            outPaths.insert(b.first);
-            buildables.insert(b.second.drvPath != "" ? b.second.drvPath : b.first);
+    for (auto & i : installables) {
+        for (auto & b : i->toBuildables()) {
+            if (b.drvPath != "")
+                pathsToBuild.insert(b.drvPath);
+            buildables.push_back(std::move(b));
         }
+    }
 
     if (mode == DryRun)
-        printMissing(store, buildables, lvlError);
+        printMissing(store, pathsToBuild, lvlError);
     else if (mode == Build)
-        store->buildPaths(buildables);
+        store->buildPaths(pathsToBuild);
+
+    return buildables;
+}
+
+PathSet InstallablesCommand::toStorePaths(ref<Store> store, RealiseMode mode)
+{
+    PathSet outPaths;
+
+    for (auto & b : toBuildables(store, mode))
+        for (auto & output : b.outputs)
+            outPaths.insert(output.second);
 
     return outPaths;
 }
diff --git a/src/nix/log.cc b/src/nix/log.cc
index ba5e71c10a08..15ae61d08ccb 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -24,23 +24,25 @@ struct CmdLog : InstallableCommand
 
     void run(ref<Store> store) override
     {
+        settings.readOnlyMode = true;
+
         auto subs = getDefaultSubstituters();
 
         subs.push_front(store);
 
-        for (auto & b : installable->toBuildable(true)) {
-
-            for (auto & sub : subs) {
-                auto log = b.second.drvPath != "" ? sub->getBuildLog(b.second.drvPath) : nullptr;
-                if (!log) {
-                    log = sub->getBuildLog(b.first);
-                    if (!log) continue;
-                }
-                stopProgressBar();
-                printInfo("got build log for '%s' from '%s'", b.first, sub->getUri());
-                std::cout << *log;
-                return;
+        auto b = installable->toBuildable();
+
+        for (auto & sub : subs) {
+            auto log = b.drvPath != "" ? sub->getBuildLog(b.drvPath) : nullptr;
+            for (auto & output : b.outputs) {
+                if (log) break;
+                log = sub->getBuildLog(output.second);
             }
+            if (!log) continue;
+            stopProgressBar();
+            printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
+            std::cout << *log;
+            return;
         }
 
         throw Error("build log of '%s' is not available", installable->what());