* 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:
parent
401452e57a
commit
49231fbe41
120
src/nix.cc
120
src/nix.cc
|
@ -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,48 +106,62 @@ 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);
|
|
||||||
if (!opFlags.empty()) throw UsageError("unknown flag");
|
|
||||||
|
|
||||||
for (Strings::iterator it = opArgs.begin();
|
|
||||||
it != opArgs.end(); it++)
|
|
||||||
{
|
|
||||||
FSId id = argToId(*it);
|
|
||||||
|
|
||||||
switch (query) {
|
switch (query) {
|
||||||
|
|
||||||
case qPath: {
|
case qPaths: {
|
||||||
Strings paths = fstatePaths(id, true);
|
StringSet paths;
|
||||||
for (Strings::iterator j = paths.begin();
|
for (Strings::iterator i = opArgs.begin();
|
||||||
j != paths.end(); j++)
|
i != opArgs.end(); i++)
|
||||||
cout << format("%s\n") % *j;
|
{
|
||||||
|
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;
|
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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 + "/");
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue