diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 846cc259c..3be6d5937 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -423,6 +423,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) bool createDirsBeforeInstall = false; string runtimeStateArgs = ""; string sharedState = ""; + string externalState = ""; vector stateDirs; for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { @@ -508,7 +509,9 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) } } - else if(key == "solidStateDependencies"){ + else if(key == "solidStateDependency"){ + + /* ATermList es; value = evalExpr(state, value); if (!matchList(value, es)) { @@ -520,6 +523,8 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) string s = coerceToString(state, *i, context, true); drv.solidStateDeps.insert(s); } + */ + externalState = coerceToString(state, value, context, true); } else if(key == "shareType") { shareType = coerceToString(state, value, context, true); } else if(key == "synchronization") { syncState = coerceToString(state, value, context, true); } @@ -621,7 +626,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) if(enableState && !disableState){ if(runtimeStateArgs == ""){ string enableStateS = bool2string("true"); - drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateArgs, queryCurrentUsername(), "", false); + drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateArgs, queryCurrentUsername(), "", "", false); } } @@ -634,13 +639,6 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) drv.env["out"] = outPath; drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash); - /* Replace $(statePath) in solidStateDeps */ - for (StringSet::iterator i = drv.solidStateDeps.begin(); i != drv.solidStateDeps.end(); ++i) - if(*i == "$(statePath)" || "$statePath" ){ - drv.solidStateDeps.erase(*i); - drv.solidStateDeps.insert(outPath); - } - //printMsg(lvlError, format("DerivationOutput %1% %2% %3%") % outPath % outputHashAlgo % outputHash); //only add state when we have to to keep compitibilty with the 'old' format. //We add state when it's enbaled by the keywords, and not excplicitly disabled by the user @@ -657,7 +655,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) string enableStateS = bool2string("true"); string createDirsBeforeInstallS = bool2string(createDirsBeforeInstall); drv.stateOutputs["state"] = DerivationStateOutput(stateOutPath, printHash(componentHash), outputHashAlgo, outputHash, stateIdentifier, enableStateS, - shareType, syncState, createDirsBeforeInstallS, runtimeStateArgs, queryCurrentUsername(), sharedState); + shareType, syncState, createDirsBeforeInstallS, runtimeStateArgs, queryCurrentUsername(), sharedState, externalState); for(vector::iterator i = stateDirs.begin(); i != stateDirs.end(); ++i) drv.stateOutputDirs[(*i).path] = *(i); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 969608235..a960460ee 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1704,8 +1704,17 @@ void DerivationGoal::computeClosure() /* Get rid of all weird permissions. */ canonicalisePathMetaData(path); - /* Just before the very first scanForReferences, we insert the solid state references in its table so its references will show up in the scan*/ - setSolidStateReferencesTxn(noTxn, path, drv.solidStateDeps); + /* In case we have an externalState: + * Just before the very first scanForReferences, we insert the solid state references + * in its table so its references will show up in the scan + */ + if(isStateDrv(drv)){ + if(drv.stateOutputs.find("state")->second.externalState != ""){ + PathSet singStatePath; + singStatePath.insert(drv.stateOutputs.find("state")->second.statepath); + setSolidStateReferencesTxn(noTxn, path, singStatePath); + } + } /* For this output path, find the component references to other paths contained in it. */ PathSet references = scanForReferences(path, allPaths); diff --git a/src/libstore/db.cc b/src/libstore/db.cc index d886b3f7a..bb5eecf6e 100644 --- a/src/libstore/db.cc +++ b/src/libstore/db.cc @@ -664,13 +664,6 @@ void Database::setStateRevisions(const Transaction & txn, TableId revisions_tabl //get all paths that point to the same state (using shareing) and check if one of them equals the rootStatePath PathSet sharedWith = getSharedWithPathSetRecTxn(txn, statePath); - - /* - printMsg(lvlError, format("SP RootSP '%1%' - '%2%'") % statePath % rootStatePath); - for (PathSet::const_iterator j = sharedWith.begin(); j != sharedWith.end(); ++j) - printMsg(lvlError, format("SP SW '%1%'") % *j); - */ - if(statePath == rootStatePath || sharedWith.find(rootStatePath) != sharedWith.end()) metadata.push_back(comment); else diff --git a/src/libstore/derivations-ast.def b/src/libstore/derivations-ast.def index 7be6ad573..83ae2808a 100644 --- a/src/libstore/derivations-ast.def +++ b/src/libstore/derivations-ast.def @@ -1,10 +1,10 @@ init initDerivationsHelpers -Derive | ATermList ATermList ATermList ATermList ATermList ATermList string string ATermList ATermList | ATerm | +Derive | ATermList ATermList ATermList ATermList ATermList string string ATermList ATermList | ATerm | | string string | ATerm | EnvBinding | | string ATermList | ATerm | DerivationInput | | string string string string | ATerm | DerivationOutput | -| string string string string string string string string string string string string string | ATerm | DerivationStateOutput | +| string string string string string string string string string string string string string string | ATerm | DerivationStateOutput | | string string string | ATerm | DerivationStateOutputDir | #We use DeriveWithOutState to create derivations that dont use state, and thus dont have the stateDerivationStateOutput and DerivationStateOutputDir in their derivation diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 66039bd1d..3adda6dc1 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -67,12 +67,12 @@ Derivation parseDerivation(ATerm t) { Derivation drv; ATermList outs, inDrvs, inSrcs, args, bnds; - ATermList stateOuts = ATempty, stateOutDirs = ATempty, solidStateDeps = ATempty; + ATermList stateOuts = ATempty, stateOutDirs = ATempty; ATerm builder, platform; bool withState; - if (matchDerive(t, outs, stateOuts, stateOutDirs, solidStateDeps, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = true; } + if (matchDerive(t, outs, stateOuts, stateOutDirs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = true; } else if (matchDeriveWithOutState(t, outs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = false; } else throwBadDrv(t); @@ -93,8 +93,8 @@ Derivation parseDerivation(ATerm t) { //parse state part for (ATermIterator i(stateOuts); i; ++i) { - ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState; - if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState)) + ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState, externalState; //TODO unitialized warning + if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState, externalState)) throwBadDrv(t); DerivationStateOutput stateOut; stateOut.statepath = aterm2String(statepath); @@ -109,7 +109,8 @@ Derivation parseDerivation(ATerm t) stateOut.createDirsBeforeInstall = aterm2String(createDirsBeforeInstall); stateOut.runtimeStateArgs = aterm2String(runtimeStateArgs); stateOut.username = aterm2String(username); - stateOut.sharedState = aterm2String(sharedState); + stateOut.sharedState = aterm2String(sharedState); + stateOut.externalState = aterm2String(externalState); drv.stateOutputs[aterm2String(id)] = stateOut; } @@ -126,12 +127,6 @@ Derivation parseDerivation(ATerm t) drv.stateOutputDirs[aterm2String(id)] = stateOutDirs; } - //parse solid state dependencies - for (ATermIterator i(solidStateDeps); i; ++i) { - if (ATgetType(*i) != AT_APPL) - throw badTerm("string expected", *i); - drv.solidStateDeps.insert(aterm2String(*i)); - } } for (ATermIterator i(inDrvs); i; ++i) { @@ -201,7 +196,8 @@ ATerm unparseDerivation(const Derivation & drv) toATerm(i->second.createDirsBeforeInstall), toATerm(i->second.runtimeStateArgs), toATerm(i->second.username), - toATerm(i->second.sharedState) + toATerm(i->second.sharedState), + toATerm(i->second.externalState) )); } @@ -214,11 +210,6 @@ ATerm unparseDerivation(const Derivation & drv) toATerm(i->second.interval) )); - ATermList solidStateDeps = ATempty; - for (StringSet::const_reverse_iterator i = drv.solidStateDeps.rbegin(); - i != drv.solidStateDeps.rend(); ++i) - solidStateDeps = ATinsert(solidStateDeps, toATerm(*i)); - ATermList inDrvs = ATempty; for (DerivationInputs::const_reverse_iterator i = drv.inputDrvs.rbegin(); i != drv.inputDrvs.rend(); ++i) @@ -245,7 +236,6 @@ ATerm unparseDerivation(const Derivation & drv) outputs, stateOutputs, stateOutputDirs, - solidStateDeps, inDrvs, toATermList(drv.inputSrcs), toATerm(drv.platform), diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index 9025f9ed7..79472fa68 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -55,12 +55,14 @@ struct DerivationStateOutput string sharedState; //Path to share state From + string externalState; //a statePath not not in the stateStore (Official hack) + DerivationStateOutput() { } //TODO add const ?? - DerivationStateOutput(Path statepath, string componentHash, string hashAlgo, string hash, string stateIdentifier, string enabled, string shareType, string synchronization, string createDirsBeforeInstall, string runtimeStateArgs, string username, string sharedState, bool check=true) + DerivationStateOutput(Path statepath, string componentHash, string hashAlgo, string hash, string stateIdentifier, string enabled, string shareType, string synchronization, string createDirsBeforeInstall, string runtimeStateArgs, string username, string sharedState, string externalState, bool check=true) { if(check){ if(shareType != "none" && shareType != "full" && shareType != "group") @@ -73,8 +75,8 @@ struct DerivationStateOutput throw Error(format("the stateIdenfier cannot be this value '%1%'") % stateIdentifier); if(runtimeStateArgs == "__NOARGS__") throw Error(format("the runtimeStateArgs cannot be this value '%1%'") % runtimeStateArgs); - - + if(externalState != "" && sharedState != "") + throw Error(format("You cannot have an externalState and sharedState at the same time")); } //TODO @@ -93,6 +95,7 @@ struct DerivationStateOutput this->runtimeStateArgs = runtimeStateArgs; this->username = username; this->sharedState = sharedState; + this->externalState = externalState; } bool getEnabled(){ @@ -119,6 +122,7 @@ struct DerivationStateOutput this->runtimeStateArgs = ""; //this->username; //Changes the statepath directly this->sharedState = ""; + this->externalState = ""; } }; @@ -171,7 +175,6 @@ struct Derivation DerivationOutputs outputs; /* keyed on symbolic IDs */ DerivationStateOutputs stateOutputs; /* TODO */ DerivationStateOutputDirs stateOutputDirs; /* TODO */ - StringSet solidStateDeps; /* TODO */ DerivationInputs inputDrvs; /* inputs that are sub-derivations */ PathSet inputSrcs; /* inputs that are sources */ string platform; diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index d2e977f5d..8bfae9831 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1813,20 +1813,14 @@ PathSet getSharedWithPathSetRecTxn_private(const Transaction & txn, const Path & { //Get all paths pointing to statePath PathSet newStatePaths = getDirectlySharedWithPathSetTxn(txn, statePath); - - /* - printMsg(lvlError, format("getSharedWithPathSetRecTxn_private: '%1%'") % statePath); - for (PathSet::const_iterator j = newStatePaths.begin(); j != newStatePaths.end(); ++j) - printMsg(lvlError, format("newStatePaths '%1%'") % *j); - */ //go into recursion to see if there are more paths indirectly pointing to statePath for (PathSet::iterator i = newStatePaths.begin(); i != newStatePaths.end(); ++i){ + //Only recurse on the really new statePaths to prevent infinite recursion - if(statePaths.find(*i) == statePaths.end()) - { + if(statePaths.find(*i) == statePaths.end()) { statePaths.insert(*i); - statePaths = pathSets_union(statePaths, getSharedWithPathSetRecTxn_private(txn, *i, statePaths)); //TODO !!!!!!!!!!!!!!!!!!!!!! + statePaths = pathSets_union(statePaths, getSharedWithPathSetRecTxn_private(txn, *i, statePaths)); } } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 759b667b6..4a1f9ebe4 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1271,14 +1271,37 @@ string padd(const string & s, char c , unsigned int size, bool front) return ss; } -void sharePath(const Path & fromExisting, const Path & toNew) +void symlinkPath(const Path & fromExisting, const Path & toNew) { //Symlink link to the share path + //Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form) Strings p_args; p_args.push_back("-sf"); - p_args.push_back(fromExisting); + p_args.push_back(fromExisting); p_args.push_back(toNew); - runProgram_AndPrintOutput("ln", true, p_args, "ln"); //run + runProgram_AndPrintOutput("ln", true, p_args, "ln"); + + printMsg(lvlError, format("ln -sf %1% %2%") % fromExisting % toNew); +} + +void sharePath(const Path & fromExisting, const Path & toNew) +{ + symlinkPath(fromExisting, toNew); +} + +void copyContents(const Path & from, const Path & to) +{ + Strings p_args; + p_args.push_back("-R"); + p_args.push_back(from + "/*"); + p_args.push_back(to); + runProgram_AndPrintOutput("cp", true, p_args, "cp"); + + p_args.clear(); + p_args.push_back("-R"); + p_args.push_back(from + "/.*"); //Also copy the hidden files + p_args.push_back(to); + runProgram_AndPrintOutput("cp", true, p_args, "cp"); } } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 0160e01e9..5f3f6ca2f 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -327,8 +327,15 @@ void setChmod(const Path & pathOrFile, const string & chmod); string padd(const string & s, char c , unsigned int size, bool front = false); +/* Symlinks one path to the other */ +void symlinkPath(const Path & fromExisting, const Path & toNew); + +/* Exactly the same as symlinkPath */ void sharePath(const Path & fromExisting, const Path & toNew); +/* Copy all files and folders recursively (also the hidden ones) from the dir from/... to the dir to/... */ +void copyContents(const Path & from, const Path & to); + } #endif /* !__UTIL_H */ diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 8cb829a08..8dd6ccdd7 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -487,6 +487,8 @@ static void installDerivations(Globals & globals, DrvInfos newElems; queryInstSources(globals.state, globals.instSource, args, newElems, true); + StringPairs externalStates; //Mapping from statePath --> some path outide the store + StringSet newNames; for (DrvInfos::iterator i = newElems.begin(); i != newElems.end(); ++i) { /* `forceName' is a hack to get package names right in some @@ -501,11 +503,20 @@ static void installDerivations(Globals & globals, { DerivationStateOutputs stateOutputs = drv.stateOutputs; string stateIdentifier = stateOutputs.find("state")->second.stateIdentifier; - printMsg(lvlError, format("Add '%2%' with '%1%'") % stateIdentifier % i->queryOutPath(globals.state) ); + printMsg(lvlError, format("Add '%2%' with '%1%'") % stateIdentifier % i->queryOutPath(globals.state)); if(stateIdentifier == "") i->setStateIdentifier("__EMTPY__"); else i->setStateIdentifier(stateIdentifier); + + //Later on we need to link the sharedState path out of the store to the statePath inside the state-store + string externalState = stateOutputs.find("state")->second.externalState; + Path statePath = stateOutputs.find("state")->second.statepath; + if(externalState != ""){ + if(stateIdentifier != "") + externalState = externalState + "-" + stateIdentifier; + externalStates[statePath] = externalState; + } } if (globals.forceName != "") @@ -609,7 +620,41 @@ static void installDerivations(Globals & globals, //Set in database store->setSharedState(i->first, i->second); } + + //Let the stateDirs in /nix/state point to the solidStateDependencies + for (StringPairs::iterator i = externalStates.begin(); i != externalStates.end(); ++i){ + + Path statePath = i->first; + Path externalState = i->second; + //1. If dir externalState exists, we move its data into the statePath + //2. We ensure that the parent dir of externalState exists so we can create a symlink + if(IsDirectory(externalState)){ + copyContents(externalState, statePath); + + //TODO !!!!!!!!!!!!!! + //cp: cannot stat `/home/wouterdb/test/aaaaaaaa-test/*': No such file or directory + //error: program `cp' failed with exit code 1 + + deletePath(externalState); + } + else{ + + //Ensure parent dir + //outsidestorePath + //ensureDirExists(); + } + + //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! these last 2 items should be done by the store I think for security reasons !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // /nix/state should be root.nixbl and 775 + + //Now we create a symlink externalState --> statePath + printMsg(lvlError, format("SYMLINK: '%1%' --> '%2%'") % externalState % statePath); + symlinkPath(statePath, externalState); + + //SET IN DB !!! + //TODO + } }