Completed
Push — master ( 74cc4f...1ff922 )
by Jan Philipp
16s
created

Application   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 217
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 10
dl 0
loc 217
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
C run() 0 56 10
B showListing() 0 26 4
A extractScriptNames() 0 8 2
A execute() 0 23 3
A notifySuccess() 0 4 1
A notifyError() 0 4 1
A printHeader() 0 8 2
A getPaddingSize() 0 10 3
1
<?php declare(strict_types=1);
2
3
4
namespace Shopware\Psh\Application;
5
6
use Khill\Duration\Duration;
7
use League\CLImate\CLImate;
8
use Shopware\Psh\Config\Config;
9
use Shopware\Psh\Listing\Script;
10
use Shopware\Psh\Listing\ScriptNotFoundException;
11
use Shopware\Psh\Listing\ScriptPathNotValidException;
12
use Shopware\Psh\ScriptRuntime\ExecutionErrorException;
13
use Shopware\Psh\ScriptRuntime\TemplateNotValidException;
14
15
/**
16
 * Main application entry point. moves the requested data around and outputs user information.
17
 */
18
class Application
19
{
20
    const RESULT_SUCCESS = 0;
21
22
    const RESULT_ERROR = 1;
23
24
    const MIN_PADDING_SIZE = 30;
25
26
    /**
27
     * @var CLImate
28
     */
29
    public $cliMate;
30
31
    /**
32
     * @var string
33
     */
34
    private $rootDirectory;
35
36
    /**
37
     * @var ApplicationFactory
38
     */
39
    private $applicationFactory;
40
41
    /**
42
     * @var Duration
43
     */
44
    private $duration;
45
46
    /**
47
     * @param string $rootDirectory
48
     */
49
    public function __construct(string $rootDirectory)
50
    {
51
        $this->rootDirectory = $rootDirectory;
52
        $this->applicationFactory = new ApplicationFactory();
53
        $this->cliMate = new CLImate();
54
        $this->duration = new Duration();
55
    }
56
57
    /**
58
     * Main entry point to execute the application.
59
     *
60
     * @param array $inputArgs
61
     * @return int exit code
62
     */
63
    public function run(array $inputArgs): int
64
    {
65
        $config = $this->applicationFactory
66
            ->createConfig($this->rootDirectory);
67
68
        $scriptFinder = $this->applicationFactory
69
            ->createScriptFinder($config);
70
71
        $this->printHeader($config);
72
        $scriptNames = $this->extractScriptNames($inputArgs);
73
        if (count($scriptNames) > 0 && $scriptNames[0] === 'bash_autocompletion_dump') {
74
            $scripts = $scriptFinder->getAllScripts();
75
            $commands = array_map(function (Script $script) {
76
                return $script->getName();
77
            }, $scripts);
78
            echo implode(' ', $commands);
79
            return self::RESULT_SUCCESS;
80
        }
81
82
        try {
83
            foreach ($scriptNames as $scriptName) {
84
                $executionExitCode = $this->execute($scriptFinder->findScriptByName($scriptName), $config);
85
86
                if ($executionExitCode !== self::RESULT_SUCCESS) {
87
                    return $executionExitCode;
88
                }
89
            }
90
91
            if (isset($executionExitCode)) {
92
                return $executionExitCode;
93
            }
94
        } catch (ScriptNotFoundException $e) {
95
            $this->notifyError("Script with name {$inputArgs[1]} not found\n");
96
97
            $scripts = [];
98
            foreach ($scriptNames as $scriptName) {
99
                $newScripts = $scriptFinder->findScriptsByPartialName($scriptName);
100
                $scripts = array_merge($scripts, $newScripts);
101
            }
102
103
            if (count($scripts) > 0) {
104
                $this->cliMate->yellow()->bold('Have you been looking for this?');
105
                $this->showListing($scripts);
106
            }
107
            return self::RESULT_ERROR;
108
        }
109
110
        try {
111
            $this->showListing($scriptFinder->getAllScripts());
112
        } catch (ScriptPathNotValidException $e) {
113
            $this->notifyError($e->getMessage() . "\n");
114
            return self::RESULT_ERROR;
115
        }
116
117
        return self::RESULT_SUCCESS;
118
    }
119
120
    /**
121
     * @param Script[] $scripts
122
     */
123
    public function showListing(array $scripts)
124
    {
125
        $this->cliMate->green()->bold('Available commands:')->br();
126
127
        if (!count($scripts)) {
128
            $this->cliMate->yellow()->bold('-> Currently no scripts available');
129
        }
130
131
        $paddingSize = $this->getPaddingSize($scripts);
132
        $padding = $this->cliMate->padding($paddingSize)->char(' ');
133
134
        $scriptEnvironment = false;
135
136
        foreach ($scripts as $script) {
137
            if ($scriptEnvironment !== $script->getEnvironment()) {
138
                $scriptEnvironment = $script->getEnvironment();
139
                $this->cliMate->green()->br()->bold(($scriptEnvironment ?? 'default'). ':');
140
            }
141
142
            $padding
143
                ->label('<bold> - ' . $script->getName() . '</bold>')
144
                ->result('<dim>' . $script->getDescription() . '</dim>');
145
        }
146
147
        $this->cliMate->green()->bold("\n" . count($scripts) . " script(s) available\n");
148
    }
149
150
    /**
151
     * @param array $inputArgs
152
     * @return array
153
     */
154
    protected function extractScriptNames(array $inputArgs): array
155
    {
156
        if (!isset($inputArgs[1])) {
157
            return [];
158
        }
159
160
        return explode(',', $inputArgs[1]);
161
    }
162
163
    /**
164
     * @param Script $script
165
     * @param Config $config
166
     * @return int
167
     */
168
    protected function execute(Script $script, Config $config): int
169
    {
170
        $commands = $this->applicationFactory
171
            ->createCommands($script);
172
173
        $logger = new ClimateLogger($this->cliMate, $this->duration);
174
        $executor = $this->applicationFactory
175
            ->createProcessExecutor($script, $config, $logger, $this->rootDirectory);
176
177
        try {
178
            $executor->execute($script, $commands);
179
        } catch (ExecutionErrorException $e) {
180
            $this->notifyError("\nExecution aborted, a subcommand failed!\n");
181
            return self::RESULT_ERROR;
182
        } catch (TemplateNotValidException $e) {
183
            $this->notifyError("\n" . $e->getMessage() . "\n");
184
            return self::RESULT_ERROR;
185
        }
186
187
        $this->notifySuccess("All commands successfully executed!\n");
188
189
        return self::RESULT_SUCCESS;
190
    }
191
192
    /**
193
     * @param $string
194
     */
195
    public function notifySuccess($string)
196
    {
197
        $this->cliMate->bold()->green($string);
198
    }
199
200
    /**
201
     * @param $string
202
     */
203
    public function notifyError($string)
204
    {
205
        $this->cliMate->bold()->red($string);
206
    }
207
208
    /**
209
     * @param $config
210
     */
211
    protected function printHeader(Config $config)
212
    {
213
        $this->cliMate->green()->bold()->out("\n###################");
214
215
        if ($config->getHeader()) {
216
            $this->cliMate->out("\n" . $config->getHeader());
217
        }
218
    }
219
220
    /**
221
     * @param Script[] $scripts
222
     * @return Int
223
     */
224
    private function getPaddingSize(array $scripts): Int
225
    {
226
        $maxScriptNameLength = 0;
227
        foreach ($scripts as $script) {
228
            if (strlen($script->getName()) > $maxScriptNameLength) {
229
                $maxScriptNameLength = strlen($script->getName());
230
            }
231
        }
232
        return $maxScriptNameLength + self::MIN_PADDING_SIZE;
233
    }
234
}
235