forked from lix-project/lix
* Another change to low-level derivations. The last one this year, I
promise :-) This allows derivations to specify on *what* output paths of input derivations they are dependent. This helps to prevent unnecessary downloads. For instance, a build might be dependent on the `devel' and `lib' outputs of some library component, but not the `docs' output.
This commit is contained in:
parent
6ff48e77f6
commit
05f0430de1
7 changed files with 70 additions and 32 deletions
|
@ -68,17 +68,17 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
|
||||||
|
|
||||||
/* For other derivations, replace the inputs paths with recursive
|
/* For other derivations, replace the inputs paths with recursive
|
||||||
calls to this function.*/
|
calls to this function.*/
|
||||||
PathSet inputs2;
|
DerivationInputs inputs2;
|
||||||
for (PathSet::iterator i = drv.inputDrvs.begin();
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||||
i != drv.inputDrvs.end(); ++i)
|
i != drv.inputDrvs.end(); ++i)
|
||||||
{
|
{
|
||||||
Hash h = state.drvHashes[*i];
|
Hash h = state.drvHashes[i->first];
|
||||||
if (h.type == htUnknown) {
|
if (h.type == htUnknown) {
|
||||||
Derivation drv2 = derivationFromPath(*i);
|
Derivation drv2 = derivationFromPath(i->first);
|
||||||
h = hashDerivationModulo(state, drv2);
|
h = hashDerivationModulo(state, drv2);
|
||||||
state.drvHashes[*i] = h;
|
state.drvHashes[i->first] = h;
|
||||||
}
|
}
|
||||||
inputs2.insert(printHash(h));
|
inputs2[printHash(h)] = i->second;
|
||||||
}
|
}
|
||||||
drv.inputDrvs = inputs2;
|
drv.inputDrvs = inputs2;
|
||||||
|
|
||||||
|
@ -119,7 +119,9 @@ static void processBinding(EvalState & state, Expr e, Derivation & drv,
|
||||||
/* !!! supports only single output path */
|
/* !!! supports only single output path */
|
||||||
Path outPath = evalPath(state, a);
|
Path outPath = evalPath(state, a);
|
||||||
|
|
||||||
drv.inputDrvs.insert(drvPath);
|
StringSet ids;
|
||||||
|
ids.insert("out");
|
||||||
|
drv.inputDrvs[drvPath] = ids;
|
||||||
ss.push_back(outPath);
|
ss.push_back(outPath);
|
||||||
} else
|
} else
|
||||||
throw Error("invalid derivation attribute");
|
throw Error("invalid derivation attribute");
|
||||||
|
|
|
@ -448,9 +448,10 @@ void DerivationGoal::haveStoreExpr()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inputs must be built before we can build this goal. */
|
/* Inputs must be built before we can build this goal. */
|
||||||
for (PathSet::iterator i = drv.inputDrvs.begin();
|
/* !!! but if possible, only install the paths that we need */
|
||||||
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||||
i != drv.inputDrvs.end(); ++i)
|
i != drv.inputDrvs.end(); ++i)
|
||||||
addWaitee(worker.makeDerivationGoal(*i));
|
addWaitee(worker.makeDerivationGoal(i->first));
|
||||||
|
|
||||||
for (PathSet::iterator i = drv.inputSrcs.begin();
|
for (PathSet::iterator i = drv.inputSrcs.begin();
|
||||||
i != drv.inputSrcs.end(); ++i)
|
i != drv.inputSrcs.end(); ++i)
|
||||||
|
@ -812,18 +813,23 @@ bool DerivationGoal::prepareBuild()
|
||||||
/* Determine the full set of input paths. */
|
/* Determine the full set of input paths. */
|
||||||
|
|
||||||
/* First, the input derivations. */
|
/* First, the input derivations. */
|
||||||
for (PathSet::iterator i = drv.inputDrvs.begin();
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||||
i != drv.inputDrvs.end(); ++i)
|
i != drv.inputDrvs.end(); ++i)
|
||||||
{
|
{
|
||||||
/* Add all the output closures of the input derivation `*i' as
|
/* Add the relevant output closures of the input derivation
|
||||||
input paths. !!! there should be a way to indicate
|
`*i' as input paths. Only add the closures of output paths
|
||||||
specific outputs. */
|
that are specified as inputs. */
|
||||||
/* !!! is `*i' present? */
|
/* !!! is `*i' present? */
|
||||||
assert(isValidPath(*i));
|
assert(isValidPath(i->first));
|
||||||
Derivation inDrv = derivationFromPath(*i);
|
Derivation inDrv = derivationFromPath(i->first);
|
||||||
for (DerivationOutputs::iterator j = inDrv.outputs.begin();
|
for (StringSet::iterator j = i->second.begin();
|
||||||
j != inDrv.outputs.end(); ++j)
|
j != i->second.begin(); ++j)
|
||||||
computeFSClosure(j->second.path, inputPaths);
|
if (inDrv.outputs.find(*j) != inDrv.outputs.end())
|
||||||
|
computeFSClosure(inDrv.outputs[*j].path, inputPaths);
|
||||||
|
else
|
||||||
|
throw Error(
|
||||||
|
format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'")
|
||||||
|
% drvPath % *j % i->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PathSet::iterator i = inputPaths.begin(); i != inputPaths.end(); ++i)
|
for (PathSet::iterator i = inputPaths.begin(); i != inputPaths.end(); ++i)
|
||||||
|
|
|
@ -3,4 +3,5 @@ init initDerivationsHelpers
|
||||||
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm |
|
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm |
|
||||||
|
|
||||||
| string string | ATerm | EnvBinding |
|
| string string | ATerm | EnvBinding |
|
||||||
|
| string ATermList | ATerm | DerivationInput |
|
||||||
| string string string string | ATerm | DerivationOutput |
|
| string string string string | ATerm | DerivationOutput |
|
||||||
|
|
|
@ -26,13 +26,13 @@ static void checkPath(const string & s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void parsePaths(ATermList paths, PathSet & out)
|
static void parseStrings(ATermList paths, StringSet & out, bool arePaths)
|
||||||
{
|
{
|
||||||
for (ATermIterator i(paths); i; ++i) {
|
for (ATermIterator i(paths); i; ++i) {
|
||||||
if (ATgetType(*i) != AT_APPL)
|
if (ATgetType(*i) != AT_APPL)
|
||||||
throw badTerm("not a path", *i);
|
throw badTerm("not a path", *i);
|
||||||
string s = aterm2String(*i);
|
string s = aterm2String(*i);
|
||||||
checkPath(s);
|
if (arePaths) checkPath(s);
|
||||||
out.insert(s);
|
out.insert(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,19 @@ Derivation parseDerivation(ATerm t)
|
||||||
drv.outputs[aterm2String(id)] = out;
|
drv.outputs[aterm2String(id)] = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
parsePaths(inDrvs, drv.inputDrvs);
|
for (ATermIterator i(inDrvs); i; ++i) {
|
||||||
parsePaths(inSrcs, drv.inputSrcs);
|
ATerm drvPath;
|
||||||
|
ATermList ids;
|
||||||
|
if (!matchDerivationInput(*i, drvPath, ids))
|
||||||
|
throwBadDrv(t);
|
||||||
|
Path drvPath2 = aterm2String(drvPath);
|
||||||
|
checkPath(drvPath2);
|
||||||
|
StringSet ids2;
|
||||||
|
parseStrings(ids, ids2, false);
|
||||||
|
drv.inputDrvs[drvPath2] = ids2;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseStrings(inSrcs, drv.inputSrcs, true);
|
||||||
|
|
||||||
drv.builder = aterm2String(builder);
|
drv.builder = aterm2String(builder);
|
||||||
drv.platform = aterm2String(platform);
|
drv.platform = aterm2String(platform);
|
||||||
|
@ -88,11 +99,11 @@ Derivation parseDerivation(ATerm t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ATermList unparsePaths(const PathSet & paths)
|
static ATermList unparseStrings(const StringSet & paths)
|
||||||
{
|
{
|
||||||
ATermList l = ATempty;
|
ATermList l = ATempty;
|
||||||
for (PathSet::const_iterator i = paths.begin();
|
for (PathSet::const_iterator i = paths.begin();
|
||||||
i != paths.end(); i++)
|
i != paths.end(); ++i)
|
||||||
l = ATinsert(l, toATerm(*i));
|
l = ATinsert(l, toATerm(*i));
|
||||||
return ATreverse(l);
|
return ATreverse(l);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +113,7 @@ ATerm unparseDerivation(const Derivation & drv)
|
||||||
{
|
{
|
||||||
ATermList outputs = ATempty;
|
ATermList outputs = ATempty;
|
||||||
for (DerivationOutputs::const_iterator i = drv.outputs.begin();
|
for (DerivationOutputs::const_iterator i = drv.outputs.begin();
|
||||||
i != drv.outputs.end(); i++)
|
i != drv.outputs.end(); ++i)
|
||||||
outputs = ATinsert(outputs,
|
outputs = ATinsert(outputs,
|
||||||
makeDerivationOutput(
|
makeDerivationOutput(
|
||||||
toATerm(i->first),
|
toATerm(i->first),
|
||||||
|
@ -110,14 +121,22 @@ ATerm unparseDerivation(const Derivation & drv)
|
||||||
toATerm(i->second.hashAlgo),
|
toATerm(i->second.hashAlgo),
|
||||||
toATerm(i->second.hash)));
|
toATerm(i->second.hash)));
|
||||||
|
|
||||||
|
ATermList inDrvs = ATempty;
|
||||||
|
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin();
|
||||||
|
i != drv.inputDrvs.end(); ++i)
|
||||||
|
inDrvs = ATinsert(inDrvs,
|
||||||
|
makeDerivationInput(
|
||||||
|
toATerm(i->first),
|
||||||
|
unparseStrings(i->second)));
|
||||||
|
|
||||||
ATermList args = ATempty;
|
ATermList args = ATempty;
|
||||||
for (Strings::const_iterator i = drv.args.begin();
|
for (Strings::const_iterator i = drv.args.begin();
|
||||||
i != drv.args.end(); i++)
|
i != drv.args.end(); ++i)
|
||||||
args = ATinsert(args, toATerm(*i));
|
args = ATinsert(args, toATerm(*i));
|
||||||
|
|
||||||
ATermList env = ATempty;
|
ATermList env = ATempty;
|
||||||
for (StringPairs::const_iterator i = drv.env.begin();
|
for (StringPairs::const_iterator i = drv.env.begin();
|
||||||
i != drv.env.end(); i++)
|
i != drv.env.end(); ++i)
|
||||||
env = ATinsert(env,
|
env = ATinsert(env,
|
||||||
makeEnvBinding(
|
makeEnvBinding(
|
||||||
toATerm(i->first),
|
toATerm(i->first),
|
||||||
|
@ -125,8 +144,8 @@ ATerm unparseDerivation(const Derivation & drv)
|
||||||
|
|
||||||
return makeDerive(
|
return makeDerive(
|
||||||
ATreverse(outputs),
|
ATreverse(outputs),
|
||||||
unparsePaths(drv.inputDrvs),
|
ATreverse(inDrvs),
|
||||||
unparsePaths(drv.inputSrcs),
|
unparseStrings(drv.inputSrcs),
|
||||||
toATerm(drv.platform),
|
toATerm(drv.platform),
|
||||||
toATerm(drv.builder),
|
toATerm(drv.builder),
|
||||||
ATreverse(args),
|
ATreverse(args),
|
||||||
|
|
|
@ -28,12 +28,17 @@ struct DerivationOutput
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef map<string, DerivationOutput> DerivationOutputs;
|
typedef map<string, DerivationOutput> DerivationOutputs;
|
||||||
|
|
||||||
|
/* For inputs that are sub-derivations, we specify exactly which
|
||||||
|
output IDs we are interested in. */
|
||||||
|
typedef map<Path, StringSet> DerivationInputs;
|
||||||
|
|
||||||
typedef map<string, string> StringPairs;
|
typedef map<string, string> StringPairs;
|
||||||
|
|
||||||
struct Derivation
|
struct Derivation
|
||||||
{
|
{
|
||||||
DerivationOutputs outputs; /* keyed on symbolic IDs */
|
DerivationOutputs outputs; /* keyed on symbolic IDs */
|
||||||
PathSet inputDrvs; /* inputs that are sub-derivations */
|
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
|
||||||
PathSet inputSrcs; /* inputs that are sources */
|
PathSet inputSrcs; /* inputs that are sources */
|
||||||
string platform;
|
string platform;
|
||||||
Path builder;
|
Path builder;
|
||||||
|
|
|
@ -39,9 +39,12 @@ void storePathRequisites(const Path & storePath,
|
||||||
|
|
||||||
Derivation drv = derivationFromPath(storePath);
|
Derivation drv = derivationFromPath(storePath);
|
||||||
|
|
||||||
for (PathSet::iterator i = drv.inputDrvs.begin();
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||||
i != drv.inputDrvs.end(); ++i)
|
i != drv.inputDrvs.end(); ++i)
|
||||||
storePathRequisites(*i, includeOutputs, paths);
|
/* !!! Maybe this is too strict, since it will include
|
||||||
|
*all* output paths of the input derivation, not just
|
||||||
|
the ones needed by this derivation. */
|
||||||
|
storePathRequisites(i->first, includeOutputs, paths);
|
||||||
|
|
||||||
for (PathSet::iterator i = drv.inputSrcs.begin();
|
for (PathSet::iterator i = drv.inputSrcs.begin();
|
||||||
i != drv.inputSrcs.end(); ++i)
|
i != drv.inputSrcs.end(); ++i)
|
||||||
|
|
|
@ -588,6 +588,8 @@ Strings unpackStrings(const string & s)
|
||||||
len |= ((unsigned char) *i++) << 16;
|
len |= ((unsigned char) *i++) << 16;
|
||||||
len |= ((unsigned char) *i++) << 24;
|
len |= ((unsigned char) *i++) << 24;
|
||||||
|
|
||||||
|
if (len == 0xffffffff) return strings; /* explicit end-of-list */
|
||||||
|
|
||||||
if (i + len > s.end())
|
if (i + len > s.end())
|
||||||
throw Error(format("short db entry: `%1%'") % s);
|
throw Error(format("short db entry: `%1%'") % s);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue