1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-26 12:10:59 +01:00
nix/src/nix-state/nix-state.cc
2007-06-13 16:18:42 +00:00

381 lines
12 KiB
C++

#include <iostream>
#include <algorithm>
#include "globals.hh"
#include "misc.hh"
#include "archive.hh"
#include "shared.hh"
#include "db.hh"
#include "util.hh"
#include "help.txt.hh"
#include "local-store.hh"
#include "derivations.hh"
using namespace nix;
using std::cin;
using std::cout;
typedef void (* Operation) (Strings opFlags, Strings opArgs);
/************************* Build time Functions ******************************/
/************************* Build time Functions ******************************/
void printHelp()
{
cout << string((char *) helpText, sizeof helpText);
}
//
Derivation getDerivation_andCheckArgs_(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath, string & stateIdentifier, string & binary, string & derivationPath,
bool getDerivers, PathSet & derivers, string & username) //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]) )");
//Parse the full path like /nix/store/...../bin/hello
string fullPath = opArgs.front();
componentPath = fullPath.substr(nixStore.size() + 1, fullPath.size()); //+1 to strip off the /
int pos = componentPath.find("/",0);
componentPath = fullPath.substr(0, pos + nixStore.size() + 1);
binary = fullPath.substr(pos + nixStore.size() + 1, fullPath.size());
//TODO REAL CHECK for validity of componentPath ... ?
if(componentPath == "/nix/store")
throw UsageError("You must specify the full! binary path");
if(opArgs.size() > 1){
opArgs.pop_front();
stateIdentifier = opArgs.front();
}
if(username == "")
username = getCallingUserName();
printMsg(lvlError, format("%1% - %2% - %3% - %4%") % componentPath % stateIdentifier % binary % username);
derivers = queryDerivers(noTxn, componentPath, stateIdentifier, username);
if(getDerivers == true)
return Derivation();
else if(derivers.size() != 1)
throw UsageError("There is more than one deriver....");
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;
return drv;
}
//Wrapper
Derivation getDerivation_andCheckArgs(Strings opFlags, Strings opArgs, Path & componentPath, Path & statePath, string & stateIdentifier, string & binary, string & derivationPath)
{
PathSet empty;
string empty2;
return getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, false, empty, empty2);
}
//
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;
Derivation drv = getDerivation_andCheckArgs_(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath, true, derivers, username);
for (PathSet::iterator i = derivers.begin(); i != derivers.end(); ++i)
printMsg(lvlError, format("%1%") % (*i));
}
//Prints the statepath of a component - indetiefier combination
static void opShowStatePath(Strings opFlags, Strings opArgs)
{
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath);
printMsg(lvlError, format("%1%") % statePath);
}
//Prints the root path that contains the repoisitorys of the state of a component - indetiefier combination
static void opShowStateReposRootPath(Strings opFlags, Strings opArgs)
{
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath;
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath);
string drvName = drv.env.find("name")->second;
//Get the a repository for this state location
string repos = makeStateReposPath("stateOutput:staterepospath", statePath, "/", drvName, stateIdentifier); //this is a copy from store-state.cc
//TODO Strip off
//repos = repos.substr(0, repos.length() - .... );
printMsg(lvlError, format("%1%") % repos);
}
static void opRunComponent(Strings opFlags, Strings opArgs)
{
//get the derivation of the current component
Path componentPath;
Path statePath;
string stateIdentifier;
string binary;
string derivationPath
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, stateIdentifier, binary, derivationPath);
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
DerivationStateOutputs stateOutputs = drv.stateOutputs;
DerivationOutputs outputs = drv.outputs;
string drvName = drv.env.find("name")->second;
//Check if component is a state component !!!
//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
PathSet paths = store->getStateReferencesClosure(derivationPath);
//TODO nix-store -q --tree $(nix-store -qd /nix/store/6x6glnb9idn53yxfqrz6wq53459vv3qd-firefox-2.0.0.3/)
//Transaction txn;
//createStoreTransaction(txn);
//txn.commit();
//or noTxn
//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;
//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 + "/";
//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");
}
void run(Strings args)
{
Strings opFlags, opArgs;
Operation op = 0;
/* test *
store = openStore();
Path p = "/nix/store/l569q3a2cfx834mcf3vhwczjgbaljnp7-hellohardcodedstateworld-1.0"; //
store->addUpdatedStateDerivation("/nix/store/63xcbrk3v5nbn9qla7rwnx6rvz3iqm5l-hellohardcodedstateworld-1.0.drv", p); //
Path p2 = "/nix/store/4ycq45hsgc8yaj4vwafx3lgd473jaqwg-hellohardcodedstateworld-1.0";
store->addUpdatedStateDerivation("/nix/store/s6wggk924jx0gcb0l29ra4g9fxa3b4pp-hellohardcodedstateworld-1.0.drv", p2); //
store->updateAllStateDerivations();
return;
string a = makeStatePathFromGolbalHash("8f3b56a9a985fce54fd88c3e95a81a4b6b11fb98da12b977aee7f278c73ad3d7-hellohardcodedstateworld-1.0-test2", "kaaz");
printMsg(lvlError, format("%1%") % a);
return;
printMsg(lvlError, format("Result: \"%1%\"") % getCallingUserName());
return;
*/
store = openStore();
//store->addUpdatedStateDerivation("/nix/store/bk4p7378ndm1p5qdr6a99wgxbiklilxy-hellohardcodedstateworld-1.0.drv", "/nix/store/vjijdazrn2jyzyk9sqwrl8fjq0qsmi8y-hellohardcodedstateworld-1.0");
//store->updateAllStateDerivations();
//return;
PathSet paths
storePathRequisites("", false, paths);
//PathSet paths = store->getStateReferencesClosure("/nix/store/928dd2wl5cgqg10hzc3aj4rqaips6bdk-hellohardcodedstateworld-dep1-1.0.drv");
return;
/* test */
for (Strings::iterator i = args.begin(); i != args.end(); ) {
string arg = *i++;
Operation oldOp = op;
if (arg == "--run" || arg == "-r")
op = opRunComponent;
else if (arg == "--showstatepath")
op = opShowStatePath;
else if (arg == "--showstatereposrootpath")
op = opShowStateReposRootPath;
else if (arg == "--showderivations")
op = opShowDerivations;
/*
--commit
--run-without-commit
--backup
--exclude-commit-paths
TODO update getDerivation in nix-store to handle state indentifiers
--update state drv
--revert-to-state (recursive revert...)
--delete state?
--user=...
*/
else
opArgs.push_back(arg);
if (oldOp && oldOp != op)
throw UsageError("only one operation may be specified");
}
if (!op) throw UsageError("no operation specified");
/* !!! hack */
store = openStore();
op(opFlags, opArgs);
}
string programId = "nix-state";