* Changes to the command line syntax of Nix.

* A function to find all Nix expressions whose output ids are
  completely contained in some set.  Useful for uploading relevant Nix
  expressions to a shared cache.
This commit is contained in:
Eelco Dolstra 2003-07-21 14:46:01 +00:00
parent 401452e57a
commit 49231fbe41
5 changed files with 115 additions and 76 deletions

View File

@ -9,9 +9,7 @@
typedef void (* Operation) (Strings opFlags, Strings opArgs); typedef void (* Operation) (Strings opFlags, Strings opArgs);
typedef enum { atpHash, atpPath, atpUnknown } ArgType; static bool pathArgs = false;
static ArgType argType = atpUnknown;
/* Nix syntax: /* Nix syntax:
@ -39,12 +37,11 @@ static ArgType argType = atpUnknown;
Source selection for --install, --dump: Source selection for --install, --dump:
--file / -f: by file name !!! -> path --path / -p: by file name !!! -> path
--hash / -h: by hash (identifier)
Query flags: Query flags:
--path / -p: query the path of an fstate --list / -l: query the output paths (roots) of an fstate
--refs / -r: query paths referenced by an fstate --refs / -r: query paths referenced by an fstate
Options: Options:
@ -53,39 +50,16 @@ static ArgType argType = atpUnknown;
*/ */
/* Parse the `-f' / `-h' / flags, i.e., the type of arguments. These
flags are deleted from the referenced vector. */
static void getArgType(Strings & flags)
{
for (Strings::iterator it = flags.begin();
it != flags.end(); )
{
string arg = *it;
ArgType tp;
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");
argType = tp;
it = flags.erase(it);
}
if (argType == atpUnknown)
throw UsageError("argument type not specified");
}
static FSId argToId(const string & arg) static FSId argToId(const string & arg)
{ {
if (argType == atpHash) if (!pathArgs)
return parseHash(arg); return parseHash(arg);
else if (argType == atpPath) { else {
string path;
FSId id; FSId id;
addToStore(arg, path, id); if (!queryPathId(arg, id))
throw Error(format("don't know id of `%1%'") % arg);
return id; return id;
} }
else abort();
} }
@ -93,7 +67,6 @@ static FSId argToId(const string & arg)
expressions. */ expressions. */
static void opInstall(Strings opFlags, Strings opArgs) static void opInstall(Strings opFlags, Strings opArgs)
{ {
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
for (Strings::iterator it = opArgs.begin(); for (Strings::iterator it = opArgs.begin();
@ -117,7 +90,6 @@ static void opDelete(Strings opFlags, Strings opArgs)
paths. */ paths. */
static void opAdd(Strings opFlags, Strings opArgs) static void opAdd(Strings opFlags, Strings opArgs)
{ {
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
for (Strings::iterator it = opArgs.begin(); for (Strings::iterator it = opArgs.begin();
@ -134,47 +106,61 @@ static void opAdd(Strings opFlags, Strings opArgs)
/* Perform various sorts of queries. */ /* Perform various sorts of queries. */
static void opQuery(Strings opFlags, Strings opArgs) static void opQuery(Strings opFlags, Strings opArgs)
{ {
enum { qPath, qRefs, qUnknown } query = qPath; enum { qPaths, qRefs, qGenerators, qUnknown } query = qPaths;
for (Strings::iterator it = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
it != opFlags.end(); ) i != opFlags.end(); i++)
{ if (*i == "--list" || *i == "-l") query = qPaths;
string arg = *it; else if (*i == "--refs" || *i == "-r") query = qRefs;
if (arg == "--path" || arg == "-p") query = qPath; else if (*i == "--generators" || *i == "-g") query = qGenerators;
else if (arg == "--refs" || arg == "-r") query = qRefs; else throw UsageError(format("unknown flag `%1%'") % *i);
else { it++; continue; }
it = opFlags.erase(it);
}
getArgType(opFlags); switch (query) {
if (!opFlags.empty()) throw UsageError("unknown flag");
case qPaths: {
for (Strings::iterator it = opArgs.begin(); StringSet paths;
it != opArgs.end(); it++) for (Strings::iterator i = opArgs.begin();
{ i != opArgs.end(); i++)
FSId id = argToId(*it); {
Strings paths2 = fstatePaths(argToId(*i), true);
switch (query) { paths.insert(paths2.begin(), paths2.end());
}
case qPath: { for (StringSet::iterator i = paths.begin();
Strings paths = fstatePaths(id, true); i != paths.end(); i++)
for (Strings::iterator j = paths.begin(); cout << format("%s\n") % *i;
j != paths.end(); j++)
cout << format("%s\n") % *j;
break; break;
} }
case qRefs: { case qRefs: {
StringSet refs = fstateRefs(id); StringSet paths;
for (StringSet::iterator j = refs.begin(); for (Strings::iterator i = opArgs.begin();
j != refs.end(); j++) i != opArgs.end(); i++)
cout << format("%s\n") % *j; {
Strings paths2 = fstateRefs(argToId(*i));
paths.insert(paths2.begin(), paths2.end());
}
for (StringSet::iterator i = paths.begin();
i != paths.end(); i++)
cout << format("%s\n") % *i;
break;
}
case qGenerators: {
FSIds outIds;
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); i++)
outIds.push_back(argToId(*i));
FSIds genIds = findGenerators(outIds);
for (FSIds::iterator i = genIds.begin();
i != genIds.end(); i++)
cout << format("%s\n") % (string) *i;
break; break;
} }
default: default:
abort(); abort();
}
} }
} }
@ -224,16 +210,12 @@ struct StdoutSink : DumpSink
output. */ output. */
static void opDump(Strings opFlags, Strings opArgs) static void opDump(Strings opFlags, Strings opArgs)
{ {
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
if (opArgs.size() != 1) throw UsageError("only one argument allowed"); if (opArgs.size() != 1) throw UsageError("only one argument allowed");
StdoutSink sink; StdoutSink sink;
string arg = *opArgs.begin(); string arg = *opArgs.begin();
string path; string path = pathArgs ? arg : expandId(parseHash(arg));
if (argType == atpHash) path = expandId(parseHash(arg));
else if (argType == atpPath) path = arg;
dumpPath(path, sink); dumpPath(path, sink);
} }
@ -313,6 +295,8 @@ void run(Strings args)
op = opInit; op = opInit;
else if (arg == "--verify") else if (arg == "--verify")
op = opVerify; op = opVerify;
else if (arg == "--path" || arg == "-p")
pathArgs = true;
else if (arg[0] == '-') else if (arg[0] == '-')
opFlags.push_back(arg); opFlags.push_back(arg);
else else

View File

@ -248,18 +248,57 @@ Strings fstatePaths(const FSId & id, bool normalise)
} }
StringSet fstateRefs(const FSId & id) Strings fstateRefs(const FSId & id)
{ {
StringSet paths; Strings paths;
Slice slice = normaliseFState(id); Slice slice = normaliseFState(id);
for (SliceElems::const_iterator i = slice.elems.begin(); for (SliceElems::const_iterator i = slice.elems.begin();
i != slice.elems.end(); i++) i != slice.elems.end(); i++)
paths.insert(i->path); paths.push_back(i->path);
return paths; return paths;
} }
void findGenerators(const FSIds & ids) FSIds findGenerators(const FSIds & _ids)
{ {
FSIdSet ids(_ids.begin(), _ids.end());
FSIds generators;
/* !!! hack; for performance, we just look at the rhs of successor
mappings, since we know that those are Nix expressions. */
Strings sucs;
enumDB(nixDB, dbSuccessors, sucs);
for (Strings::iterator i = sucs.begin();
i != sucs.end(); i++)
{
string s;
queryDB(nixDB, dbSuccessors, *i, s);
FSId id = parseHash(s);
FState fs;
try {
/* !!! should substitutes be used? */
fs = parseFState(termFromId(id));
} catch (...) { /* !!! only catch parse errors */
continue;
}
if (fs.type != FState::fsSlice) continue;
bool okay = true;
for (SliceElems::const_iterator i = fs.slice.elems.begin();
i != fs.slice.elems.end(); i++)
if (ids.find(i->id) == ids.end()) {
okay = false;
break;
}
if (!okay) continue;
generators.push_back(id);
}
return generators;
} }

View File

@ -16,7 +16,11 @@ void realiseSlice(const Slice & slice);
Strings fstatePaths(const FSId & id, bool normalise); Strings fstatePaths(const FSId & id, bool normalise);
/* Get the list of paths referenced by the given fstate-expression. */ /* Get the list of paths referenced by the given fstate-expression. */
StringSet fstateRefs(const FSId & id); Strings fstateRefs(const FSId & id);
/* Return the list of the ids of all known fstate-expressions whose
output ids are completely contained in `ids'. */
FSIds findGenerators(const FSIds & ids);
/* Register a successor. */ /* Register a successor. */
void registerSuccessor(const FSId & id1, const FSId & id2); void registerSuccessor(const FSId & id1, const FSId & id2);

View File

@ -148,6 +148,15 @@ void unregisterPath(const string & _path)
} }
bool queryPathId(const string & path, FSId & id)
{
string s;
if (!queryDB(nixDB, dbPath2Id, path, s)) return false;
id = parseHash(s);
return true;
}
bool isInPrefix(const string & path, const string & _prefix) bool isInPrefix(const string & path, const string & _prefix)
{ {
string prefix = canonPath(_prefix + "/"); string prefix = canonPath(_prefix + "/");

View File

@ -20,6 +20,9 @@ void registerSubstitute(const FSId & srcId, const FSId & subId);
/* Register a path keyed on its id. */ /* Register a path keyed on its id. */
void registerPath(const string & path, const FSId & id); void registerPath(const string & path, const FSId & id);
/* Query the id of a path. */
bool queryPathId(const string & path, FSId & id);
/* Return a path whose contents have the given hash. If target is /* Return a path whose contents have the given hash. If target is
not empty, ensure that such a path is realised in target (if not empty, ensure that such a path is realised in target (if
necessary by copying from another location). If prefix is not necessary by copying from another location). If prefix is not