From 49231fbe419d37717b0d951377fbfc9bf445dd55 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 21 Jul 2003 14:46:01 +0000 Subject: [PATCH] * 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. --- src/nix.cc | 124 +++++++++++++++++++++-------------------------- src/normalise.cc | 49 +++++++++++++++++-- src/normalise.hh | 6 ++- src/store.cc | 9 ++++ src/store.hh | 3 ++ 5 files changed, 115 insertions(+), 76 deletions(-) diff --git a/src/nix.cc b/src/nix.cc index ad4e6a468..de60c28c5 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -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,47 +106,61 @@ 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); - } + 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); - 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) { - - case qPath: { - Strings paths = fstatePaths(id, true); - for (Strings::iterator j = paths.begin(); - j != paths.end(); j++) - cout << format("%s\n") % *j; + switch (query) { + + 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 diff --git a/src/normalise.cc b/src/normalise.cc index bdeddf08d..fcb9c4d0d 100644 --- a/src/normalise.cc +++ b/src/normalise.cc @@ -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; } diff --git a/src/normalise.hh b/src/normalise.hh index 85dbca5ef..49f9e68ee 100644 --- a/src/normalise.hh +++ b/src/normalise.hh @@ -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); diff --git a/src/store.cc b/src/store.cc index 6f1a2fc39..6157b4bc2 100644 --- a/src/store.cc +++ b/src/store.cc @@ -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 + "/"); diff --git a/src/store.hh b/src/store.hh index 78d5529e7..faac76009 100644 --- a/src/store.hh +++ b/src/store.hh @@ -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