Issues (33)

src/Commands/AnalyzeDependencyCommand.php (2 issues)

1
<?php
2
declare(strict_types = 1);
3
4
namespace DependencyAnalyzer\Commands;
5
6
use DependencyAnalyzer\DependencyDumper;
7
use DependencyAnalyzer\DependencyGraph;
8
use DependencyAnalyzer\Exceptions\InvalidCommandArgumentException;
9
use DependencyAnalyzer\Exceptions\ShouldNotHappenException;
10
use DependencyAnalyzer\Exceptions\UnexpectedException;
11
use Symfony\Component\Console\Command\Command;
12
use Symfony\Component\Console\Input\InputArgument;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Input\InputOption;
15
use Symfony\Component\Console\Output\Output;
16
use Symfony\Component\Console\Output\OutputInterface;
17
18
/**
19
 * @da-internal \DependencyAnalyzer\Commands\
20
 */
21
abstract class AnalyzeDependencyCommand extends Command
22
{
23
    const DEFAULT_CONFIG_FILES = [__DIR__ . '/../../conf/config.neon'];
24
25
    protected abstract function inspectDependencyGraph(DependencyGraph $graph, OutputInterface $output): int;
26
    protected abstract function getCommandName(): string;
27
    protected abstract function getCommandDescription(): string;
28
29
    protected function configure(): void
30
    {
31
        $this->setName($this->getCommandName())
32
            ->setDescription($this->getCommandDescription())
33
            ->setDefinition([
34
                new InputArgument('paths', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Target directory of analyze'),
35
                new InputOption('memory-limit', null, InputOption::VALUE_REQUIRED, 'Memory limit for the run (ex: 500k, 500M, 5G)'),
36
                new InputOption('exclude', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Exclude directory of analyze'),
37
            ]);
38
    }
39
40
    protected function execute(InputInterface $input, OutputInterface $output): int
41
    {
42
        if ($memoryLimit = $input->getOption('memory-limit')) {
43
            $this->setMemoryLimit($memoryLimit);
44
        }
45
46
        $dependencyGraph = $this->createDependencyGraph(
47
            $output,
48
            $input->getArgument('paths'),
0 ignored issues
show
It seems like $input->getArgument('paths') can also be of type null and string; however, parameter $paths of DependencyAnalyzer\Comma...createDependencyGraph() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

48
            /** @scrutinizer ignore-type */ $input->getArgument('paths'),
Loading history...
49
            !is_null($input->getOption('exclude')) ? $input->getOption('exclude') : []
0 ignored issues
show
It seems like ! is_null($input->getOpt...on('exclude') : array() can also be of type boolean and null and string; however, parameter $excludePaths of DependencyAnalyzer\Comma...createDependencyGraph() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
            /** @scrutinizer ignore-type */ !is_null($input->getOption('exclude')) ? $input->getOption('exclude') : []
Loading history...
50
        );
51
52
        return $this->inspectDependencyGraph($dependencyGraph, $output);
53
    }
54
55
    /**
56
     * @param OutputInterface $output
57
     * @param string[] $paths
58
     * @param string[] $excludePaths
59
     * @return DependencyGraph
60
     */
61
    protected function createDependencyGraph(OutputInterface $output, array $paths, array $excludePaths = []): DependencyGraph
62
    {
63
        $convertRealpathClosure = function ($path) {
64
            $realpath = realpath($path);
65
            if (!is_file($realpath) && !is_dir($realpath)) {
66
                throw new InvalidCommandArgumentException("path was not found: {$realpath}");
67
            }
68
69
            return $realpath;
70
        };
71
        $paths = array_map($convertRealpathClosure, $paths);
72
        $excludePaths = array_map($convertRealpathClosure, $excludePaths);
73
74
        return $this->createDependencyDumper($output)->dump($paths, $excludePaths);
75
    }
76
77
    /**
78
     * @param OutputInterface $output
79
     * @return DependencyDumper
80
     */
81
    protected function createDependencyDumper(OutputInterface $output): DependencyDumper
82
    {
83
        $currentWorkingDirectory = getcwd();
84
        if ($currentWorkingDirectory === false) {
85
            throw new ShouldNotHappenException('getting current working dir is failed.');
86
        }
87
88
        $tmpDir = sys_get_temp_dir() . '/phpstan';
89
        if (!@mkdir($tmpDir, 0777, true) && !is_dir($tmpDir)) {
90
            throw new ShouldNotHappenException('creating a temp directory is failed: ' . $tmpDir);
91
        }
92
93
        return DependencyDumper::createFromConfig(
94
            $currentWorkingDirectory,
95
            $tmpDir,
96
            self::DEFAULT_CONFIG_FILES
97
        )->setObserver(new DependencyDumperObserver($output));
98
    }
99
100
    /**
101
     * @param string $memoryLimit
102
     */
103
    protected function setMemoryLimit(string $memoryLimit): void
104
    {
105
        if (preg_match('#^-?\d+[kMG]?$#i', $memoryLimit) !== 1) {
106
            throw new InvalidCommandArgumentException(sprintf('memory-limit is invalid format "%s".', $memoryLimit));
107
        }
108
        if (ini_set('memory_limit', $memoryLimit) === false) {
109
            throw new UnexpectedException("setting memory_limit to {$memoryLimit} is failed.");
110
        }
111
    }
112
}
113