Passed
Push — master ( 4c3962...96d1ab )
by Théo
03:03
created

GenerateDockerFile::executeCommand()   B

Complexity

Conditions 7
Paths 138

Size

Total Lines 80
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 43
dl 0
loc 80
rs 8.0452
c 0
b 0
f 0
cc 7
nc 138
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Console\Command;
16
17
use Assert\Assertion;
18
use function file_exists;
19
use function getcwd;
20
use KevinGH\Box\Console\IO\IO;
21
use function KevinGH\Box\create_temporary_phar;
22
use KevinGH\Box\DockerFileGenerator;
23
use function KevinGH\Box\FileSystem\dump_file;
24
use function KevinGH\Box\FileSystem\make_path_relative;
25
use function KevinGH\Box\FileSystem\remove;
26
use function realpath;
27
use function sprintf;
28
use Symfony\Component\Console\Input\InputArgument;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Input\StringInput;
31
use Symfony\Component\Console\Question\ConfirmationQuestion;
32
33
/**
34
 * @private
35
 */
36
final class GenerateDockerFile extends ConfigurableBaseCommand
37
{
38
    private const PHAR_ARG = 'phar';
39
    private const DOCKER_FILE_NAME = 'Dockerfile';
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    protected function configure(): void
45
    {
46
        parent::configure();
47
48
        $this->setName('docker');
49
        $this->setDescription('🐳  Generates a Dockerfile for the given PHAR');
50
        $this->addArgument(
51
            self::PHAR_ARG,
52
            InputArgument::OPTIONAL,
53
            'The PHAR file'
54
        );
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    protected function executeCommand(IO $io): int
61
    {
62
        $pharPath = $io->getInput()->getArgument(self::PHAR_ARG);
63
64
        if (null === $pharPath) {
65
            $pharPath = $this->guessPharPath($io);
66
        }
67
68
        if (null === $pharPath) {
69
            return 1;
70
        }
71
72
        Assertion::file($pharPath);
1 ignored issue
show
Bug introduced by
It seems like $pharPath can also be of type string[]; however, parameter $value of Assert\Assertion::file() does only seem to accept string, 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

72
        Assertion::file(/** @scrutinizer ignore-type */ $pharPath);
Loading history...
73
74
        $pharPath = false !== realpath($pharPath) ? realpath($pharPath) : $pharPath;
75
76
        $io->newLine();
77
        $io->writeln(
78
            sprintf(
79
                '🐳  Generating a Dockerfile for the PHAR "<comment>%s</comment>"',
80
                $pharPath
81
            )
82
        );
83
84
        $tmpPharPath = create_temporary_phar($pharPath);
85
86
        $requirementsPhar = 'phar://'.$tmpPharPath.'/.box/.requirements.php';
87
88
        try {
89
            if (false === file_exists($requirementsPhar)) {
90
                $io->error(
91
                    'Cannot retrieve the requirements for the PHAR. Make sure the PHAR has been built with Box and the '
92
                    .'requirement checker enabled.'
93
                );
94
95
                return 1;
96
            }
97
98
            $requirements = include $requirementsPhar;
99
100
            $dockerFileContents = DockerFileGenerator::createForRequirements(
101
                $requirements,
102
                make_path_relative($pharPath, getcwd())
103
                )
104
                ->generate()
105
            ;
106
107
            if (file_exists(self::DOCKER_FILE_NAME)) {
108
                $remove = $io->askQuestion(
109
                    new ConfirmationQuestion(
110
                        'A Docker file has already been found, are you sure you want to override it?',
111
                        true
112
                    )
113
                );
114
115
                if (false === $remove) {
116
                    $io->writeln('Skipped the docker file generation.');
117
118
                    return 0;
119
                }
120
            }
121
122
            dump_file(self::DOCKER_FILE_NAME, $dockerFileContents);
123
124
            $io->success('Done');
125
126
            $io->writeln(
127
                [
128
                    sprintf(
129
                        'You can now inspect your <comment>%s</comment> file or build your container with:',
130
                        self::DOCKER_FILE_NAME
131
                    ),
132
                    '$ <comment>docker build .</comment>',
133
                ]
134
            );
135
        } finally {
136
            remove($tmpPharPath);
137
        }
138
139
        return 0;
140
    }
141
142
    private function guessPharPath(IO $io): ?string
143
    {
144
        $config = $this->getConfig($io, true);
145
146
        if (file_exists($config->getOutputPath())) {
147
            return $config->getOutputPath();
148
        }
149
150
        $compile = $io->askQuestion(
151
            new ConfirmationQuestion(
152
                'The output PHAR could not be found, do you wish to generate it by running "<comment>box '
153
                .'compile</comment>"?',
154
                true
155
            )
156
        );
157
158
        if (false === $compile) {
159
            $io->error('Could not find the PHAR to generate the docker file for');
160
161
            return null;
162
        }
163
164
        $this->getCompileCommand()->run(
165
            $this->createCompileInput($io),
166
            clone $io->getOutput()
167
        );
168
169
        return $config->getOutputPath();
170
    }
171
172
    private function getCompileCommand(): Compile
173
    {
174
        return $this->getApplication()->find('compile');
175
    }
176
177
    private function createCompileInput(IO $io): InputInterface
178
    {
179
        if ($io->isQuiet()) {
180
            $compileInput = '--quiet';
181
        } elseif ($io->isVerbose()) {
182
            $compileInput = '--verbose 1';
183
        } elseif ($io->isVeryVerbose()) {
184
            $compileInput = '--verbose 2';
185
        } elseif ($io->isDebug()) {
186
            $compileInput = '--verbose 3';
187
        } else {
188
            $compileInput = '';
189
        }
190
191
        $compileInput = new StringInput($compileInput);
192
        $compileInput->setInteractive(false);
193
194
        return $compileInput;
195
    }
196
}
197