aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-08-05 16:07:29 +0200
committerGitHub <noreply@github.com>2020-08-05 16:07:29 +0200
commit75f220a59570e4de58914fa60b0deefe5d06058c (patch)
treeb8f163c4b1b7476a1c816b8d23585d88ccdab761 /src
parent088dcea0e80bf2861fd9d6b808e76a1669b7122a (diff)
parent8065c6d1606402e936b048aa75ad98ffdd7c8d60 (diff)
Merge pull request #3864 from obsidiansystems/more-topo-sort
Abstract out topo sorting logic
Diffstat (limited to 'src')
-rw-r--r--src/libstore/misc.cc51
-rw-r--r--src/libutil/topo-sort.hh40
2 files changed, 56 insertions, 35 deletions
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index 7f1b62f26..ddba5d052 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -4,6 +4,7 @@
#include "local-store.hh"
#include "store-api.hh"
#include "thread-pool.hh"
+#include "topo-sort.hh"
namespace nix {
@@ -256,41 +257,21 @@ void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
StorePaths Store::topoSortPaths(const StorePathSet & paths)
{
- StorePaths sorted;
- StorePathSet visited, parents;
-
- std::function<void(const StorePath & path, const StorePath * parent)> dfsVisit;
-
- dfsVisit = [&](const StorePath & path, const StorePath * parent) {
- if (parents.count(path))
- throw BuildError("cycle detected in the references of '%s' from '%s'",
- printStorePath(path), printStorePath(*parent));
-
- if (!visited.insert(path).second) return;
- parents.insert(path);
-
- StorePathSet references;
- try {
- references = queryPathInfo(path)->references;
- } catch (InvalidPath &) {
- }
-
- for (auto & i : references)
- /* Don't traverse into paths that don't exist. That can
- happen due to substitutes for non-existent paths. */
- if (i != path && paths.count(i))
- dfsVisit(i, &path);
-
- sorted.push_back(path);
- parents.erase(path);
- };
-
- for (auto & i : paths)
- dfsVisit(i, nullptr);
-
- std::reverse(sorted.begin(), sorted.end());
-
- return sorted;
+ return topoSort(paths,
+ {[&](const StorePath & path) {
+ StorePathSet references;
+ try {
+ references = queryPathInfo(path)->references;
+ } catch (InvalidPath &) {
+ }
+ return references;
+ }},
+ {[&](const StorePath & path, const StorePath & parent) {
+ return BuildError(
+ "cycle detected in the references of '%s' from '%s'",
+ printStorePath(path),
+ printStorePath(parent));
+ }});
}
diff --git a/src/libutil/topo-sort.hh b/src/libutil/topo-sort.hh
new file mode 100644
index 000000000..7a68ff169
--- /dev/null
+++ b/src/libutil/topo-sort.hh
@@ -0,0 +1,40 @@
+#include "error.hh"
+
+namespace nix {
+
+template<typename T>
+std::vector<T> topoSort(std::set<T> items,
+ std::function<std::set<T>(const T &)> getChildren,
+ std::function<Error(const T &, const T &)> makeCycleError)
+{
+ std::vector<T> sorted;
+ std::set<T> visited, parents;
+
+ std::function<void(const T & path, const T * parent)> dfsVisit;
+
+ dfsVisit = [&](const T & path, const T * parent) {
+ if (parents.count(path)) throw makeCycleError(path, *parent);
+
+ if (!visited.insert(path).second) return;
+ parents.insert(path);
+
+ std::set<T> references = getChildren(path);
+
+ for (auto & i : references)
+ /* Don't traverse into items that don't exist in our starting set. */
+ if (i != path && items.count(i))
+ dfsVisit(i, &path);
+
+ sorted.push_back(path);
+ parents.erase(path);
+ };
+
+ for (auto & i : items)
+ dfsVisit(i, nullptr);
+
+ std::reverse(sorted.begin(), sorted.end());
+
+ return sorted;
+}
+
+}