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. */
@ -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],
@ -1749,14 +1752,17 @@ void DerivationGoal::computeClosure()
* 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);
}

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

@ -49,6 +49,8 @@ public:
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);
void queryReferences(const Path & path, PathSet & references);
void queryStateReferences(const Path & storePath, PathSet & stateReferences);
@ -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);
};
@ -206,6 +210,8 @@ 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

@ -37,6 +37,8 @@ public:
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);
void queryReferences(const Path & path, PathSet & references);
void queryStateReferences(const Path & storePath, PathSet & stateReferences);
@ -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,
@ -213,6 +216,7 @@ public:
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

@ -40,6 +40,10 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
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
for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){
@ -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();
@ -57,24 +62,32 @@ 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();
allargs = opArgs.front();
Strings progam_args;
//TODO !!!!!!!!!!!!!!!!!!!!!!
}
if(username == "")
username = getCallingUserName();
printMsg(lvlError, format("'%1%' - '%2%' - '%3%' - '%4%' - '%5%'") % componentPath % stateIdentifier % binary % username % allargs);
//printMsg(lvlError, format("%1% - %2% - %3% - %4%") % componentPath % stateIdentifier % binary % username);
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].
@ -82,37 +95,33 @@ Derivation getDerivation_andCheckArgs_(Strings opFlags, Strings opArgs, Path & c
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);
}
//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 drvs ! (combo of component + state | component path)
//return single state paths
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);
//Check if component is a state component !!!
//Specifiy the SVN binarys
string svnbin = nixSVNPath + "/svn";
string svnadminbin = nixSVNPath + "/svnadmin";
//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 (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;
//for(...){
//
//}
//Print
printMsg(lvlError, format("Committing statePath: %1%") % statePath);
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;
//Vector includeing all commit scripts:
vector<string> subversionedpaths;
vector<bool> subversionedpathsCommitBoolean;
vector<string> nonversionedpaths; //of type none, no versioning needed
vector<string> checkoutcommands;
//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;
//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;
string thisdir = d.path;
string fullstatedir = statePath + "/" + thisdir;
if(d.type == "interval"){
intervalPaths.insert(fullstatedir);
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");
}
@ -338,6 +331,7 @@ void run(Strings args)
Strings opFlags, opArgs;
Operation op = 0;
/* test *
store = openStore();
Path p = "/nix/store/l569q3a2cfx834mcf3vhwczjgbaljnp7-hellohardcodedstateworld-1.0"; //
@ -363,6 +357,14 @@ 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;
*/
@ -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,15 +402,12 @@ 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);
@ -416,6 +415,10 @@ void run(Strings args)
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

@ -281,6 +281,15 @@ static void performOp(Source & from, Sink & to, unsigned int op)
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: {
Path path = readStorePath(from);
@ -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;