* 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 enum { atpHash, atpPath, atpUnknown } ArgType;
static ArgType argType = atpUnknown;
static bool pathArgs = false;
/* Nix syntax:
@ -39,12 +37,11 @@ static ArgType argType = atpUnknown;
Source selection for --install, --dump:
--file / -f: by file name !!! -> path
--hash / -h: by hash (identifier)
--path / -p: by file name !!! -> path
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
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)
{
if (argType == atpHash)
if (!pathArgs)
return parseHash(arg);
else if (argType == atpPath) {
string path;
else {
FSId id;
addToStore(arg, path, id);
if (!queryPathId(arg, id))
throw Error(format("don't know id of `%1%'") % arg);
return id;
}
else abort();
}
@ -93,7 +67,6 @@ static FSId argToId(const string & arg)
expressions. */
static void opInstall(Strings opFlags, Strings opArgs)
{
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag");
for (Strings::iterator it = opArgs.begin();
@ -117,7 +90,6 @@ static void opDelete(Strings opFlags, Strings opArgs)
paths. */
static void opAdd(Strings opFlags, Strings opArgs)
{
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag");
for (Strings::iterator it = opArgs.begin();
@ -134,48 +106,62 @@ 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;
enum { qPaths, qRefs, qGenerators, qUnknown } query = qPaths;
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++)
{
FSId id = argToId(*it);
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); i++)
if (*i == "--list" || *i == "-l") query = qPaths;
else if (*i == "--refs" || *i == "-r") query = qRefs;
else if (*i == "--generators" || *i == "-g") query = qGenerators;
else throw UsageError(format("unknown flag `%1%'") % *i);
switch (query) {
case qPath: {
Strings paths = fstatePaths(id, true);
for (Strings::iterator j = paths.begin();
j != paths.end(); j++)
cout << format("%s\n") % *j;
case qPaths: {
StringSet paths;
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); i++)
{
Strings paths2 = fstatePaths(argToId(*i), true);
paths.insert(paths2.begin(), paths2.end());
}
for (StringSet::iterator i = paths.begin();
i != paths.end(); i++)
cout << format("%s\n") % *i;
break;
}
case qRefs: {
StringSet refs = fstateRefs(id);
for (StringSet::iterator j = refs.begin();
j != refs.end(); j++)
cout << format("%s\n") % *j;
StringSet paths;
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); i++)
{
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;
}
default:
abort();
}
}
}
@ -224,16 +210,12 @@ struct StdoutSink : DumpSink
output. */
static void opDump(Strings opFlags, Strings opArgs)
{
getArgType(opFlags);
if (!opFlags.empty()) throw UsageError("unknown flag");
if (opArgs.size() != 1) throw UsageError("only one argument allowed");
StdoutSink sink;
string arg = *opArgs.begin();
string path;
if (argType == atpHash) path = expandId(parseHash(arg));
else if (argType == atpPath) path = arg;
string path = pathArgs ? arg : expandId(parseHash(arg));
dumpPath(path, sink);
}
@ -313,6 +295,8 @@ void run(Strings args)
op = opInit;
else if (arg == "--verify")
op = opVerify;
else if (arg == "--path" || arg == "-p")
pathArgs = true;
else if (arg[0] == '-')
opFlags.push_back(arg);
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);
for (SliceElems::const_iterator i = slice.elems.begin();
i != slice.elems.end(); i++)
paths.insert(i->path);
paths.push_back(i->path);
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);
/* 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. */
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)
{
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. */
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
not empty, ensure that such a path is realised in target (if
necessary by copying from another location). If prefix is not