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.
the 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 Package.swift
?
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
Prior art: yarn why
, cargo tree -i
Actually, the command @0xTim shared without dot format is very readable:
-> % swift package show-dependencies
.
βββ swift-nio<https://github.com/apple/swift-nio.git@2.41.1>
β βββ swift-atomics<https://github.com/apple/swift-atomics.git@1.0.2>
βββ swift-nio-ssl<https://github.com/apple/swift-nio-ssl.git@2.21.0>
β βββ swift-nio<https://github.com/apple/swift-nio.git@2.41.1>
β βββ swift-atomics<https://github.com/apple/swift-atomics.git@1.0.2>
βββ swift-nio-extras<https://github.com/apple/swift-nio-extras.git@1.12.1>
β βββ swift-nio<https://github.com/apple/swift-nio.git@2.41.1>
β βββ swift-atomics<https://github.com/apple/swift-atomics.git@1.0.2>
βββ swift-log<https://github.com/apple/swift-log.git@1.4.2>
βββ swift-metrics<https://github.com/apple/swift-metrics.git@2.3.2>
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.
Example output:
$ 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')
Nice job
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.