Giter Club home page Giter Club logo

dependency-graph's Introduction

πŸ•ΈοΈ dependency-graph

Build and Test SwiftLint

dependency-graph is a command-line tool that can visualize the dependencies of packages. The tool takes the path to an Xcode project or a Package.swift file as input and outputs a graph that shows the dependencies of the packages in the project or package.

πŸ‘€ Examples

The following graphs are examples of the graphs that dependency-graph can output. The first graph built by providing dependency-graph the path to a Package.swift file and the second graph was made by providing dependency-graph the path to an .xcodeproj file as input.

Swift Package Xcode Project
Example graph showing the dependencies of this package. Example graph showing the dependencies of an Xcode project.

Nodes shaped as ellipsis represent products, e.g. the libraries in a Swift package, and the square nodes represent targets.

πŸš€ Getting Started

Start off by installing the tool with Homebrew.

brew tap simonbs/dependency-graph https://github.com/simonbs/dependency-graph.git
brew install dependency-graph

Note If you get the following error when attempting to install dependency-graph:

Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
   arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.

You can use the the following to install dependency-graph:

arch -arm64 brew install dependency-graph

You may now run the following command to verify that the tool was installed correctly. The following command should print information on how the tool can be used.

dependency-graph --help

Run the dependency-graph command with the path to a folder containing an .xcodeproj or Package.swift file.

dependency-graph ~/Developer/Example

You may also pass the full path to the .xcodeproj or Package.swift file as shown below.

dependency-graph ~/Developer/Example/Example.xcodeproj

Rendering a Graph

The dependency-graph command will output a textual representation of a graph. By default the tool will output a graph using the DOT syntax. For example, if the Xcode project or Package.swift file contains the following dependencies:

Library A in Package A depends on Target A
Library B in Package B depends on Target B
Library A in Package A depends on Library B in Package B

The output of the tool would be a graph that looks like this:

digraph g {
  subgraph cluster_packageA {
    label="Package A"
    libraryA [label="LibraryB", shape=ellipse]
    targetA [label="TargetA", shape=box]
  }

  subgraph cluster_packageB {
    label="Package B"
    libraryB [label="LibraryB", shape=ellipse]
    targetB [label="TargetB", shape=box]
  }

  libraryA -> targetA
  libraryB -> targetB
  libraryA -> libraryB
}

The output can be rendered to an image by piping it to a renderer. See the following sections for details on the supported renderers.

DOT

Example graph rendered with dot.

By default dependency-graph will use the DOT syntax which can be rendered by the dot CLI, which is part of Graphviz.

Install Graphviz and run dependency-graph and pass the output to the newly installed dot CLI.

brew install graphviz
dependency-graph ~/Developer/Example | dot -Tsvg -o graph.svg

When rendering the graph to a PNG, you will likely want to specify the size of the output to ensure it is readable. To generate an image with dot that is exactly 6000 pixels wide or 8000 pixels tall but not necessarily both, do the following:

dependency-graph ~/Developer/Example | dot -Tpng -Gsize=60,80\! -Gdpi=100 -o graph.png

You may want to play around with the values for --node-spacing and --rank-spacing to increase the readability of the graph.

dependency-graph --node-spacing 50 --rank-spacing 150 ~/Developer/Example | dot -Tsvg -o graph.svg

For large projects the graph may become unreadable. Passing the output through Grahpviz' unflatten command may improve the results.

dependency-graph ~/Developer/Example | unflatten -l 100 -c 100 -f | dot -Tpng -o graph.png

Mermaid

Example graph rendered with mermaid.

Specify the --syntax mermaid option to have dependency-graph output a graph using the Mermaid diagram syntax.

The output be rendered to an image using the the mermaid cli.

npm install -g @mermaid-js/mermaid-cli
dependency-graph --syntax mermaid ~/Developer/Example | mmdc -o graph.svg

To generate an image on a page that is 6000 pixels wide with mermaid, do the following:

dependency-graph --syntax mermaid ~/Developer/Example | mmdc -o graph.png -w 6000

You may also want to play around with the values for --node-spacing and --rank-spacing to increase the readability of the graph.

dependency-graph --syntax mermaid --node-spacing 50 --rank-spacing 150 ~/Developer/Example | mmdc -o graph.png

D2

Example graph rendered with D2.

Specify the --syntax d2 option to have dependency-graph output a graph using the d2 scripting language.

The output be rendered to an image using the the d2 cli.

curl -fsSL https://d2lang.com/install.sh | sh -s --
dependency-graph --syntax d2 ~/Developer/Example | d2 - graph.png

The ELK layout engine renders some quite tidy graphs, as shown in the example below.

Example graph rendered with D2 and the ELK layout engine.

Graphing Packages Only

Pass the --packages-only flag to include only the Xcode project and Swift packages in the graph. This omits the libraries and targets within the Xcode project and Swift packages.

Example graph showing only an Xcode project and Swift packages.

πŸ€·β€β™‚οΈ OK, why?

As I'm splitting my iOS and macOS applications into small Swift packages with several small targets, I started wishing for a way to visualise the relationship between the products and targets in my Swift packages. That's why I built this tool.

Several other tools can visualise a Swift package, however, I wanted a tool that can take both a Swift package and an Xcode project as input.

The example in the top of this README shows a visualization of a Swift package and the graph below shows a visualisation of an Xcode project. Notice that the left-most subgraph represents an Xcode project named ScriptUIEditor.xcodeproj and it has three targets: ScriptUIEditor, ScriptBrowserFeature, and ScriptBrowserFeatureUITests. Two of these depends on the Swift packages represented by the remaining subgraphs.

These graphs provide a good way to get an overview of a package or the relationship between several packages. Sometimes it can be helpful to generate multiple graphs to get a good overview, for example, a graph of the entire project and graphs of selected packages. Fortunately, the dependency-graph CLI makes this easy as it can take either an Xcode project and a Package.swift file as input.

🧐 ...but how?

dependency-graph parses Xcode project using XcodeProj and interprets Package.swift files using the output from the swift package dump-package command.

This means that dependency-graph does not perform any package resolution or build the project, making it very fast to run the dependency-graph command but also produces a less detailed output that tools that rely on package resolution.

The tool has a focus on visualising local dependencies, that is, Swift packages stored locally in a project. dependency-graph will include remote dependencies in the visualisation but it will not clone those dependencies to determine their dependency graph. It is technically possible to include this but it has not been necessary for my use cases.

dependency-graph's People

Contributors

alessionossa avatar emadgnia avatar felixherrmann avatar jonasrottmann avatar jordanekay avatar simonbs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

dependency-graph's Issues

Unable to install via brew

What happened?

Attempting to install via brew reveals the following error:

error: 'dependency-graph-20221212-22643-1xg8p9v': Invalid manifest
/private/tmp/dependency-graph-20221212-22643-1xg8p9v/Package.swift:4:8: error: no such module 'PackageDescription'

Do not report this issue to Homebrew/brew or Homebrew/core!

/opt/homebrew/Library/Homebrew/utils/github/api.rb:306:in `raise_error': Validation Failed: [{"message"=>"The listed users and repositories cannot be searched either because the resources do not exist or you do not have permission to view them.", "resource"=>"Search", "field"=>"q", "code"=>"invalid"}] (GitHub::API::ValidationFailedError)

What are the steps to reproduce?

  1. Follow install instructions in readme for tapping
  2. Try brew install dependency-graph

What is the expected behavior?

brew would properly install dependency-graph.

Only output is `Bus error: 10`

What happened?

Run it on my xcodeproj and only get the following output:

$ dependency-graph /Users/.../SomeProject.xcodeproj
Bus error: 10

What are the steps to reproduce?

$ dependency-graph --version
1.2.0

Run with ".xcodeproj"

What is the expected behavior?

Generate the dependency tree in DOT-syntax

Using target dependency condition results in parsing error

What happened?

Using a Target Dependency Condition results in an error Error: Failed parsing dumped Package.swift file at ....

What are the steps to reproduce?

  1. Update a target dependency to use a condition, for example:
...
dependencies: [
    .product(
    	name: "Name", 
    	package: "package", 
    	condition: .when(platforms: [.iOS])
    ),
    ...
]
...
  1. Run dependency-graph

What is the expected behavior?

The Package.swift file should be parsed without an error. The condition of the dependency does probably not need to be evident from the resulting visualisation.

Support for .xcworkspace

I have a project which uses a workspace, which contains a good number of subprojects, Swift packages and also some cocoapods. Any chance, that this will be supported in the future?

Uncaught exception

What happened?

Hi,

Then i try to use your tool on my large project with SPM, i receive this error output:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'working directory doesn't exist.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000187e76ccc __exceptionPreprocess + 176
1 libobjc.A.dylib 0x000000018795e788 objc_exception_throw + 60
2 Foundation 0x0000000188fa0a80 -[NSConcreteTask launchWithDictionary:error:] + 4284
3 dependency-graph 0x000000010507e2f8 $s22ShellCommandRunnerLiveAAV3run13withArguments16fromDirectoryURL0abC00aB6OutputVSaySSG_10Foundation0J0VtFTf4nnd_n + 448
4 dependency-graph 0x0000000105061858 $s22DumpPackageServiceLiveAAV04dumpB033_33DF866953EC50C8C73DEAC71694AABCLL2at10Foundation4DataVAF3URLV_tKF + 260
5 dependency-graph 0x000000010506168c $s22DumpPackageServiceLiveAAV04dumpb8ForSwiftB4File2at10Foundation4DataVAE3URLV_tKF + 248
6 dependency-graph 0x0000000105061980 $s22DumpPackageServiceLiveAAV0abC0Aca2CP04dumpb8ForSwiftB4File2at10Foundation4DataVAG3URLV_tKFTW + 12
7 dependency-graph 0x0000000105073dcc $s26PackageSwiftFileParserLiveAAC09justParseC033_A17BD4055C4467321940459E7754879DLL2at0abC0AFV10Foundation3URLV_tKF + 172
8 dependency-graph 0x000000010507413c $s26PackageSwiftFileParserLiveAAC0abcD0Aca2CP05parseC02at0abC0AGV10Foundation3URLV_tKFTW + 184
9 dependency-graph 0x00000001050731fc $s26PackageSwiftFileParserLive0abC6MapperV3map33_EE38B89A39AD106C0853D66BE4501831LLy0abC0AFV10DependencyOAA012IntermediateabC0VAHOKF + 596
10 dependency-graph 0x0000000105072ea4 $s26PackageSwiftFileParserLive0abC6MapperV3mapy0abC0AEVAA012IntermediateabC0VKF + 1124
11 dependency-graph 0x0000000105073eb4 $s26PackageSwiftFileParserLiveAAC09justParseC033_A17BD4055C4467321940459E7754879DLL2at0abC0AFV10Foundation3URLV_tKF + 404
12 dependency-graph 0x000000010507413c $s26PackageSwiftFileParserLiveAAC0abcD0Aca2CP05parseC02at0abC0AGV10Foundation3URLV_tKFTW + 184
13 dependency-graph 0x000000010515c238 $s28XcodeProjectGraphBuilderLive015AllDependenciescD0V05buildC04from08DirectedC0AFC0aB0AHV_tKF + 956
14 dependency-graph 0x000000010515d458 $s28XcodeProjectGraphBuilderLiveAAC05buildC04from08DirectedC0AEC0aB0AGV_tKF + 192
15 dependency-graph 0x000000010515d56c $s28XcodeProjectGraphBuilderLiveAAC0abcD0Aca2CP05buildC04from08DirectedC0AGC0aB0AIV_tKFTW + 20
16 dependency-graph 0x00000001050628f8 $s12GraphCommandAAV3run9withInput6syntaxySS_AA6SyntaxOtKF + 1216
17 dependency-graph 0x00000001050640cc $s4Main15DependencyGraphV3runyyKF + 320
18 dependency-graph 0x00000001050643b8 $s4Main15DependencyGraphV14ArgumentParser15ParsableCommandAadEP3runyyKFTW + 64
19 dependency-graph 0x00000001050645e4 Main_main + 96
20 dyld 0x000000018799a0e0 start + 2360
)
libc++abi: terminating due to uncaught exception of type NSException

What are the steps to reproduce?

Really large project + SPM

What is the expected behavior?

Without error

`.target(name: "Package name"),` in dependencies is not supported.

What happened?

Getting errors while parsing the top-level Package.swift file.

$ dependency-graph Packages/MyApp

Error: Failed parsing dumped Package.swift file at /myapp-master/Packages/MyApp/Package.swift: 
dataCorrupted(Swift.DecodingError.Context(codingPath: [
CodingKeys(stringValue: "targets", intValue: nil), 
_JSONKey(stringValue: "Index 0", intValue: 0), 
CodingKeys(stringValue: "dependencies", intValue: nil), 
_JSONKey(stringValue: "Index 0", intValue: 0)
], 
debugDescription: "Unsupported keys: ", 
underlyingError: nil))

What are the steps to reproduce?

Add a target dependency with below syntax: .target(name: "MyAppAccessibility"),

For example:

targets: [
        .target(
            name: "ChocoIOSApp",
            dependencies: [
                .target(name: "MyAppAccessibility"),
                .product(name: "FoundationThing", package: "Thing"),
            ]
        )
]

If I change .target(name: "MyAppAccessibility"), to "MyAppAccessibility", the tool can parse the file, but I have too many package files with the same syntax. So the next file fails.

What is the expected behavior?

dependency-graph should be able to parse the .target(name: "") syntax.

Fails to locate local swift packages

What happened?

Error: App depends on Media Player but the dependency was not found in the graph.

What are the steps to reproduce?

Use local Swift Packages with dependencies on other local packages

What is the expected behavior?

Dependency graph should interpret local package nodes.

`zsh: segmentation fault` dependency-graph TestDependency.xcodeproj

What happened?

Test with my xcodeproj failed. below is the error log

`zsh: segmentation fault`  dependency-graph TestDependency.xcodeproj

dependency-graph version: 1.2.0, installed by brew
Project Document Format Xcode 14.0
Xcode Version 15.0 (15A240d)
arch i386
uname -m x86_64

What are the steps to reproduce?

Create a new test project test for it.

What is the expected behavior?

show the result as the document mentioned.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.