diff --git a/R/find.R b/R/find.R index a9ac09d..42e8b5f 100644 --- a/R/find.R +++ b/R/find.R @@ -17,6 +17,7 @@ #' conflict_scout() conflict_scout <- function(pkgs = NULL) { pkgs <- pkgs %||% pkgs_attached() + pkgs <- topo_sort(pkgs) objs <- lapply(pkgs, pkg_ls) names(objs) <- pkgs diff --git a/R/topo.R b/R/topo.R new file mode 100644 index 0000000..dae5fa9 --- /dev/null +++ b/R/topo.R @@ -0,0 +1,54 @@ +pkg_dep <- function(pkg) { + if (pkg == "base") { + return() + } + ns <- asNamespace(pkg) + path <- ns$.__NAMESPACE__.$path + + # Safety net + if (is.null(path)) { + lib <- NULL + } else { + lib <- dirname(path) + } + + imports <- utils::packageDescription(pkg, lib.loc = lib)$Imports + if (is.null(imports)) { + return(character()) + } + imports <- gsub(" *", "", imports) + imports <- gsub("[(][^)]+[)]", "", imports) + imports <- gsub("\n", "", imports) + strsplit(imports, ",")[[1]] +} + +pkg_deps <- function(pkgs) { + lapply(set_names(pkgs), pkg_dep) +} + +# AI generated +topo_sort <- function(pkgs) { + adj_list <- pkg_deps(pkgs) + visited <- list() + stack <- character() + + dfs <- function(vertex) { + visited[[vertex]] <<- TRUE + + for (neighbor in adj_list[[vertex]]) { + if (!isTRUE(visited[[neighbor]])) { + dfs(neighbor) + } + } + + stack <<- c(stack, vertex) + } + + for (vertex in names(adj_list)) { + if (!isTRUE(visited[[vertex]])) { + dfs(vertex) + } + } + + intersect(stack, pkgs) +} diff --git a/tests/testthat/_snaps/topo.md b/tests/testthat/_snaps/topo.md new file mode 100644 index 0000000..f2575c0 --- /dev/null +++ b/tests/testthat/_snaps/topo.md @@ -0,0 +1,12 @@ +# topo_sort() works + + Code + intersect(topo_sort(c("testthat", "rlang")), c("testthat", "rlang")) + Output + [1] "rlang" "testthat" + Code + intersect(topo_sort(c("testthat", "rlang", "withr")), c("testthat", "rlang", + "withr")) + Output + [1] "rlang" "withr" "testthat" + diff --git a/tests/testthat/test-topo.R b/tests/testthat/test-topo.R new file mode 100644 index 0000000..d48801b --- /dev/null +++ b/tests/testthat/test-topo.R @@ -0,0 +1,13 @@ +test_that("topo_sort() works", { + # Can only use packages that we import or suggest + expect_snapshot({ + intersect( + topo_sort(c("testthat", "rlang")), + c("testthat", "rlang") + ) + intersect( + topo_sort(c("testthat", "rlang", "withr")), + c("testthat", "rlang", "withr") + ) + }) +})