1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-26 04:00:59 +01:00

nix-state now works, state is recursively commited (when necessary)

This commit is contained in:
Wouter den Breejen 2007-06-27 15:43:16 +00:00
parent c0dcfed3c3
commit 3d22bd50b3
17 changed files with 457 additions and 277 deletions

View file

@ -22,12 +22,15 @@ nonversionedpaths=( $4 )
checkouts=( $5 )
deletesvn=$6 #this flag can be set to 1 to DELETE all .svn folders and NOT commit
echo svnbin: $svnbin
echo subversionedpaths: ${subversionedpaths[@]}
echo subversionedpathsCommitBools: ${subversionedpathsCommitBools[@]}
echo nonversionedpaths: ${nonversionedpaths[@]}
echo checkouts: ${checkouts[@]}
echo deletesvn: $deletesvn
if [ "$debug" != "" ] ; then
echo svnbin: $svnbin
echo subversionedpaths: ${subversionedpaths[@]}
echo subversionedpathsCommitBools: ${subversionedpathsCommitBools[@]}
echo nonversionedpaths: ${nonversionedpaths[@]}
echo checkouts: ${checkouts[@]}
echo deletesvn: $deletesvn
fi
#
#

View file

@ -1629,6 +1629,7 @@ void DerivationGoal::computeClosure()
if(!drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
createStateDirs(drv.stateOutputDirs, drv.stateOutputs, drv.env);
/* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all
output paths read-only. */
@ -1681,7 +1682,7 @@ void DerivationGoal::computeClosure()
format("output path `%1%' should have %2% hash `%3%', instead has `%4%'")
% path % algo % printHash(h) % printHash(h2));
}
/* Get rid of all weird permissions. */
canonicalisePathMetaData(path);
@ -1719,7 +1720,7 @@ void DerivationGoal::computeClosure()
if we could combine this with filterReferences(). */
contentHashes[path] = hashPath(htSHA256, path);
}
/* Register each output path as valid, and register the sets of
paths referenced by each of them. This is wrapped in one
database transaction to ensure that if we crash, either
@ -1737,6 +1738,8 @@ void DerivationGoal::computeClosure()
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
//printMsg(lvlError, format("SetValidPath: %1%") % i->second.path);
registerValidPath(txn, i->second.path,
"", //dummy statePath
contentHashes[i->second.path],
@ -1744,19 +1747,22 @@ void DerivationGoal::computeClosure()
PathSet(), //dummy stateReferences
drvPath);
}
/*
* We first register alls paths as valid, and only scan for component references.
* Now that those paths are registered as valid, we're able to call queryDeriversStatePath
*
* We already scanned for Component references in Component paths
* Now we scan in Component paths for state references
* We already scanned for [Component references in Component paths] //1
* Now we scan in [Component paths for state references] //2
*
* If state is enabled for the path we:
* scan for and state references and component references in the state path
* [scan for and state references and component references in the state path] //3,4
*/
//TODO we scan for each output, be then we do multiple scans inside for the state path .....
//TODO !!!!!!!!! we don not ONLY need to scan all outputs, but also (recursively) the component references in the state folders
for (DerivationOutputs::iterator i = drv.outputs.begin(); i != drv.outputs.end(); ++i)
{
Path path = i->second.path;
@ -1770,7 +1776,7 @@ void DerivationGoal::computeClosure()
Path componentPath = *i;
if(isStateComponentTxn(txn, componentPath)){
//printMsg(lvlError, format("Scanning for state path: %1%") % (*i));
//printMsg(lvlError, format("Scanning for state path: %1%") % componentPath);
PathSet stateRefs = queryDeriversStatePath(txn, componentPath ,"*",getCallingUserName());
allStatePaths = mergePathSets(stateRefs, allStatePaths);
}
@ -1783,7 +1789,7 @@ void DerivationGoal::computeClosure()
if(isStateDrvTxn(txn, drv)){
Path statePath = drv.stateOutputs.find("state")->second.statepath;
printMsg(lvlTalkative, format("scanning for component and state references inside `%1%'") % statePath);
PathSet state_references = scanForReferences(statePath, allPaths);
PathSet state_stateReferences = scanForStateReferences(statePath, allStatePaths);
all_state_references = mergePathSets(all_state_references, mergePathSets(state_references, state_stateReferences));

View file

@ -507,16 +507,24 @@ void LocalStore::queryStateReferrers(const Path & storePath, PathSet & stateRefe
void setDeriver(const Transaction & txn, const Path & storePath, const Path & deriver)
{
printMsg(lvlError, format("xxxxxxxxxxxxxxxxxxxxxxx"));
assertStorePath(storePath);
printMsg(lvlError, format("Ttttttttttttttttttttttttt"));
if (deriver == "") return;
printMsg(lvlError, format("uuuuuuuuuuuuuuuuuuuuuuuuuuuuu"));
assertStorePath(deriver);
printMsg(lvlError, format("yyyyyyyyyyyyyyyyyyyyyyyyy"));
if (!isRealisablePath(txn, storePath))
throw Error(format("path `%1%' is not valid") % storePath);
if (isStateDrvPathTxn(txn, deriver)){ //Redirect if its a state component
printMsg(lvlError, format("bbbbbbbbbbbbbbb"));
addStateDeriver(txn, storePath, deriver);
}
else{
printMsg(lvlError, format("ccccccccccccccccccc"));
nixDB.setString(txn, dbDerivers, storePath, deriver);
}
}
@ -530,13 +538,19 @@ void addStateDeriver(const Transaction & txn, const Path & storePath, const Path
if (!isRealisablePath(txn, storePath))
throw Error(format("path `%1%' is not valid") % storePath);
printMsg(lvlError, format("dddddddddddddd"));
Derivation drv = derivationFromPath(deriver);
string identifier = drv.stateOutputs.find("state")->second.stateIdentifier;
string user = drv.stateOutputs.find("state")->second.username;
printMsg(lvlError, format("eeeeeeeeeeeeeeeeee"));
PathSet currentDerivers = queryDerivers(txn, storePath, identifier, user);
PathSet updatedDerivers = mergeNewDerivationIntoList(storePath, deriver, currentDerivers, true);
printMsg(lvlError, format("ffffffffffffffffffff"));
Strings data;
for (PathSet::iterator i = updatedDerivers.begin(); i != updatedDerivers.end(); ++i) //Convert Paths to Strings
data.push_back(*i);
@ -597,7 +611,7 @@ Path queryDeriver(const Transaction & txn, const Path & storePath)
bool b = nixDB.queryString(txn, dbDerivers, storePath, deriver);
Derivation drv = derivationFromPath(deriver);
if (drv.outputs.size() != 0)
if (isStateDrvTxn(txn, drv))
throw Error(format("This deriver `%1%' is a state deriver, u should use queryDerivers instead of queryDeriver") % deriver);
if (b)
@ -769,18 +783,14 @@ void clearSubstitutes()
static void setHash(const Transaction & txn, const Path & storePath, const Hash & hash, bool stateHash = false)
{
if(stateHash){
nixDB.setString(txn, dbValidStatePaths, storePath, "");
}
else{
nixDB.setString(txn, dbValidPaths, storePath, "sha256:" + printHash(hash));
assert(hash.type == htSHA256);
}
nixDB.setString(txn, dbValidPaths, storePath, "sha256:" + printHash(hash));
assert(hash.type == htSHA256);
}
static void setStateHash(const Transaction & txn, const Path & storePath, const Hash & hash)
static void setStateValid(const Transaction & txn, const Path & statePath, const Path & drvPath)
{
setHash(txn, storePath, hash, true);
printMsg(lvlError, format("setStateValid: '%1%' '%2%'") % statePath % drvPath);
nixDB.setString(txn, dbValidStatePaths, statePath, drvPath);
}
static Hash queryHash(const Transaction & txn, const Path & storePath)
@ -806,6 +816,20 @@ Hash LocalStore::queryPathHash(const Path & path)
return queryHash(noTxn, path);
}
static Path queryStatePathDrv(const Transaction & txn, const Path & statePath)
{
string s;
nixDB.queryString(txn, dbValidStatePaths, statePath, s);
return s;
}
Path LocalStore::queryStatePathDrv(const Path & statePath)
{
if (!isValidStatePath(statePath))
throw Error(format("statepath `%1%' is not valid") % statePath);
return nix::queryStatePathDrv(noTxn, statePath);
}
void registerValidPath(const Transaction & txn,
const Path & path, const Path & statePath, const Hash & hash,
@ -839,19 +863,18 @@ void registerValidPaths(const Transaction & txn, const ValidPathInfos & infos)
setHash(txn, i->path, i->hash);
if (i->statePath != "")
setStateHash(txn, i->statePath, Hash()); //the hash value in the db now becomes empty, but if the key exists, we know that the state path is valid
setStateValid(txn, i->statePath, i->deriver); //if the key exists, we know that the state path is valid, we set the value to the drvPath
setReferences(txn, i->path, i->references, i->stateReferences);
/* Check that all referenced paths are also valid (or about to) become valid). */
//TODO Maybe also check this for stateReferences????
for (PathSet::iterator j = i->references.begin();
j != i->references.end(); ++j)
if (!isValidPathTxn(txn, *j) && newPaths.find(*j) == newPaths.end())
throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid")
% i->path % *j);
//TODO Also do this for stateReferences????
setDeriver(txn, i->path, i->deriver);
}
}
@ -1489,11 +1512,79 @@ void storePathRequisites(const Path & storePath, const bool includeOutputs, Path
}
}
/*
* Same as storePathRequisites with withState=true, but now only returns the state paths
*/
void storePathStateRequisitesOnlyTxn(const Transaction & txn, const Path & storePath, const bool includeOutputs, PathSet & statePaths)
{
PathSet paths;
storePathRequisites(storePath, includeOutputs, paths, true);
//filter out all non-state paths
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i){
if (isValidStatePathTxn(txn, *i))
statePaths.insert(*i);
}
}
void LocalStore::storePathStateRequisitesOnly(const Path & storePath, const bool includeOutputs, PathSet & statePaths)
{
nix::storePathStateRequisitesOnlyTxn(noTxn, storePath, includeOutputs, statePaths);
}
void LocalStore::storePathRequisites(const Path & storePath, const bool includeOutputs, PathSet & paths, const bool & withState)
{
return nix::storePathRequisites(storePath, includeOutputs, paths, withState);
}
void convertStatePathsToDerivations(const Transaction & txn, const Path & storePath)
{
//TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
void getDependenciesAtBuildTime(const Transaction & txn, const Path & drvPath)
{
Derivation drv = derivationFromPath(drvPath);
PathSet allPaths;
PathSet inputPaths;
//TODO THIS IS A DIRECT COPY FROM BUILD.CC WE SHOULD MERGE !!!!!!!!!!!!1!!!!!!!!!!!!!
/* The outputs are referenceable paths. */
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
debug(format("building path `%1%'") % i->second.path);
allPaths.insert(i->second.path);
}
/* First, the input derivations. */
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
{
/* Add the relevant output closures of the input derivation
`*i' as input paths. Only add the closures of output paths
that are specified as inputs. */
assert(store->isValidPath(i->first));
Derivation inDrv = derivationFromPath(i->first);
for (StringSet::iterator j = i->second.begin(); j != i->second.end(); ++j)
if (inDrv.outputs.find(*j) != inDrv.outputs.end())
computeFSClosure(inDrv.outputs[*j].path, inputPaths, false); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!! WE (MAY) ALSO NEED TO COPY STATE
else
throw Error(format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'") % drvPath % *j % i->first);
}
/* Second, the input sources. */
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
computeFSClosure(*i, inputPaths, false); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!! WE (MAY) ALSO NEED TO COPY STATE
//debug(format("added input paths %1%") % showPaths(inputPaths)); //TODO
allPaths.insert(inputPaths.begin(), inputPaths.end());
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
printMsg(lvlError, format("ALLPATHS2: %1%") % *i);
}
/* Upgrade from schema 1 (Nix <= 0.7) to schema 2 (Nix >= 0.8). */
static void upgradeStore07()
{

View file

@ -48,6 +48,8 @@ public:
Substitutes querySubstitutes(const Path & srcPath);
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);
void queryReferences(const Path & path, PathSet & references);
@ -96,6 +98,8 @@ public:
void storePathRequisites(const Path & storePath, const bool includeOutputs, PathSet & paths, const bool & withState);
void storePathStateRequisitesOnly(const Path & storePath, const bool includeOutputs, PathSet & statePaths);
};
@ -205,6 +209,8 @@ bool isStateComponentTxn(const Transaction & txn, const Path & path);
bool isStateDrvPathTxn(const Transaction & txn, const Path & drvPath);
bool isStateDrvTxn(const Transaction & txn, const Derivation & drv);
void convertStatePathsToDerivations(const Transaction & txn, const Path & storePath);
}

View file

@ -17,28 +17,32 @@ Derivation derivationFromPath(const Path & drvPath)
return parseDerivation(t);
}
/*
void computeFSClosure(const Path & storePath,
PathSet & paths, bool flipDirection)
{
if (paths.find(storePath) != paths.end()) return;
paths.insert(storePath);
PathSet references;
if (flipDirection)
store->queryReferrers(storePath, references);
else
store->queryReferences(storePath, references);
for (PathSet::iterator i = references.begin(); i != references.end(); ++i)
computeFSClosure(*i, paths, flipDirection);
}
*/
void computeFSClosure(const Path & path, PathSet & paths, const bool & withState, bool flipDirection)
{
if (paths.find(path) != paths.end()) return;
PathSet allPaths;
computeFSClosureRec(path, allPaths, flipDirection);
//if withState is false, we filter out all state paths
if(withState == false){
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i){
if ( ! store->isValidStatePath(*i) ){
paths.insert(*i);
//TODO (OBSOLETE) CHECK TO SEE IF THERE WERE NO /NIX/STATE PATHS THAT ARENT VALID AT THIS POINT, REMOVE THIS IN THE FUTURE
string test = "/nix/state";
if((*i).substr(0, test.size()) == test)
throw Error(format("THIS CANNOT HAPPEN ! computeFSClosure is called before the state path was valid...."));
}
}
}
else{
paths = allPaths;
}
}
void computeFSClosureRec(const Path & path, PathSet & paths, const bool & flipDirection)
{
if (paths.find(path) != paths.end()) return; //takes care of double entries
paths.insert(path);
@ -47,23 +51,18 @@ void computeFSClosure(const Path & path, PathSet & paths, const bool & withState
if (flipDirection){
store->queryReferrers(path, references);
if(withState)
store->queryStateReferrers(path, stateReferences);
store->queryStateReferrers(path, stateReferences);
}
else{
store->queryReferences(path, references);
if(withState)
store->queryStateReferences(path, stateReferences);
store->queryStateReferences(path, stateReferences);
}
PathSet allReferences;
if(withState)
allReferences = mergePathSets(references, stateReferences);
else
allReferences = references;
allReferences = mergePathSets(references, stateReferences);
for (PathSet::iterator i = allReferences.begin(); i != allReferences.end(); ++i)
computeFSClosure(*i, paths, withState, flipDirection);
computeFSClosureRec(*i, paths, flipDirection);
}

View file

@ -18,8 +18,9 @@ Derivation derivationFromPath(const Path & drvPath);
`storePath' is returned; that is, the closures under the
`referrers' relation instead of the `references' relation is
returned. */
void computeFSClosure(const Path & storePath,
PathSet & paths, const bool & withState, bool flipDirection = false);
void computeFSClosure(const Path & storePath, PathSet & paths, const bool & withState, bool flipDirection = false);
void computeFSClosureRec(const Path & path, PathSet & paths, const bool & flipDirection); //private
/* Return the path corresponding to the output identifier `id' in the
given derivation. */

View file

@ -206,6 +206,14 @@ Hash RemoteStore::queryPathHash(const Path & path)
return parseHash(htSHA256, hash);
}
Path RemoteStore::queryStatePathDrv(const Path & statePath)
{
writeInt(wopQueryStatePathDrv, to);
writeString(statePath, to);
processStderr();
Path p = readString(from); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!! check wheter from is the state path ????
return p;
}
void RemoteStore::queryReferences(const Path & path,
PathSet & references)
@ -449,4 +457,10 @@ void RemoteStore::storePathRequisites(const Path & storePath, const bool include
}
//TODO
void RemoteStore::storePathStateRequisitesOnly(const Path & storePath, const bool includeOutputs, PathSet & statePaths)
{
}
}

View file

@ -36,6 +36,8 @@ public:
bool hasSubstitutes(const Path & path);
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);
void queryReferences(const Path & path, PathSet & references);
@ -84,6 +86,7 @@ public:
void storePathRequisites(const Path & storePath, const bool includeOutputs, PathSet & paths, const bool & withState);
void storePathStateRequisitesOnly(const Path & storePath, const bool includeOutputs, PathSet & statePaths);
private:
AutoCloseFD fdSocket;

View file

@ -115,9 +115,7 @@ void checkStatePath(const Derivation & drv)
Error(format("The statepath from the Derivation does not match the recalculated statepath, are u trying to spoof the statepath?"));
}
Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier)
void calculateStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier, Path & rootPath, Path & fullPath)
{
//This is a little trick: we could use the same hash as the statepath, but we change it so the repository also gets a unique scannable hash
Hash hash = hashString(htSHA256, statePath);
@ -127,7 +125,7 @@ Path makeStateReposPath(const string & type, const Path statePath, const string
throw Error(format("Cannot create a repository for a subfolder without a name"));
string hash_subfolder = type + ":sha256:" + printHash(hash) + ":" + subfolder;
string subfolder_ = printHash32(compressHash(hashString(htSHA256, hash_subfolder), 20)) + "-" + subfolder;
string subfolder2 = printHash32(compressHash(hashString(htSHA256, hash_subfolder), 20)) + "-" + subfolder;
string suffix_stateIdentifier = stateIdentifier;
if(suffix_stateIdentifier != "")
@ -140,9 +138,27 @@ Path makeStateReposPath(const string & type, const Path statePath, const string
checkStoreName(suffix);
checkStoreName(stateIdentifier);
return nixStoreStateRepos + "/"
rootPath = nixStoreStateRepos + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20))
+ "-" + suffix + suffix_stateIdentifier + "/" + subfolder_;
+ "-" + suffix + suffix_stateIdentifier;
fullPath = rootPath + "/" + subfolder2;
}
Path getStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier)
{
Path fullPath;
Path rootPath;
calculateStateReposPath(type, statePath, subfolder, suffix, stateIdentifier, rootPath, fullPath);
return fullPath;
}
Path getStateReposRootPath(const string & type, const Path statePath, const string & suffix, const string & stateIdentifier)
{
Path fullPath;
Path rootPath;
calculateStateReposPath(type, statePath, "/", suffix, stateIdentifier, rootPath, fullPath);
return rootPath;
}
Path makeFixedOutputPath(bool recursive,

View file

@ -75,6 +75,9 @@ public:
/* Queries the hash of a valid path. */
virtual Hash queryPathHash(const Path & path) = 0;
/* Queries the derivation Path of a valid state path. */
virtual Path queryStatePathDrv(const Path & statePath) = 0;
/* Queries the set of outgoing FS references for a store path.
The result is not cleared. */
virtual void queryReferences(const Path & path,
@ -212,7 +215,8 @@ public:
virtual bool isStateDrv(const Derivation & drv) = 0;
virtual void storePathRequisites(const Path & storePath, const bool includeOutputs, PathSet & paths, const bool & withState) = 0;
virtual void storePathStateRequisitesOnly(const Path & storePath, const bool includeOutputs, PathSet & statePaths) = 0;
};
@ -245,9 +249,14 @@ Path makeStatePath(const string & componentHash, const string & suffix, const st
/* TODO ... */
void checkStatePath(const Derivation & drv);
/* Constructs a unique store state repos path name. */
Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier);
/* Calculates a unique store state repos path and also the root path */
void calculateStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier, Path & rootPath, Path & fullPath);
/* Returns the full repository path */
Path getStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier);
/* Returns the root path containing the repository's */
Path getStateReposRootPath(const string & type, const Path statePath, const string & suffix, const string & stateIdentifier);
/* This is the preparatory part of addToStore() and addToStoreFixed();
it computes the store path to which srcPath is to be copied.

View file

@ -39,6 +39,10 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
string svnadminbin = nixSVNPath + "/svnadmin";
PathSet intervalPaths;
//Make sure the 'root' path which holds the repositorys exists, so svn doenst complain.
string repos_root_path = getStateReposRootPath("stateOutput:staterepospath", stateDir, drvName, stateIdentifier);
executeAndPrintShellCommand("mkdir -p " + repos_root_path, "mkdir");
//TODO check if we can create state and staterepos dirs
@ -56,13 +60,13 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
}
//Create a repository for this state location
string repos = makeStateReposPath("stateOutput:staterepospath", stateDir, thisdir, drvName, stateIdentifier);
executeAndPrintShellCommand("mkdir -p " + repos, "mkdir");
string repos = getStateReposPath("stateOutput:staterepospath", stateDir, thisdir, drvName, stateIdentifier);
if(IsDirectory(repos))
printMsg(lvlTalkative, format("Repos %1% already exists, so we use that repository") % repos);
else
executeAndPrintShellCommand(svnadminbin + " create " + repos, "svnadmin"); //TODO create as nixbld.nixbld chmod 700... can you still commit than ??
executeAndPrintShellCommand(svnadminbin + " create " + repos, "svnadmin"); //TODO create as nixbld.nixbld chmod 700... can you still commit then ??
if(d.type == "interval"){
intervalPaths.insert(statePath);
@ -70,12 +74,13 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
printMsg(lvlTalkative, format("Adding state subdir: %1% to %2% from repository %3%") % thisdir % fullstatedir % repos);
if(IsDirectory(fullstatedir + "/.svn/")){
string fullstatedir_svn = fullstatedir + "/.svn/";
if( ! IsDirectory(fullstatedir_svn) ){
string checkoutcommand = svnbin + " checkout file://" + repos + " " + fullstatedir;
executeAndPrintShellCommand(checkoutcommand, "svn"); //TODO checkout as user
}
else
printMsg(lvlTalkative, format("Statedir %1% already exists, so dont check out its repository again") % fullstatedir);
printMsg(lvlTalkative, format("Statedir %1% already exists, so dont check out its repository again") % fullstatedir_svn);
}
//Initialize the counters for the statePaths that have an interval to 0

View file

@ -17,6 +17,7 @@ typedef enum {
wopQuerySubstitutes,
wopHasSubstitutes,
wopQueryPathHash,
wopQueryStatePathDrv,
wopQueryReferences,
wopQueryStateReferences,
wopQueryReferrers,

View file

@ -1015,6 +1015,19 @@ string trim(const string & s) {
//TODO , check if we can replace!!! with runProgram like this: string a = runProgram("whoami", true, s);
/*
Strings args;
args.push_back("rsautl");
args.push_back("-sign");
args.push_back("-inkey");
args.push_back(secretKey);
args.push_back("-in");
args.push_back(hashFile);
string signature = runProgram(OPENSSL_PATH, true, args);
*/
void executeAndPrintShellCommand(const string & command, const string & commandName)
{
string tempoutput = "/tmp/svnoutput.txt";
@ -1073,20 +1086,18 @@ string time_t2string(const time_t & t)
return s;
}
//TODO Does this work on windows?
bool FileExist(const string FileName)
{
const char* FileName_C = FileName.c_str();
//strcpy(FileName_C, FileName.c_str());
struct stat my_stat;
return (stat(FileName_C, &my_stat) == 0);
}
//TODO Does this work on windows?
bool IsDirectory(const string FileName)
{
const char* FileName_C = FileName.c_str();
//strcpy(FileName_C, FileName.c_str());
struct stat my_stat;
if (stat(FileName_C, &my_stat) != 0) return false;
return ((my_stat.st_mode & S_IFDIR) != 0);
@ -1095,7 +1106,7 @@ bool IsDirectory(const string FileName)
string getCallingUserName()
{
//TODO Make this work on WINDOWS
//TODO Make this work on WINDOWS: Untested!
/*
#include <windows.h>
char acUserName[100];
@ -1109,12 +1120,11 @@ string getCallingUserName()
//Linux
Strings empty;
string username = runProgram("whoami", true, empty); //the username of the user that is trying to build the component
//TODO Can and Should NOT be faked, so this is clearly unsafe ... :(
//TODO Can be faked, so this is clearly unsafe ... :(
//Remove the \n
int pos = username.find("\n",0);
username.erase(pos,1);
//return "root6";
return username;
}

View file

@ -18,6 +18,10 @@ using std::cout;
typedef void (* Operation) (Strings opFlags, Strings opArgs);
//two global variables
string stateIdentifier;
string username;
/************************* Build time Functions ******************************/
@ -36,12 +40,13 @@ void printHelp()
//
Derivation getDerivation_andCheckArgs_(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath, string & stateIdentifier, string & binary, string & derivationPath, bool isStatePath,
bool getDerivers, PathSet & derivers, string & username) //optional
Derivation getDerivation_andCheckArgs_(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath,
string & binary, string & derivationPath, bool isStatePath, Strings & program_args,
bool getDerivers, PathSet & derivers) //optional
{
if (!opFlags.empty()) throw UsageError("unknown flag");
if ( (opArgs.size() != 1 && opArgs.size() != 2) && (getDerivers && opArgs.size() != 3) )
throw UsageError("only one or two arguments allowed component path / identiefier (or a third when you need to see the derivations: [username]) )");
if ( opArgs.size() != 1 && opArgs.size() != 2 )
throw UsageError("only one or two arguments allowed component path and program arguments (counts as one) ");
//Parse the full path like /nix/store/...../bin/hello
string fullPath = opArgs.front();
@ -56,63 +61,67 @@ Derivation getDerivation_andCheckArgs_(Strings opFlags, Strings opArgs, Path & c
//Check if path is statepath
isStatePath = store->isStateComponent(componentPath);
//Extract the program arguments
string allargs;
if(opArgs.size() > 1){
opArgs.pop_front();
stateIdentifier = opArgs.front();
}
if(username == "")
username = getCallingUserName();
allargs = opArgs.front();
Strings progam_args;
//TODO !!!!!!!!!!!!!!!!!!!!!!
}
//printMsg(lvlError, format("%1% - %2% - %3% - %4%") % componentPath % stateIdentifier % binary % username);
printMsg(lvlError, format("'%1%' - '%2%' - '%3%' - '%4%' - '%5%'") % componentPath % stateIdentifier % binary % username % allargs);
derivers = queryDerivers(noTxn, componentPath, stateIdentifier, username);
if(isStatePath)
derivers = queryDerivers(noTxn, componentPath, stateIdentifier, username);
else
derivers.insert(queryDeriver(noTxn, componentPath));
if(getDerivers == true)
return Derivation();
else if(derivers.size() == 0)
throw UsageError(format("There are no derivers with this combination of identifier '%1%' and username '%2%'") % stateIdentifier % username);
else if(derivers.size() != 1)
throw UsageError(format("There is more than one deriver with identifier '%1%' and username '%2%'") % stateIdentifier % username);
if(isStatePath){
if(derivers.size() == 0)
throw UsageError(format("There are no derivers with this combination of identifier '%1%' and username '%2%'") % stateIdentifier % username);
if(derivers.size() != 1)
throw UsageError(format("There is more than one deriver with stateIdentifier '%1%' and username '%2%'") % stateIdentifier % username);
}
Derivation drv;
for (PathSet::iterator i = derivers.begin(); i != derivers.end(); ++i){ //ugly workaround for drvs[0].
derivationPath = *i;
drv = derivationFromPath(derivationPath);
}
DerivationStateOutputs stateOutputs = drv.stateOutputs;
statePath = stateOutputs.find("state")->second.statepath;
if(isStatePath){
DerivationStateOutputs stateOutputs = drv.stateOutputs;
statePath = stateOutputs.find("state")->second.statepath;
}
return drv;
}
//Wrapper
Derivation getDerivation_andCheckArgs(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath, string & stateIdentifier, string & binary, string & derivationPath, bool & isStatePath)
Derivation getDerivation_andCheckArgs(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath,
string & binary, string & derivationPath, bool & isStatePath, Strings & program_args)
{
PathSet empty;
string empty2;
return getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, isStatePath, false, empty, empty2);
return getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStatePath, program_args, false, empty);
}
//
static void opShowDerivations(Strings opFlags, Strings opArgs)
{
string username;
if(opArgs.size() == 3)
username = opArgs.back();
else if(opArgs.size() == 2)
username = getCallingUserName();
string stateIdentifier;
Path componentPath;
Path statePath;
string binary;
PathSet derivers;
string derivationPath;
bool isStatePath;
Derivation drv = getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, true, isStatePath, derivers, username);
Strings program_args;
Derivation drv = getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStatePath, program_args, true, derivers);
if(!isStatePath)
throw UsageError(format("This path '%1%' is not a state path") % componentPath);
@ -127,11 +136,11 @@ static void opShowStatePath(Strings opFlags, Strings opArgs)
{
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath;
bool isStatePath;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, isStatePath);
Strings program_args;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStatePath, program_args);
if(!isStatePath)
throw UsageError(format("This path '%1%' is not a state path") % componentPath);
@ -144,191 +153,175 @@ static void opShowStateReposRootPath(Strings opFlags, Strings opArgs)
{
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath;
bool isStatePath;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, isStatePath);
Strings program_args;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStatePath, program_args);
if(!isStatePath)
throw UsageError(format("This path '%1%' is not a state path") % componentPath);
//Get the a repository for this state location
string drvName = drv.env.find("name")->second;
string repos = makeStateReposPath("stateOutput:staterepospath", statePath, "/", drvName, stateIdentifier); //this is a copy from store-state.cc
string repos = getStateReposPath("stateOutput:staterepospath", statePath, "/", drvName, stateIdentifier); //this is a copy from store-state.cc
printMsg(lvlError, format("%1%") % repos);
}
PathSet getReferencesClosureWithState(const Path & storepath)
//Comment TODO
PathSet getAllStateDerivationsRecursively(const Path & storePath)
{
PathSet paths;
store->storePathRequisites(storepath, false, paths, true);
//Get recursively all state paths
PathSet statePaths;
store->storePathStateRequisitesOnly(storePath, false, statePaths);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
{
printMsg(lvlError, format("REFCLOSURE %1%") % *i);
}
//return drvs ! (combo of component + state | component path)
//return single state paths
//Find the matching drv with the statePath
PathSet derivations;
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
derivations.insert(store->queryStatePathDrv(*i));
return derivations;
}
//TODO
static void recheckrefsinstaterecursive()
{
//PathSet state_references = scanForReferences(statePath, allPaths);
//PathSet state_stateReferences = scanForStateReferences(statePath, allStatePaths);
}
static void opRunComponent(Strings opFlags, Strings opArgs)
{
//get the derivation of the current component
//get the all the info of the component that is being called (we dont really use it yet)
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath;
bool isStatePath;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, isStatePath);
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
DerivationStateOutputs stateOutputs = drv.stateOutputs;
DerivationOutputs outputs = drv.outputs;
string drvName = drv.env.find("name")->second;
Strings program_args;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStatePath, program_args);
//Specifiy the SVN binarys
string svnbin = nixSVNPath + "/svn";
string svnadminbin = nixSVNPath + "/svnadmin";
//Check if component is a state component !!!
//Check for locks ...
//Check for locks ... ?
//add locks ... ?
//svn lock ... ?
//******************* Run the component
//TODO
//******************* Afterwards, call the commit script (recursively)
//get dependecies (if neccecary | recusively) of all state components that need to be updated
//
//TODO nix-store -qR $(nix-store -qd /nix/store/6x6glnb9idn53yxfqrz6wq53459vv3qd-firefox-2.0.0.3/)
//TODO maybe also scan the parameters for state or component hashes?
PathSet drvs = getAllStateDerivationsRecursively(componentPath);
//????
//Transaction txn;
//createStoreTransaction(txn);
//txn.commit();
//or noTxn
//******************* With everything in place, we call the commit script on all statePaths **********************
//for(...){
//
//}
string svnbin = nixSVNPath + "/svn";
string svnadminbin = nixSVNPath + "/svnadmin";
//Vector includeing all commit scripts:
vector<string> subversionedpaths;
vector<bool> subversionedpathsCommitBoolean;
vector<string> nonversionedpaths; //of type none, no versioning needed
vector<string> checkoutcommands;
for (PathSet::iterator d = drvs.begin(); d != drvs.end(); ++d)
{
//Extract the neccecary info from each Drv
Path drvPath = *d;
Derivation drv = derivationFromPath(drvPath);
DerivationStateOutputs stateOutputs = drv.stateOutputs;
Path statePath = stateOutputs.find("state")->second.statepath;
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
string drvName = drv.env.find("name")->second;
//Get all the inverals from the database at once
PathSet intervalPaths;
for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){
DerivationStateOutputDir d = i->second;
string thisdir = d.path;
string fullstatedir = statePath + "/" + thisdir;
//Print
printMsg(lvlError, format("Committing statePath: %1%") % statePath);
//Vector includeing all commit scripts:
vector<string> subversionedpaths;
vector<bool> subversionedpathsCommitBoolean;
vector<string> nonversionedpaths; //of type none, no versioning needed
vector<string> checkoutcommands;
if(d.type == "interval"){
intervalPaths.insert(fullstatedir);
//Get all the inverals from the database at once
PathSet intervalPaths;
for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){
DerivationStateOutputDir d = i->second;
string thisdir = d.path;
string fullstatedir = statePath + "/" + thisdir;
if(d.type == "interval"){
intervalPaths.insert(fullstatedir);
}
}
vector<int> intervals = store->getStatePathsInterval(intervalPaths);
int intervalAt=0;
for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){
DerivationStateOutputDir d = i->second;
string thisdir = d.path; //TODO CONVERT
string fullstatedir = statePath + "/" + thisdir;
if(thisdir == "/") //exception for the root dir
fullstatedir = statePath + "/";
if(d.type == "none"){
nonversionedpaths.push_back(fullstatedir);
continue;
}
//Get the a repository for this state location
string repos = getStateReposPath("stateOutput:staterepospath", statePath, thisdir, drvName, stateIdentifier); //this is a copy from store-state.cc
//Add the checkout command in case its needed
checkoutcommands.push_back(svnbin + " --ignore-externals checkout file://" + repos + " " + fullstatedir);
subversionedpaths.push_back(fullstatedir);
if(d.type == "interval"){
//Get the interval-counter from the database
int interval_counter = intervals[intervalAt];
int interval = d.getInterval();
subversionedpathsCommitBoolean.push_back(interval_counter % interval == 0);
//update the interval
intervals[intervalAt] = interval_counter + 1;
intervalAt++;
}
else if(d.type == "full")
subversionedpathsCommitBoolean.push_back(true);
else if(d.type == "manual") //TODO !!!!!
subversionedpathsCommitBoolean.push_back(false);
else
throw Error(format("interval '%1%' is not handled in nix-state") % d.type);
}
//Update the intervals again
//store->setStatePathsInterval(intervalPaths, intervals); //TODO UNCOMMENT
//Call the commit script with the appropiate paramenters
string subversionedstatepathsarray;
for (vector<string>::iterator i = subversionedpaths.begin(); i != subversionedpaths.end(); ++i)
{
subversionedstatepathsarray += *(i) + " ";
}
string subversionedpathsCommitBooleansarray;
for (vector<bool>::iterator i = subversionedpathsCommitBoolean.begin(); i != subversionedpathsCommitBoolean.end(); ++i)
{
subversionedpathsCommitBooleansarray += bool2string(*i) + " ";
}
string nonversionedstatepathsarray;
for (vector<string>::iterator i = nonversionedpaths.begin(); i != nonversionedpaths.end(); ++i)
{
nonversionedstatepathsarray += *(i) + " ";
}
string commandsarray;
for (vector<string>::iterator i = checkoutcommands.begin(); i != checkoutcommands.end(); ++i)
{
//#HACK: I cant seem to find a way for bash to parse a 2 dimensional string array as argument, so we use a 1-d array with '|' as seperator
commandsarray += "" + *(i) + " | ";
}
//make the call
executeAndPrintShellCommand(nixLibexecDir + "/nix/nix-statecommit.sh " + svnbin +
" \"" + subversionedstatepathsarray + "\" " +
" \"" + subversionedpathsCommitBooleansarray + "\" " +
" \"" + nonversionedstatepathsarray + "\" " +
" \"" + commandsarray + "\" ",
"commit-script");
}
vector<int> intervals = store->getStatePathsInterval(intervalPaths);
int intervalAt=0;
for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){
DerivationStateOutputDir d = i->second;
string thisdir = d.path; //TODO CONVERT
string fullstatedir = statePath + "/" + thisdir;
if(thisdir == "/") //exception for the root dir
fullstatedir = statePath + "/";
//Path fullStatePath = fullstatedir; //TODO call coerce function //TODO REMOVE?
if(d.type == "none"){
nonversionedpaths.push_back(fullstatedir);
continue;
}
//Get the a repository for this state location
string repos = makeStateReposPath("stateOutput:staterepospath", statePath, thisdir, drvName, stateIdentifier); //this is a copy from store-state.cc
//
checkoutcommands.push_back(svnbin + " --ignore-externals checkout file://" + repos + " " + fullstatedir);
subversionedpaths.push_back(fullstatedir);
if(d.type == "interval"){
//Get the interval-counter from the database
int interval_counter = intervals[intervalAt];
int interval = d.getInterval();
subversionedpathsCommitBoolean.push_back(interval_counter % interval == 0);
//update the interval
intervals[intervalAt] = interval_counter + 1;
intervalAt++;
}
else if(d.type == "full")
subversionedpathsCommitBoolean.push_back(true);
else if(d.type == "manual") //TODO !!!!!
subversionedpathsCommitBoolean.push_back(false);
else
throw Error(format("interval '%1%' is not handled in nix-state") % d.type);
}
//Update the intervals again
//store->setStatePathsInterval(intervalPaths, intervals);
//Call the commit script with the appropiate paramenters
string subversionedstatepathsarray;
for (vector<string>::iterator i = subversionedpaths.begin(); i != subversionedpaths.end(); ++i)
{
subversionedstatepathsarray += *(i) + " ";
}
string subversionedpathsCommitBooleansarray;
for (vector<bool>::iterator i = subversionedpathsCommitBoolean.begin(); i != subversionedpathsCommitBoolean.end(); ++i)
{
subversionedpathsCommitBooleansarray += bool2string(*i) + " ";
}
string nonversionedstatepathsarray;
for (vector<string>::iterator i = nonversionedpaths.begin(); i != nonversionedpaths.end(); ++i)
{
nonversionedstatepathsarray += *(i) + " ";
}
string commandsarray;
for (vector<string>::iterator i = checkoutcommands.begin(); i != checkoutcommands.end(); ++i)
{
//#HACK: I cant seem to find a way for bash to parse a 2 dimensional string array as argument, so we use a 1-d array with '|' as seperator
commandsarray += "" + *(i) + " | ";
}
//make the call
executeAndPrintShellCommand(nixLibexecDir + "/nix/nix-statecommit.sh " + svnbin +
" \"" + subversionedstatepathsarray + "\" " +
" \"" + subversionedpathsCommitBooleansarray + "\" " +
" \"" + nonversionedstatepathsarray + "\" " +
" \"" + commandsarray + "\" ",
"commit-script");
}
@ -337,6 +330,7 @@ void run(Strings args)
{
Strings opFlags, opArgs;
Operation op = 0;
/* test *
store = openStore();
@ -363,10 +357,18 @@ void run(Strings args)
printMsg(lvlError, format("1: %1%") % bool2string( store->isStateComponent("/nix/store/7xkw5fkz5yw7dpx0pc6l12bh9a56135c-hellostateworld-1.0") ) );
printMsg(lvlError, format("2: %1%") % bool2string( store->isStateComponent("/nix/store/05441jm8xmsidqm43ivk0micckf0mr2m-nvidiaDrivers") ) );
printMsg(lvlError, format("3: %1%") % bool2string( store->isStateDrvPath("/nix/store/2hpx60ibdfv2pslg4rjvp177frijamvi-hellostateworld-1.0.drv") ) );
store = openStore();
convertStatePathsToDerivations(noTxn, "");
return;
store = openStore();
Path p = store->queryStatePathDrv("/nix/state/6g6kfgimz8szznlshf13s29fn01zp99d-hellohardcodedstateworld-1.0-test2");
printMsg(lvlError, format("Result: %1%") % p);
return;
*/
/* test */
for (Strings::iterator i = args.begin(); i != args.end(); ) {
@ -374,7 +376,7 @@ void run(Strings args)
Operation oldOp = op;
if (arg == "--run" || arg == "-r")
if (arg == "--commit" || arg == "-c")
op = opRunComponent;
else if (arg == "--showstatepath")
op = opShowStatePath;
@ -400,22 +402,23 @@ void run(Strings args)
--delete state?
--user=...
--show-state-references- -rev = ...
--show-state-references-current //in nix-store
--show-state-referrers- -rev = ...
--show-state-referrers-current //in nix-store
*/
else if (arg.substr(0,13) == "--identifier=")
stateIdentifier = arg.substr(13,arg.length());
else if (arg.substr(0,7) == "--user=")
username = arg.substr(7,arg.length());
else
opArgs.push_back(arg);
if (oldOp && oldOp != op)
throw UsageError("only one operation may be specified");
}
if(username == "")
username = getCallingUserName();
printMsg(lvlError, format("%1% - %2%") % stateIdentifier % username);
if (!op) throw UsageError("no operation specified");

View file

@ -30,8 +30,9 @@ Operations:
Query flags:
--outputs: query the output paths of a Nix derivation (default)
--requisites / -R: print all paths necessary to realise a path
--requisites-withstate: same as --requisites but now also including state paths
--requisites / -R: print all component paths necessary to realise a path
--requisites-state: same as --requisites but now only printing state paths
--requisites-full: same as --requisites but now also including state paths
--references: print all paths referenced by the given path
--references-state: print all state paths referenced by the given path
--referrers: print all paths directly refering to the given path

View file

@ -222,7 +222,7 @@ static void printTree(const Path & path,
/* Perform various sorts of queries. */
static void opQuery(Strings opFlags, Strings opArgs)
{
enum { qOutputs, qRequisites, qRequisitesWithState, qReferences, qStateReferences, qReferrers, qStateReferrers
enum { qOutputs, qRequisites, qRequisitesState, qRequisitesFull, qReferences, qStateReferences, qReferrers, qStateReferrers
, qReferrersClosure, qReferrersClosureWithState, qDeriver, qBinding, qHash
, qTree, qGraph, qResolve } query = qOutputs;
bool useOutput = false;
@ -234,7 +234,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
i != opFlags.end(); ++i)
if (*i == "--outputs") query = qOutputs;
else if (*i == "--requisites" || *i == "-R") query = qRequisites;
else if (*i == "--requisites-withstate") query = qRequisitesWithState;
else if (*i == "--requisites-state") query = qRequisitesState;
else if (*i == "--requisites-full") query = qRequisitesFull;
else if (*i == "--references") query = qReferences;
else if (*i == "--references-state") query = qStateReferences;
else if (*i == "--referrers" || *i == "--referers") query = qReferrers;
@ -273,7 +274,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
}
case qRequisites:
case qRequisitesWithState:
case qRequisitesState:
case qRequisitesFull:
case qReferences:
case qStateReferences:
case qReferrers:
@ -286,7 +288,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
{
Path path = maybeUseOutput(fixPath(*i), useOutput, forceRealise);
if (query == qRequisites) store->storePathRequisites(path, includeOutputs, paths, false);
else if (query == qRequisitesWithState) store->storePathRequisites(path, includeOutputs, paths, true);
else if (query == qRequisitesState) store->storePathStateRequisitesOnly(path, includeOutputs, paths);
else if (query == qRequisitesFull) store->storePathRequisites(path, includeOutputs, paths, true);
else if (query == qReferences) store->queryReferences(path, paths);
else if (query == qStateReferences) store->queryStateReferences(path, paths);
else if (query == qReferrers) store->queryReferrers(path, paths);

View file

@ -280,6 +280,15 @@ static void performOp(Source & from, Sink & to, unsigned int op)
writeString(printHash(hash), to);
break;
}
case wopQueryStatePathDrv: {
Path path = readStorePath(from); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! needs to be the state path
startWork();
Path p = store->queryStatePathDrv(path);
stopWork();
writeString(p, to);
break;
}
case wopQueryReferences:
case wopQueryReferrers: {
@ -303,7 +312,7 @@ static void performOp(Source & from, Sink & to, unsigned int op)
if (op == wopQueryStateReferences)
store->queryStateReferences(path, paths);
else
store->queryStateReferrers(path, paths); //TODO Does this work???
store->queryStateReferrers(path, paths); //TODO Does this work???, how about the state path?????????
stopWork();
writeStringSet(paths, to);
break;