about summary refs log tree commit diff
path: root/src/libstore/misc.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-11-26T16·15+0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-11-26T16·15+0100
commit8d8d47abd2a66898aa5d8999fcd75b29991e529d (patch)
tree01ff64266efd7b5bf00f9e763b43f0b0fe469219 /src/libstore/misc.cc
parent46a369ad9558939bc2c6ee588df483ca503bbb5a (diff)
Only substitute wanted outputs of a derivation
If a derivation has multiple outputs, then we only want to download
those outputs that are actuallty needed.  So if we do "nix-build -A
openssl.man", then only the "man" output should be downloaded.
Likewise if another package depends on ${openssl.man}.

The tricky part is that different derivations can depend on different
outputs of a given derivation, so we may need to restart the
corresponding derivation goal if that happens.
Diffstat (limited to 'src/libstore/misc.cc')
-rw-r--r--src/libstore/misc.cc27
1 files changed, 17 insertions, 10 deletions
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index dacd1d3d74..ecba0c419d 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -93,12 +93,13 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
                 Derivation drv = derivationFromPath(store, i2.first);
 
                 PathSet invalid;
-                // FIXME: only fetch the desired outputs
                 foreach (DerivationOutputs::iterator, j, drv.outputs)
-                    if (!store.isValidPath(j->second.path)) invalid.insert(j->second.path);
+                    if (wantOutput(j->first, i2.second)
+                        && !store.isValidPath(j->second.path))
+                        invalid.insert(j->second.path);
                 if (invalid.empty()) continue;
 
-                todoDrv.insert(i2.first);
+                todoDrv.insert(*i);
                 if (settings.useSubstitutes) query.insert(invalid.begin(), invalid.end());
             }
 
@@ -115,26 +116,32 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
         store.querySubstitutablePathInfos(query, infos);
 
         foreach (PathSet::iterator, i, todoDrv) {
+            DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
+
             // FIXME: cache this
-            Derivation drv = derivationFromPath(store, *i);
+            Derivation drv = derivationFromPath(store, i2.first);
 
+            PathSet outputs;
             bool mustBuild = false;
             if (settings.useSubstitutes) {
-                foreach (DerivationOutputs::iterator, j, drv.outputs)
+                foreach (DerivationOutputs::iterator, j, drv.outputs) {
+                    if (!wantOutput(j->first, i2.second)) continue;
                     if (!store.isValidPath(j->second.path) &&
                         infos.find(j->second.path) == infos.end())
                         mustBuild = true;
+                    else
+                        outputs.insert(j->second.path);
+                }
             } else
                 mustBuild = true;
 
             if (mustBuild) {
-                willBuild.insert(*i);
+                willBuild.insert(i2.first);
                 todo.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
-                foreach (DerivationInputs::iterator, i, drv.inputDrvs)
-                    todo.insert(i->first);
+                foreach (DerivationInputs::iterator, j, drv.inputDrvs)
+                    todo.insert(makeDrvPathWithOutputs(j->first, j->second));
             } else
-                foreach (DerivationOutputs::iterator, i, drv.outputs)
-                    todoNonDrv.insert(i->second.path);
+                todoNonDrv.insert(outputs.begin(), outputs.end());
         }
 
         foreach (PathSet::iterator, i, todoNonDrv) {