Are there existing tools for evaluating the reverse dependencies of a package? That is, for determining the packages that depend directly or indirectly on a particular package?
It occurred to me that, if not, this might be an occasion for me to learn a bit more about the Registries used with Pkg3
. How would I begin exploring the TOML capabilities if I decided to try to parse a Registry?
1 Like
Pkg.dependents
will give you the direct dependencies at least. Shouldn’t be hard to call it recursively if needed.
2 Likes
Thanks. It seems that I should have done a bit more research before asking the question.
https://juliaobserver.com will also give you this information.
2 Likes
This showed up in my Google search today. I don’t think the answers here still work, so I feel compelled to post, with apology, a kludge that does work. Perhaps someone will also post a more elegant solution which makes use of the dependency graph that I believe Pkg
maintains in the first place.
import Pkg
ctx = Pkg.Types.Context()
latest_version(ctx, uuid) = maximum(keys(Pkg.Operations.load_versions(Pkg.Types.registered_paths(ctx.env, uuid)[])))
function latest_pkgspec(ctx, name)
uuid = Pkg.Types.registered_uuid(ctx.env, name)
Pkg.Types.PackageSpec(name, uuid, latest_version(ctx, uuid))
end
latest_deps(pkg_name) = Pkg.Operations.load_deps(ctx, latest_pkgspec(ctx, pkg_name))
latest_deps("Plots") # trigger populating of ctx.env
function reverse_deps(ctx, pkg_name_query)
all_names = map(
x->if length(x) == 1; x[]; else; nothing; end,
values(ctx.env.names))
all_names = filter(!isnothing, all_names)
[pkg_name for pkg_name in all_names if pkg_name_query in keys(latest_deps(pkg_name))]
end
reverse_deps(ctx, "BinDeps")
Thanks for this snippet. Just a small note — in julia 1.4 I had to adjust this to use ctx
rather than ctx.env
.
1 Like
Updated to run w/ 1.5/1.6 below. I say to run because the output is wrong. Pkg.Operations.load_all_deps
does not seem to be the correct function to get all dependencies for a package (assuming that’s what Pkg.Operations.load_deps
did - it no longer exists). Rather, I believe load_all_deps
returns all installed packages in the current environment.
julia> length(latest_deps("Revise"))
83
grep "\[\[" ~/.julia/environments/v1.6/Manifest.toml | wc -l
83
Is there a function to return all dependencies based on a given package name or spec, ideally even if it is not installed?
import Pkg
ctx = Pkg.Types.Context()
latest_version(ctx, uuid) = maximum(keys(Pkg.Operations.load_versions(ctx, Pkg.Types.registered_paths(ctx, uuid)[])))
function latest_pkgspec(ctx, name)
uuid = Pkg.Types.registered_uuid(ctx, name)
Pkg.Types.PackageSpec(name, uuid, latest_version(ctx, uuid))
end
latest_deps(pkg_name) = map(x->x.name, Pkg.Operations.load_all_deps(ctx, [latest_pkgspec(ctx, pkg_name)]))
latest_deps("Plots") # trigger populating of ctx.env
function reverse_deps(ctx, pkg_name_query)
all_names = map(
x->if length(x) == 1; x[]; else; nothing; end,
values(ctx.env.names))
all_names = filter(!isnothing, all_names)
[pkg_name for pkg_name in all_names if pkg_name_query in latest_deps(pkg_name)]
end