Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options to exclude packages and dependencies from graph. #45

Closed
Closed
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## ?.?.? (unreleased)

* Dev dependencies are only rendered for the root package

* Added new options to filter packages and dependencies:
* `--no-dev` will hide dev dependencies
* `--no-php` will hide the constraints regarding the PHP version
* `--no-ext` will hide PHP extensions
* `--depth` will limit the depth of the generated graph
* `--exclude-regex` allows to apply regular expressions to hide packages
* `--only-regex` show only packages with their name matching the expression
* `--exclude-type` exclude pacakges with given type
* `--only-type` only show packages of given type

## 1.1.0 (2020-03-26)

* Feature: Forward compatibility with symfony/console v5, v4, v3 and legacy v2.
Expand All @@ -18,6 +32,7 @@
support legacy PHP 5.3 through PHP 7.4 and legacy HHVM and simplify test matrix.
(#42 and #51 by @clue)


## 1.0.0 (2015-11-17)

* First stable release, now following SemVer.
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ $ php graph-composer.phar export ~/path/to/your/project
* You may optionally pass an `--format=[svg/svgz/png/jpeg/...]` option to set
the image type (defaults to `svg`).

### Options

|Option |Description |Example |
|----------------|----------------------------------------------------------------|-----------------------------------------------------------|
|--format |Image format (`svg`, `png` or `jpeg`), default `svg` |`graph-composer show --format png` |
|--no-dev |Hides dev dependencies |`graph-composer show --no-dev` |
|--no-php |Hides dependency to PHP version |`graph-composer show --no-php` |
|--no-ext |Hides dependency to PHP extensions |`graph-composer show --no-ext` |
|--depth |Stops rendering the graph at the given depth |`graph-composer show --depth 3` |
|--exclude-regex |Hides packages that are matching the regular expression |`graph-composer show --exclude-regex "#^phpunit/#"` |
|--only-regex |Hides packages that are **not** matching the regular expression |`graph-composer show --only-regex "#^mycompany/#"` |
|--exclude-type |Hides packages that are of the given type |`graph-composer show --exclude-type "typo3-cms-framework"` |
|--only-type |Hides packages that are **not** of the given type |`graph-composer show --only-type "typo3-cms-framework"` |

## Install

You can grab a copy of clue/graph-composer in either of the following ways.
Expand Down
93 changes: 93 additions & 0 deletions src/Clue/GraphComposer/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace Clue\GraphComposer\Command;

use Clue\GraphComposer\Exclusion\Dependency\ChainedDependencyRule;
use Clue\GraphComposer\Exclusion\Dependency\NoDevDependencyRule;
use Clue\GraphComposer\Exclusion\Package\ChainedPackageRule;
use Clue\GraphComposer\Exclusion\Package\ExcludeByNamePackageRule;
use Clue\GraphComposer\Exclusion\Package\ExcludeTypePackageRule;
use Clue\GraphComposer\Exclusion\Package\NegatePackageRule;
use Clue\GraphComposer\Exclusion\Package\NoPhpExtensionRule;
use Clue\GraphComposer\Graph\GraphComposer;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;

class AbstractCommand extends Command
{
protected function configure()
{
$this
->addArgument('dir', InputArgument::OPTIONAL, 'Path to project directory to scan', '.')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'Image format (svg, png, jpeg)', 'svg')
->addOption('no-dev', null, InputOption::VALUE_NONE, 'Removes dev dependencies from the generated graph')
->addOption('no-php', null, InputOption::VALUE_NONE, 'Hides dependency to PHP')
->addOption('no-ext', null, InputOption::VALUE_NONE, 'Hide PHP extensions')
->addOption('depth', null, InputOption::VALUE_REQUIRED, 'Set the maximum depth of dependency graph', PHP_INT_MAX)
->addOption('exclude-regex', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Excludes packages using a regular expression like #^phpunit/.*/$#')
->addOption('only-regex', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Includes only packages using a regular expression like #^phpunit/.*/$#')
->addOption('exclude-type', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Excludes packages of given type.')
->addOption('only-type', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Includes only packages of given type.')
;
}

/**
* @param InputInterface $input
* @return GraphComposer
*/
protected function createGraph(InputInterface $input)
{
$dependencyRule = new ChainedDependencyRule();
if ($input->getOption('no-dev')) {
$dependencyRule->add(new NoDevDependencyRule());
}

$packageRule = new ChainedPackageRule();
if ($input->getOption('no-php')) {
$packageRule->add(new ExcludeByNamePackageRule('#^php$#'));
}

if ($input->getOption('no-ext')) {
$packageRule->add(new NoPhpExtensionRule());
}

foreach ($input->getOption('exclude-regex') as $regex) {
$packageRule->add(new ExcludeByNamePackageRule($regex));
}

$onlyRegex = $input->getOption('only-regex');
if (count($onlyRegex)) {
$onlyRegexRule = new ChainedPackageRule();
foreach ($onlyRegex as $regex) {
$onlyRegexRule->add(new ExcludeByNamePackageRule($regex));
}
$packageRule->add(new NegatePackageRule($onlyRegexRule));
}

foreach ($input->getOption('exclude-type') as $type) {
$packageRule->add(new ExcludeTypePackageRule($type));
}

$onlyTypes = $input->getOption('only-type');
if (count($onlyTypes)) {
$onlyTypesRule = new ChainedPackageRule();
foreach ($onlyTypes as $type) {
$onlyTypesRule->add(new ExcludeTypePackageRule($type));
}
$packageRule->add(new NegatePackageRule($onlyTypesRule));
}

$graph = new GraphComposer(
$input->getArgument('dir'),
null,
$packageRule,
$dependencyRule,
(int)$input->getOption('depth')
);
$graph->setFormat($input->getOption('format'));

return $graph;
}
}
23 changes: 6 additions & 17 deletions src/Clue/GraphComposer/Command/Export.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,25 @@

namespace Clue\GraphComposer\Command;

use Symfony\Component\Console\Input\InputOption;
use Clue\GraphComposer\Graph\GraphComposer;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Clue\GraphComposer\Graph\GraphComposer;

class Export extends Command
class Export extends AbstractCommand
{
protected function configure()
{
parent::configure();

$this->setName('export')
->setDescription('Export dependency graph image for given project directory')
->addArgument('dir', InputArgument::OPTIONAL, 'Path to project directory to scan', '.')
->addArgument('output', InputArgument::OPTIONAL, 'Path to output image file')

// add output format option. default value MUST NOT be given, because default is to overwrite with output extension
->addOption('format', null, InputOption::VALUE_REQUIRED, 'Image format (svg, png, jpeg)'/*, 'svg'*/)

/*->addOption('dev', null, InputOption::VALUE_NONE, 'If set, Whether require-dev dependencies should be shown') */;
->addArgument('output', InputArgument::OPTIONAL, 'Path to output image file');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$graph = new GraphComposer($input->getArgument('dir'));
$graph = $this->createGraph($input);

$target = $input->getArgument('output');
if ($target !== null) {
Expand All @@ -42,11 +36,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}

$format = $input->getOption('format');
if ($format !== null) {
$graph->setFormat($format);
}

$path = $graph->getImagePath();

if ($target !== null) {
Expand Down
18 changes: 6 additions & 12 deletions src/Clue/GraphComposer/Command/Show.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,22 @@

namespace Clue\GraphComposer\Command;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Clue\GraphComposer\Graph\GraphComposer;

class Show extends Command
class Show extends AbstractCommand
{
protected function configure()
{
$this->setName('show')
->setDescription('Show dependency graph image for given project directory')
->addArgument('dir', InputArgument::OPTIONAL, 'Path to project directory to scan', '.')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'Image format (svg, png, jpeg)', 'svg')
/*->addOption('dev', null, InputOption::VALUE_NONE, 'If set, Whether require-dev dependencies should be shown') */;
parent::configure();
$this
->setName('show')
->setDescription('Show dependency graph image for given project directory');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$graph = new GraphComposer($input->getArgument('dir'));
$graph->setFormat($input->getOption('format'));
$graph = $this->createGraph($input);
$graph->displayGraph();

return 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Clue\GraphComposer\Exclusion\Dependency;

use JMS\Composer\Graph\DependencyEdge;

class ChainedDependencyRule implements DependencyRule
{
/**
* @var DependencyRule[]
*/
private $rules = array();

public function add(DependencyRule $rule)
{
$this->rules[] = $rule;
}

public function isExcluded(DependencyEdge $dependency)
{
foreach ($this->rules as $rule) {
if ($rule->isExcluded($dependency)) {
return true;
}
}

return false;
}
}
10 changes: 10 additions & 0 deletions src/Clue/GraphComposer/Exclusion/Dependency/DependencyRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Clue\GraphComposer\Exclusion\Dependency;

use JMS\Composer\Graph\DependencyEdge;

interface DependencyRule
{
public function isExcluded(DependencyEdge $dependency);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Clue\GraphComposer\Exclusion\Dependency;

use JMS\Composer\Graph\DependencyEdge;

class NegateDependencyRule implements DependencyRule
{
/**
* @var DependencyRule
*/
private $rule;

public function __construct(DependencyRule $rule)
{
$this->rule = $rule;
}

public function isExcluded(DependencyEdge $dependency)
{
return !$this->rule->isExcluded($dependency);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Clue\GraphComposer\Exclusion\Dependency;

use JMS\Composer\Graph\DependencyEdge;

class NoDevDependencyRule implements DependencyRule
{
public function isExcluded(DependencyEdge $dependency)
{
if ($dependency->isDevDependency()) {
return true;
}

return false;
}
}
29 changes: 29 additions & 0 deletions src/Clue/GraphComposer/Exclusion/Package/ChainedPackageRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Clue\GraphComposer\Exclusion\Package;

use JMS\Composer\Graph\PackageNode;

class ChainedPackageRule implements PackageRule
{
/**
* @var PackageRule[]
*/
private $rules = array();

public function add(PackageRule $rule)
{
$this->rules[] = $rule;
}

public function isExcluded(PackageNode $packageNode)
{
foreach ($this->rules as $rule) {
if ($rule->isExcluded($packageNode)) {
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Clue\GraphComposer\Exclusion\Package;

use JMS\Composer\Graph\PackageNode;

class ExcludeByNamePackageRule implements PackageRule
{
/**
* @var string
*/
private $pattern;

public function __construct($pattern)
{
$this->pattern = $pattern;
}

public function isExcluded(PackageNode $package)
{
return preg_match($this->pattern, $package->getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Clue\GraphComposer\Exclusion\Package;

use JMS\Composer\Graph\PackageNode;

class ExcludeTypePackageRule implements PackageRule
{
/**
* @var string
*/
private $type;

public function __construct($type)
{
$this->type = $type;
}

public function isExcluded(PackageNode $package)
{
$data = $package->getData();

if (!isset($data['type'])) {
return false;
}

return $data['type'] === $this->type;
}
}
Loading