* A command to query the paths referenced by an fstate expression.
* Use a temporary directory for build actions.
This commit is contained in:
parent
a279137327
commit
40274c1f4f
6 changed files with 198 additions and 97 deletions
30
src/fix.cc
30
src/fix.cc
|
@ -13,29 +13,6 @@ typedef ATerm Expr;
|
|||
static Expr evalFile(string fileName);
|
||||
|
||||
|
||||
static bool isFState(Expr e, string & path)
|
||||
{
|
||||
char * s1, * s2, * s3;
|
||||
Expr e1, e2;
|
||||
if (ATmatch(e, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2)) {
|
||||
path = s1;
|
||||
return true;
|
||||
}
|
||||
else if (ATmatch(e, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
|
||||
&s1, &s2, &e1, &s3, &e2))
|
||||
{
|
||||
path = s3;
|
||||
return true;
|
||||
}
|
||||
else if (ATmatch(e, "Include(<str>)", &s1))
|
||||
{
|
||||
string fn = queryPathByHash(parseHash(s1));
|
||||
return isFState(evalFile(fn), path);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
static Expr substExpr(string x, Expr rep, Expr e)
|
||||
{
|
||||
char * s;
|
||||
|
@ -113,8 +90,7 @@ static Expr evalExpr(Expr e)
|
|||
ATmatch(e, "Function([<list>], <term>)", &e1, &e2))
|
||||
return e;
|
||||
|
||||
string dummy;
|
||||
if (isFState(e, dummy)) return e;
|
||||
if (fstatePath(e) != "") return e; /* !!! hack */
|
||||
|
||||
/* Application. */
|
||||
if (ATmatch(e, "App(<term>, [<list>])", &e1, &e2)) {
|
||||
|
@ -165,8 +141,8 @@ static Expr evalExpr(Expr e)
|
|||
string key = it->first;
|
||||
ATerm value = it->second;
|
||||
|
||||
string path;
|
||||
if (isFState(value, path)) {
|
||||
string path = fstatePath(value);
|
||||
if (path != "") {
|
||||
ins = ATinsert(ins, value);
|
||||
env = ATinsert(env, ATmake("(<str>, <str>)",
|
||||
key.c_str(), path.c_str()));
|
||||
|
|
146
src/fstate.cc
146
src/fstate.cc
|
@ -1,4 +1,5 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -17,18 +18,21 @@
|
|||
typedef map<string, string> Environment;
|
||||
|
||||
|
||||
/* Return true iff the given path exists. */
|
||||
bool pathExists(const string & path)
|
||||
class AutoDelete
|
||||
{
|
||||
string path;
|
||||
public:
|
||||
|
||||
AutoDelete(const string & p) : path(p)
|
||||
{
|
||||
int res;
|
||||
struct stat st;
|
||||
res = stat(path.c_str(), &st);
|
||||
if (!res) return true;
|
||||
if (errno != ENOENT)
|
||||
throw SysError(format("getting status of %1%") % path);
|
||||
return false;
|
||||
}
|
||||
|
||||
~AutoDelete()
|
||||
{
|
||||
deletePath(path);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Run a program. */
|
||||
static void runProgram(const string & program, Environment env)
|
||||
|
@ -36,9 +40,19 @@ static void runProgram(const string & program, Environment env)
|
|||
/* Create a log file. */
|
||||
string logFileName = nixLogDir + "/run.log";
|
||||
/* !!! auto-pclose on exit */
|
||||
FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
|
||||
FILE * logFile = popen(("tee -a " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
|
||||
if (!logFile)
|
||||
throw SysError(format("unable to create log file %1%") % logFileName);
|
||||
throw SysError(format("creating log file `%1%'") % logFileName);
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
static int counter = 0;
|
||||
string tmpDir = (format("/tmp/nix-%1%-%2%") % getpid() % counter++).str();
|
||||
|
||||
if (mkdir(tmpDir.c_str(), 0777) == -1)
|
||||
throw SysError(format("creating directory `%1%'") % tmpDir);
|
||||
|
||||
AutoDelete delTmpDir(tmpDir);
|
||||
|
||||
/* Fork a child to build the package. */
|
||||
pid_t pid;
|
||||
|
@ -51,31 +65,8 @@ static void runProgram(const string & program, Environment env)
|
|||
|
||||
try { /* child */
|
||||
|
||||
#if 0
|
||||
/* Try to use a prebuilt. */
|
||||
string prebuiltHashS, prebuiltFile;
|
||||
if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHashS)) {
|
||||
|
||||
try {
|
||||
prebuiltFile = getFile(parseHash(prebuiltHashS));
|
||||
} catch (Error e) {
|
||||
cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
|
||||
goto build;
|
||||
}
|
||||
|
||||
cerr << "substituting prebuilt " << prebuiltFile << endl;
|
||||
|
||||
int res = system(("tar xfj " + prebuiltFile + " 1>&2").c_str()); // !!! escaping
|
||||
if (WEXITSTATUS(res) != 0)
|
||||
/* This is a fatal error, because path may now
|
||||
have clobbered. */
|
||||
throw Error("cannot unpack " + prebuiltFile);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// build:
|
||||
if (chdir(tmpDir.c_str()) == -1)
|
||||
throw SysError(format("changing into to `%1%'") % tmpDir);
|
||||
|
||||
/* Fill in the environment. We don't bother freeing
|
||||
the strings, since we'll exec or die soon
|
||||
|
@ -157,15 +148,7 @@ Hash hashTerm(ATerm t)
|
|||
}
|
||||
|
||||
|
||||
struct RStatus
|
||||
{
|
||||
/* !!! the comparator of this hash should match the semantics of
|
||||
the file system */
|
||||
// map<string, Hash> paths;
|
||||
};
|
||||
|
||||
|
||||
static ATerm termFromHash(const Hash & hash)
|
||||
ATerm termFromHash(const Hash & hash)
|
||||
{
|
||||
string path = queryPathByHash(hash);
|
||||
ATerm t = ATreadFromNamedFile(path.c_str());
|
||||
|
@ -188,7 +171,7 @@ Hash writeTerm(ATerm t)
|
|||
}
|
||||
|
||||
|
||||
static FState realise(RStatus & status, FState fs)
|
||||
static FState realise(FState fs)
|
||||
{
|
||||
char * s1, * s2, * s3;
|
||||
Content content;
|
||||
|
@ -212,7 +195,7 @@ static FState realise(RStatus & status, FState fs)
|
|||
/* Fall through. */
|
||||
|
||||
if (ATmatch(fs, "Include(<str>)", &s1)) {
|
||||
return realise(status, termFromHash(parseHash(s1)));
|
||||
return realise(termFromHash(parseHash(s1)));
|
||||
}
|
||||
|
||||
else if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &content, &refs)) {
|
||||
|
@ -227,7 +210,7 @@ static FState realise(RStatus & status, FState fs)
|
|||
/* Realise referenced paths. */
|
||||
ATermList refs2 = ATempty;
|
||||
while (!ATisEmpty(refs)) {
|
||||
refs2 = ATinsert(refs2, realise(status, ATgetFirst(refs)));
|
||||
refs2 = ATinsert(refs2, realise(ATgetFirst(refs)));
|
||||
refs = ATgetNext(refs);
|
||||
}
|
||||
refs2 = ATreverse(refs2);
|
||||
|
@ -278,7 +261,7 @@ static FState realise(RStatus & status, FState fs)
|
|||
/* Realise inputs. */
|
||||
ATermList ins2 = ATempty;
|
||||
while (!ATisEmpty(ins)) {
|
||||
ins2 = ATinsert(ins2, realise(status, ATgetFirst(ins)));
|
||||
ins2 = ATinsert(ins2, realise(ATgetFirst(ins)));
|
||||
ins = ATgetNext(ins);
|
||||
}
|
||||
ins2 = ATreverse(ins2);
|
||||
|
@ -335,6 +318,67 @@ static FState realise(RStatus & status, FState fs)
|
|||
|
||||
FState realiseFState(FState fs)
|
||||
{
|
||||
RStatus status;
|
||||
return realise(status, fs);
|
||||
return realise(fs);
|
||||
}
|
||||
|
||||
|
||||
string fstatePath(FState fs)
|
||||
{
|
||||
char * s1, * s2, * s3;
|
||||
FState e1, e2;
|
||||
if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2))
|
||||
return s1;
|
||||
else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
|
||||
&s1, &s2, &e1, &s3, &e2))
|
||||
return s3;
|
||||
else if (ATmatch(fs, "Include(<str>)", &s1))
|
||||
return fstatePath(termFromHash(parseHash(s1)));
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
typedef set<string> StringSet;
|
||||
|
||||
|
||||
void fstateRefs2(FState fs, StringSet & paths)
|
||||
{
|
||||
char * s1, * s2, * s3;
|
||||
FState e1, e2;
|
||||
ATermList refs, ins;
|
||||
|
||||
if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &refs)) {
|
||||
paths.insert(s1);
|
||||
|
||||
while (!ATisEmpty(refs)) {
|
||||
fstateRefs2(ATgetFirst(refs), paths);
|
||||
refs = ATgetNext(refs);
|
||||
}
|
||||
}
|
||||
|
||||
else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
|
||||
&s1, &s2, &ins, &s3, &e2))
|
||||
{
|
||||
paths.insert(s3);
|
||||
|
||||
while (!ATisEmpty(ins)) {
|
||||
fstateRefs2(ATgetFirst(ins), paths);
|
||||
ins = ATgetNext(ins);
|
||||
}
|
||||
}
|
||||
|
||||
else if (ATmatch(fs, "Include(<str>)", &s1))
|
||||
fstateRefs2(termFromHash(parseHash(s1)), paths);
|
||||
|
||||
else throw badTerm("bad fstate expression", fs);
|
||||
}
|
||||
|
||||
|
||||
Strings fstateRefs(FState fs)
|
||||
{
|
||||
StringSet paths;
|
||||
fstateRefs2(fs, paths);
|
||||
Strings paths2(paths.size());
|
||||
copy(paths.begin(), paths.end(), paths2.begin());
|
||||
return paths2;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,17 @@ typedef ATerm FState;
|
|||
typedef ATerm Content;
|
||||
|
||||
|
||||
/* Realise a $f$-normalised expression in the file system. */
|
||||
/* Realise an fstate expression in the file system. This requires
|
||||
execution of all Derive() nodes. */
|
||||
FState realiseFState(FState fs);
|
||||
|
||||
/* Return the path of an fstate expression. An empty string is
|
||||
returned if the term is not a valid fstate expression. (!!!) */
|
||||
string fstatePath(FState fs);
|
||||
|
||||
/* Return the paths referenced by fstate expression. */
|
||||
Strings fstateRefs(FState fs);
|
||||
|
||||
/* Return a canonical textual representation of an expression. */
|
||||
string printTerm(ATerm t);
|
||||
|
||||
|
@ -73,6 +81,9 @@ Error badTerm(const format & f, ATerm t);
|
|||
/* Hash an aterm. */
|
||||
Hash hashTerm(ATerm t);
|
||||
|
||||
/* Read an aterm from disk, given its hash. */
|
||||
ATerm termFromHash(const Hash & hash);
|
||||
|
||||
/* Write an aterm to the Nix store directory, and return its hash. */
|
||||
Hash writeTerm(ATerm t);
|
||||
|
||||
|
|
90
src/nix.cc
90
src/nix.cc
|
@ -21,9 +21,10 @@ static ArgType argType = atpUnknown;
|
|||
|
||||
Operations:
|
||||
|
||||
--install / -i: realise a Nix expression
|
||||
--install / -i: realise an fstate
|
||||
--delete / -d: delete paths from the Nix store
|
||||
--add / -A: copy a path to the Nix store
|
||||
--query / -q: query information
|
||||
|
||||
--dump: dump a path as a Nix archive
|
||||
--restore: restore a path from a Nix archive
|
||||
|
@ -39,6 +40,11 @@ static ArgType argType = atpUnknown;
|
|||
--file / -f: by file name
|
||||
--hash / -h: by hash
|
||||
|
||||
Query flags:
|
||||
|
||||
--path / -p: query the path of an fstate
|
||||
--refs / -r: query paths referenced by an fstate
|
||||
|
||||
Options:
|
||||
|
||||
--verbose / -v: verbose operation
|
||||
|
@ -54,10 +60,8 @@ static void getArgType(Strings & flags)
|
|||
{
|
||||
string arg = *it;
|
||||
ArgType tp;
|
||||
if (arg == "--hash" || arg == "-h")
|
||||
tp = atpHash;
|
||||
else if (arg == "--file" || arg == "-f")
|
||||
tp = atpPath;
|
||||
if (arg == "--hash" || arg == "-h") tp = atpHash;
|
||||
else if (arg == "--file" || arg == "-f") tp = atpPath;
|
||||
else { it++; continue; }
|
||||
if (argType != atpUnknown)
|
||||
throw UsageError("only one argument type specified may be specified");
|
||||
|
@ -69,6 +73,20 @@ static void getArgType(Strings & flags)
|
|||
}
|
||||
|
||||
|
||||
static Hash argToHash(const string & arg)
|
||||
{
|
||||
if (argType == atpHash)
|
||||
return parseHash(arg);
|
||||
else if (argType == atpPath) {
|
||||
string path;
|
||||
Hash hash;
|
||||
addToStore(arg, path, hash);
|
||||
return hash;
|
||||
}
|
||||
else abort();
|
||||
}
|
||||
|
||||
|
||||
/* Realise (or install) paths from the given Nix fstate
|
||||
expressions. */
|
||||
static void opInstall(Strings opFlags, Strings opArgs)
|
||||
|
@ -78,20 +96,11 @@ static void opInstall(Strings opFlags, Strings opArgs)
|
|||
|
||||
for (Strings::iterator it = opArgs.begin();
|
||||
it != opArgs.end(); it++)
|
||||
{
|
||||
Hash hash;
|
||||
if (argType == atpHash)
|
||||
hash = parseHash(*it);
|
||||
else if (argType == atpPath) {
|
||||
string path;
|
||||
addToStore(*it, path, hash);
|
||||
}
|
||||
FState fs = ATmake("Include(<str>)", ((string) hash).c_str());
|
||||
realiseFState(fs);
|
||||
}
|
||||
realiseFState(termFromHash(argToHash(*it)));
|
||||
}
|
||||
|
||||
|
||||
/* Delete a path in the Nix store directory. */
|
||||
static void opDelete(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||
|
@ -120,6 +129,51 @@ static void opAdd(Strings opFlags, Strings opArgs)
|
|||
}
|
||||
|
||||
|
||||
/* Perform various sorts of queries. */
|
||||
static void opQuery(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
enum { qPath, qRefs, qUnknown } query = qPath;
|
||||
|
||||
for (Strings::iterator it = opFlags.begin();
|
||||
it != opFlags.end(); )
|
||||
{
|
||||
string arg = *it;
|
||||
if (arg == "--path" || arg == "-p") query = qPath;
|
||||
else if (arg == "--refs" || arg == "-r") query = qRefs;
|
||||
else { it++; continue; }
|
||||
it = opFlags.erase(it);
|
||||
}
|
||||
|
||||
getArgType(opFlags);
|
||||
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||
|
||||
for (Strings::iterator it = opArgs.begin();
|
||||
it != opArgs.end(); it++)
|
||||
{
|
||||
Hash hash = argToHash(*it);
|
||||
|
||||
switch (query) {
|
||||
|
||||
case qPath:
|
||||
cout << format("%s\n") %
|
||||
(string) fstatePath(termFromHash(hash));
|
||||
break;
|
||||
|
||||
case qRefs: {
|
||||
Strings refs = fstateRefs(termFromHash(hash));
|
||||
for (Strings::iterator j = refs.begin();
|
||||
j != refs.end(); j++)
|
||||
cout << format("%s\n") % *j;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* A sink that writes dump output to stdout. */
|
||||
struct StdoutSink : DumpSink
|
||||
{
|
||||
|
@ -208,8 +262,10 @@ void run(Strings args)
|
|||
op = opInstall;
|
||||
else if (arg == "--delete" || arg == "-d")
|
||||
op = opDelete;
|
||||
else if (arg == "--add")
|
||||
else if (arg == "--add" || arg == "-A")
|
||||
op = opAdd;
|
||||
else if (arg == "--query" || arg == "-q")
|
||||
op = opQuery;
|
||||
else if (arg == "--dump")
|
||||
op = opDump;
|
||||
else if (arg == "--restore")
|
||||
|
|
12
src/util.cc
12
src/util.cc
|
@ -66,6 +66,18 @@ string baseNameOf(string path)
|
|||
}
|
||||
|
||||
|
||||
bool pathExists(const string & path)
|
||||
{
|
||||
int res;
|
||||
struct stat st;
|
||||
res = stat(path.c_str(), &st);
|
||||
if (!res) return true;
|
||||
if (errno != ENOENT)
|
||||
throw SysError(format("getting status of %1%") % path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void deletePath(string path)
|
||||
{
|
||||
struct stat st;
|
||||
|
|
|
@ -60,6 +60,8 @@ string dirOf(string path);
|
|||
the final `/'. */
|
||||
string baseNameOf(string path);
|
||||
|
||||
/* Return true iff the given path exists. */
|
||||
bool pathExists(const string & path);
|
||||
|
||||
/* Delete a path; i.e., in the case of a directory, it is deleted
|
||||
recursively. Don't use this at home, kids. */
|
||||
|
|
Loading…
Reference in a new issue