Is there an SPM command to show how a dependency came to be? Something that shows all the dependency chains that lead to a particular package being included in the build.
swift-package-catalog SPM plugin can do this. if you add and run the plugin without any arguments, it will emit a list of all the modules, organized by package, in your build, and the list of modules, organized by package, recursively depended upon by each of those targets.
the plugin supports linux, even though the badges on the readme do not indicate it.
swift package show-dependencies
Although it only tells you the packages, not the products and targets.
Hmm, I don't think this does what I'm asking for. It seems to show you what a particular package depends on. What I'm trying to find out is "what has a package as a dependency?" Also, is there a way to add SPM plugins globally? What if I can't (or don't want to) modify the local
As I mentioned above, this isn't what I'm looking for. I'm looking for the inverse of this. Given a package, what dependency chains give rise to the package in question?
i don’t know how large your dependency graph is, but maybe
swift-package-catalog emits its output as JSON, so maybe you could text-search the name of the package to see where it appears?
if this is not practical, feel free to open a feature request on
swift-package-catalog, as this is definitely in-scope for the plugin.
you can create an empty consumer package that depends on both the plugin and the local package. see
swift-biome/ecosystem for an example
They are the same question, just asked in reverse.
When I am debugging a particular package graph, I use that command and then ⌘F to search the output. From each hit, I visually trace it out backwards to the root package. That has always been simple and fast enough, so it has never occurred to me to bother automating. If you think it would be useful, you could propose a filter option for that command.
On the other hand, if you are asking how to find arbitrary clients of a package out in the wild, that would be a completely different question for which I have no answer.
Right, this is what I'm trying to avoid.
swift package show-dependencies --format dot | dot -Tsvg -o graph.svg
Will give you a nice image to work it out
Actually, the command @0xTim shared without dot format is very readable:
-> % swift package show-dependencies . ├── swift-nio<https://email@example.com> │ └── swift-atomics<https://firstname.lastname@example.org> ├── swift-nio-ssl<https://email@example.com> │ └── swift-nio<https://firstname.lastname@example.org> │ └── swift-atomics<https://email@example.com> ├── swift-nio-extras<https://firstname.lastname@example.org> │ └── swift-nio<https://email@example.com> │ └── swift-atomics<https://firstname.lastname@example.org> ├── swift-log<https://email@example.com> └── swift-metrics<https://firstname.lastname@example.org>
More prior art from the sbt ecosystem; using dependencyTree was always tremendously useful to me back then. It can do a little bit more, but the basic functionality is the same.
$ sbt dependencyTree [info] io.github.gitbucket:gitbucket_2.13:4.36.0 [S] [info] +-ch.qos.logback:logback-classic:1.2.3 [info] | +-ch.qos.logback:logback-core:1.2.3 [info] | +-org.slf4j:slf4j-api:1.7.25 (evicted by: 2.0.0-alpha1) [info] | +-org.slf4j:slf4j-api:2.0.0-alpha1 [info] | [info] +-com.github.takezoe:blocking-slick-32_2.13:0.0.12 [S] [info] | +-com.typesafe.slick:slick_2.13:3.3.2 [S] [info] | +-com.typesafe:config:1.3.2 (evicted by: 1.4.1) [info] | +-com.typesafe:config:1.4.1 [info] | +-org.reactivestreams:reactive-streams:1.0.2 [info] | +-org.scala-lang.modules:scala-collection-compat_2.13:2.0.0 [S] [info] | +-org.slf4j:slf4j-api:1.7.25 (evicted by: 2.0.0-alpha1) [info] | +-org.slf4j:slf4j-api:2.0.0-alpha1
// Yet another great plugin originated by akka team members
Would be quite nice to replicate this (looks similar to
cargo tree) using a SwiftPM plugin -- we could do some query things to answer your specific question "where does this dep come from" etc... Worth some investigation by the community?
swift-package-catalog v0.4.0 now contains a tool called
blame, which can be used to attribute dependencies to their direct consumers.
$ swift package blame Atomics NIOCore
direct consumers of Atomics: 0. NIOEmbedded (in 'swift-nio') 1. NIOPosix (in 'swift-nio') direct consumers of NIOCore: 0. NIO (in 'swift-nio') 1. NIOEmbedded (in 'swift-nio') 2. NIOPosix (in 'swift-nio') 3. NIOSSL (in 'swift-nio-ssl') 4. NIOTLS (in 'swift-nio')
That’s close! But my particular need is to see why my project has a particular dependency, so I'd love it to show the chain all the way up to the root.
well, dependencies are contagious, so i didn’t think the full recursive penumbra would be that useful. but i can add that if you want!
for now, i suppose you can just feed the descendants back into the
blame tool until you get to a leaf node?
For sure, but my intent in asking the question was to find a way to get a direct answer. I basically want to be able to find out why I have some deep dependency that I didn't explicitly add.