├── .github └── FUNDING.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin └── graph-composer ├── composer.json └── src ├── App.php ├── Command ├── Export.php └── Show.php └── Graph └── GraphComposer.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: clue 2 | custom: https://clue.engineering/support 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.1.0 (2020-03-26) 4 | 5 | * Feature: Forward compatibility with symfony/console v5, v4, v3 and legacy v2. 6 | (#34 by @keradus and #48 by @clue) 7 | 8 | * Feature / Fix: Update all dependencies and fix handling non-lowercase package names. 9 | (#50 and #52 by @clue) 10 | 11 | * Improve documentation and installation instructions and add support / sponsorship info. 12 | (#32 by @xavismeh and #43 and #49 by @clue) 13 | 14 | * Improve build setup, add clue/phar-composer to `require-dev`, add build script and update development docs. 15 | (#44 by @clue) 16 | 17 | * Improve test suite by adding PHPUnit to `require-dev`, 18 | support legacy PHP 5.3 through PHP 7.4 and legacy HHVM and simplify test matrix. 19 | (#42 and #51 by @clue) 20 | 21 | ## 1.0.0 (2015-11-17) 22 | 23 | * First stable release, now following SemVer. 24 | 25 | * Feature: Can now be installed as a `require-dev` Composer dependency and 26 | supports running as `./vendor/bin/graph-composer`. 27 | (#12 by @elkuku) 28 | 29 | * Fix: Update dependencies in order to improve error reporting and 30 | MS Windows support. 31 | (#23 by @clue) 32 | 33 | * Updated documentation, test suite and project structure. 34 | (#18, #16 by @nubs and #24, #25, #26, #27 by @clue) 35 | 36 | ## 0.1.1 (2013-09-11) 37 | 38 | * Update jms/composer-deps-analyzer to v0.1.0 and clue/graph to v0.7.0 39 | * Fix: Opening graph images now also works on Mac OS X 40 | 41 | ## 0.1.0 (2013-05-17) 42 | 43 | * BC break: Whole new command line interface 44 | * Feature: Proper command line arguments and help 45 | * Feature: Image format can now be selected (svg, png, jpg/jpeg, etc.) 46 | 47 | ## 0.0.2 (2013-05-15) 48 | 49 | * Feature: Add option to export graph images 50 | 51 | ## 0.0.1 (2013-05-15) 52 | 53 | * First tagged release 54 | 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Christian Lück 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clue/graph-composer 2 | 3 | [![CI status](https://github.com/clue/graph-composer/workflows/CI/badge.svg)](https://github.com/clue/graph-composer/actions) 4 | [![downloads on GitHub](https://img.shields.io/github/downloads/clue/graph-composer/total?color=blue&label=downloads%20on%20GitHub)](https://github.com/clue/graph-composer/releases) 5 | [![installs on Packagist](https://img.shields.io/packagist/dt/clue/graph-composer?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/graph-composer) 6 | 7 | Graph visualization for your project's `composer.json` and its dependencies: 8 | 9 | ![dependency graph for clue/graph-composer](https://cloud.githubusercontent.com/assets/776829/11199047/46dd4dd2-8cca-11e5-845f-cbe485764f56.png) 10 | 11 | **Table of contents** 12 | 13 | * [Usage](#usage) 14 | * [graph-composer show](#graph-composer-show) 15 | * [graph-composer export](#graph-composer-export) 16 | * [Install](#install) 17 | * [As a phar (recommended)](#as-a-phar-recommended) 18 | * [Installation using Composer](#installation-using-composer) 19 | * [Development](#development) 20 | * [Tests](#tests) 21 | * [License](#license) 22 | 23 | ## Usage 24 | 25 | Once clue/graph-composer is [installed](#install), you can use it via command line like this. 26 | 27 | ### graph-composer show 28 | 29 | The `show` command creates a dependency graph for the given project path and opens 30 | the default desktop image viewer for you: 31 | 32 | ```bash 33 | $ php graph-composer.phar show ~/path/to/your/project 34 | ``` 35 | 36 | * It accepts an optional argument which is the path to your project directory or composer.json file 37 | (defaults to checking the current directory for a composer.json file). 38 | 39 | * You may optionally pass an `--format=[svg/svgz/png/jpeg/...]` option to set 40 | the image type (defaults to `svg`). 41 | 42 | ### graph-composer export 43 | 44 | The `export` command works very much like the `show` command, but instead of opening your 45 | default image viewer, it will write the resulting graph to STDOUT or into an image file: 46 | 47 | ```bash 48 | $ php graph-composer.phar export ~/path/to/your/project 49 | ``` 50 | 51 | * It accepts an optional argument which is the path to your project directory or composer.json file 52 | (defaults to checking the current directory for a composer.json file). 53 | 54 | * It accepts an additional optional argument which is the path to write the resulting image to. 55 | Its file extension 56 | also sets the image format (unless you also explicitly pass the `--format` option). Example call: 57 | 58 | ```bash 59 | $ php graph-composer.phar export ~/path/to/your/project export.png 60 | ``` 61 | 62 | If this argument is not given, it defaults to writing to STDOUT, which may 63 | be useful for scripting purposes: 64 | 65 | ```bash 66 | $ php graph-composer.phar export ~/path/to/your/project | base64 67 | ``` 68 | 69 | * You may optionally pass an `--format=[svg/svgz/png/jpeg/...]` option to set 70 | the image type (defaults to `svg`). 71 | 72 | ## Install 73 | 74 | You can grab a copy of clue/graph-composer in either of the following ways. 75 | 76 | This project aims to run on any platform and thus does not require any PHP 77 | extensions and supports running on legacy PHP 5.3 through current PHP 8+. 78 | It's *highly recommended to use the latest supported PHP version* for this project. 79 | 80 | The graph drawing feature is powered by the excellent [GraphViz](https://www.graphviz.org) 81 | software. This means you'll have to install GraphViz (`dot` executable). 82 | The [Graphviz homepage](https://www.graphviz.org/download/) includes complete 83 | installation instructions for most common platforms, users of Debian/Ubuntu-based 84 | distributions may simply invoke: 85 | 86 | ```bash 87 | $ sudo apt install graphviz 88 | ``` 89 | 90 | ### As a phar (recommended) 91 | 92 | Once you have PHP and GraphViz installed, you can simply download a pre-packaged 93 | and ready-to-use version of this project as a Phar to any directory. 94 | You can simply download the latest `graph-composer.phar` file from our 95 | [releases page](https://github.com/clue/graph-composer/releases). 96 | The [latest release](https://github.com/clue/graph-composer/releases/latest) can 97 | always be downloaded like this: 98 | 99 | ```bash 100 | $ curl -JOL https://clue.engineering/graph-composer-latest.phar 101 | ``` 102 | 103 | That's it already. Once downloaded, you can verify everything works by running this: 104 | 105 | ```bash 106 | $ cd ~/Downloads 107 | $ php graph-composer.phar --version 108 | ``` 109 | 110 | > If you prefer a global (system-wide) installation without having to type the `.phar` extension 111 | each time, you may simply invoke: 112 | > 113 | > ```bash 114 | > $ chmod +x graph-composer.phar 115 | > $ sudo mv graph-composer.phar /usr/local/bin/graph-composer 116 | > ``` 117 | > 118 | > You can verify everything works by running: 119 | > 120 | > ```bash 121 | > $ graph-composer --version 122 | > ``` 123 | 124 | There's no separate `update` procedure, simply download the latest release again 125 | and overwrite the existing phar. 126 | 127 | ### Installation using Composer 128 | 129 | Alternatively, you can also install clue/graph-composer as part of your development dependencies. 130 | You will likely want to use the `require-dev` section to exclude clue/graph-composer in your production environment. 131 | 132 | This method also requires PHP 5.3+, GraphViz and, of course, Composer. 133 | 134 | You can either modify your `composer.json` manually or run the following command to include the latest tagged release: 135 | 136 | ```bash 137 | $ composer require --dev clue/graph-composer 138 | ``` 139 | 140 | Now you should be able to invoke the following command in your project root: 141 | 142 | ```bash 143 | $ ./vendor/bin/graph-composer show 144 | ``` 145 | 146 | Alternatively, you can install this globally for your user by running: 147 | 148 | ```bash 149 | $ composer global require clue/graph-composer 150 | ``` 151 | 152 | Now, assuming you have `~/.composer/vendor/bin` in your path, you can invoke the following command: 153 | 154 | ```bash 155 | $ graph-composer show ~/path/to/your/project 156 | ``` 157 | 158 | > Note: You should only invoke and rely on the main graph-composer bin file. 159 | Installing this project as a non-dev dependency in order to use its 160 | source code as a library is *not supported*. 161 | 162 | To update to the latest release, just run `composer update clue/graph-composer`. 163 | If you installed it globally via composer you can run `composer global update clue/graph-composer` instead. 164 | 165 | ## Development 166 | 167 | clue/graph-composer is an [open-source project](#license) and encourages everybody to 168 | participate in its development. 169 | You're interested in checking out how clue/graph-composer works under the hood and/or want 170 | to contribute to the development of clue/graph-composer? 171 | Then this section is for you! 172 | 173 | The recommended way to install clue/graph-composer is to clone (or download) this repository 174 | and use [Composer](https://getcomposer.org) to download its dependencies. 175 | Therefore you'll need PHP, Composer, GraphViz, git and curl installed. 176 | For example, on a recent Ubuntu/debian system, simply run: 177 | 178 | ```bash 179 | $ sudo apt install php7.2-cli git curl graphviz 180 | 181 | $ git clone https://github.com/clue/graph-composer.git 182 | $ cd graph-composer 183 | 184 | $ curl -s https://getcomposer.org/installer | php 185 | $ sudo mv composer.phar /usr/local/bin/composer 186 | 187 | $ composer install 188 | ``` 189 | 190 | You can now verify everything works by running clue/graph-composer like this: 191 | 192 | ```bash 193 | $ php bin/graph-composer show 194 | ``` 195 | 196 | If you want to distribute clue/graph-composer as a single standalone release file, you may 197 | compile the project into a single `graph-composer.phar` file like this: 198 | 199 | ```bash 200 | $ composer build 201 | ``` 202 | 203 | > Note that compiling will temporarily install a copy of this project to the 204 | local `build/` directory and install all non-development dependencies 205 | for distribution. This should only take a second or two if you've previously 206 | installed its dependencies already. 207 | The build script optionally accepts the version number (`VERSION` env) and 208 | an output file name or will otherwise try to look up the last release tag, 209 | such as `graph-composer-1.0.0.phar`. 210 | 211 | You can now verify the resulting `graph-composer.phar` file works by running it 212 | like this: 213 | 214 | ```bash 215 | $ ./graph-composer.phar --version 216 | ``` 217 | 218 | To update your development version to the latest version, just run this: 219 | 220 | ```bash 221 | $ git pull 222 | $ php composer.phar install 223 | ``` 224 | 225 | Made some changes to your local development version? 226 | 227 | Make sure to let the world know! :shipit: 228 | We welcome PRs and would love to hear from you! 229 | 230 | Happy hacking! 231 | 232 | ## Tests 233 | 234 | To run the test suite, you first need to clone this repo and then install all 235 | dependencies [through Composer](https://getcomposer.org): 236 | 237 | ```bash 238 | $ composer install 239 | ``` 240 | 241 | To run the test suite, go to the project root and run: 242 | 243 | ```bash 244 | $ php vendor/bin/phpunit 245 | ``` 246 | 247 | ## License 248 | 249 | This project is released under the permissive [MIT license](LICENSE). 250 | 251 | > Did you know that I offer custom development services and issuing invoices for 252 | sponsorships of releases and for contributions? Contact me (@clue) for details. 253 | -------------------------------------------------------------------------------- /bin/graph-composer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clue/graph-composer", 3 | "description": "Dependency graph visualization for composer.json", 4 | "keywords": ["dependency graph", "visualize dependencies", "visualize composer"], 5 | "homepage": "https://github.com/clue/graph-composer", 6 | "license": "MIT", 7 | "require": { 8 | "php": ">=5.3.6", 9 | "clue/graph": "^0.9.3", 10 | "graphp/graphviz": "^0.2.2", 11 | "jms/composer-deps-analyzer": "^1.0.1", 12 | "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.0 || ^2.1" 13 | }, 14 | "require-dev": { 15 | "clue/phar-composer": "^1.3", 16 | "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" 17 | }, 18 | "autoload": { 19 | "psr-4": { "Clue\\GraphComposer\\": "src/" } 20 | }, 21 | "bin": [ "bin/graph-composer" ], 22 | "scripts": { 23 | "build": "@php bin/build.php" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/App.php: -------------------------------------------------------------------------------- 1 | add(new Command\Show()); 14 | $this->add(new Command\Export()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Command/Export.php: -------------------------------------------------------------------------------- 1 | setName('export') 17 | ->setDescription('Export dependency graph image for given project directory') 18 | ->addArgument('dir', InputArgument::OPTIONAL, 'Path to project directory to scan', '.') 19 | ->addArgument('output', InputArgument::OPTIONAL, 'Path to output image file') 20 | 21 | // add output format option. default value MUST NOT be given, because default is to overwrite with output extension 22 | ->addOption('format', null, InputOption::VALUE_REQUIRED, 'Image format (svg, png, jpeg)'/*, 'svg'*/) 23 | 24 | /*->addOption('dev', null, InputOption::VALUE_NONE, 'If set, Whether require-dev dependencies should be shown') */; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output) 28 | { 29 | $graph = new GraphComposer($input->getArgument('dir')); 30 | 31 | $target = $input->getArgument('output'); 32 | if ($target !== null) { 33 | if (is_dir($target)) { 34 | $target = rtrim($target, '/') . '/graph-composer.svg'; 35 | } 36 | 37 | $filename = basename($target); 38 | $pos = strrpos($filename, '.'); 39 | if ($pos !== false && isset($filename[$pos + 1])) { 40 | // extension found and not empty 41 | $graph->setFormat(substr($filename, $pos + 1)); 42 | } 43 | } 44 | 45 | $format = $input->getOption('format'); 46 | if ($format !== null) { 47 | $graph->setFormat($format); 48 | } 49 | 50 | $path = $graph->getImagePath(); 51 | 52 | if ($target !== null) { 53 | rename($path, $target); 54 | } else { 55 | readfile($path); 56 | } 57 | 58 | return 0; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Command/Show.php: -------------------------------------------------------------------------------- 1 | setName('show') 17 | ->setDescription('Show dependency graph image for given project directory') 18 | ->addArgument('dir', InputArgument::OPTIONAL, 'Path to project directory to scan', '.') 19 | ->addOption('format', null, InputOption::VALUE_REQUIRED, 'Image format (svg, png, jpeg)', 'svg') 20 | /*->addOption('dev', null, InputOption::VALUE_NONE, 'If set, Whether require-dev dependencies should be shown') */; 21 | } 22 | 23 | protected function execute(InputInterface $input, OutputInterface $output) 24 | { 25 | $graph = new GraphComposer($input->getArgument('dir')); 26 | $graph->setFormat($input->getOption('format')); 27 | $graph->displayGraph(); 28 | 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Graph/GraphComposer.php: -------------------------------------------------------------------------------- 1 | '#eeeeee', 14 | 'style' => 'filled, rounded', 15 | 'shape' => 'box', 16 | 'fontcolor' => '#314B5F' 17 | ); 18 | 19 | private $layoutVertexRoot = array( 20 | 'style' => 'filled, rounded, bold' 21 | ); 22 | 23 | private $layoutEdge = array( 24 | 'fontcolor' => '#767676', 25 | 'fontsize' => 10, 26 | 'color' => '#1A2833' 27 | ); 28 | 29 | private $layoutEdgeDev = array( 30 | 'style' => 'dashed' 31 | ); 32 | 33 | private $dependencyGraph; 34 | 35 | /** 36 | * @var GraphViz 37 | */ 38 | private $graphviz; 39 | 40 | /** 41 | * 42 | * @param string $dir 43 | * @param GraphViz|null $graphviz 44 | */ 45 | public function __construct($dir, GraphViz $graphviz = null) 46 | { 47 | if ($graphviz === null) { 48 | $graphviz = new GraphViz(); 49 | $graphviz->setFormat('svg'); 50 | } 51 | $analyzer = new \JMS\Composer\DependencyAnalyzer(); 52 | $this->dependencyGraph = $analyzer->analyze($dir); 53 | $this->graphviz = $graphviz; 54 | } 55 | 56 | /** 57 | * 58 | * @param string $dir 59 | * @return \Fhaculty\Graph\Graph 60 | */ 61 | public function createGraph() 62 | { 63 | $graph = new Graph(); 64 | 65 | foreach ($this->dependencyGraph->getPackages() as $package) { 66 | $name = $package->getName(); 67 | $start = $graph->createVertex($name, true); 68 | 69 | $label = $name; 70 | if ($package->getVersion() !== null) { 71 | $label .= ': ' . $package->getVersion(); 72 | } 73 | 74 | $this->setLayout($start, array('label' => $label) + $this->layoutVertex); 75 | 76 | foreach ($package->getOutEdges() as $requires) { 77 | $targetName = $requires->getDestPackage()->getName(); 78 | $target = $graph->createVertex($targetName, true); 79 | 80 | $label = $requires->getVersionConstraint(); 81 | 82 | $edge = $start->createEdgeTo($target); 83 | $this->setLayout($edge, array('label' => $label) + $this->layoutEdge); 84 | 85 | if ($requires->isDevDependency()) { 86 | $this->setLayout($edge, $this->layoutEdgeDev); 87 | } 88 | } 89 | } 90 | 91 | $root = $graph->getVertex($this->dependencyGraph->getRootPackage()->getName()); 92 | $this->setLayout($root, $this->layoutVertexRoot); 93 | 94 | return $graph; 95 | } 96 | 97 | private function setLayout(AttributeAware $entity, array $layout) 98 | { 99 | $bag = new AttributeBagNamespaced($entity->getAttributeBag(), 'graphviz.'); 100 | $bag->setAttributes($layout); 101 | 102 | return $entity; 103 | } 104 | 105 | public function displayGraph() 106 | { 107 | $graph = $this->createGraph(); 108 | 109 | $this->graphviz->display($graph); 110 | } 111 | 112 | public function getImagePath() 113 | { 114 | $graph = $this->createGraph(); 115 | 116 | return $this->graphviz->createImageFile($graph); 117 | } 118 | 119 | public function setFormat($format) 120 | { 121 | $this->graphviz->setFormat($format); 122 | 123 | return $this; 124 | } 125 | } 126 | --------------------------------------------------------------------------------