ForrestCommand::initClient()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Startwind\Forrest\CliCommand;
4
5
use GuzzleHttp\Client;
6
use Startwind\Forrest\Command\Command;
7
use Startwind\Forrest\Config\ConfigFileHandler;
8
use Startwind\Forrest\Config\RecentParameterMemory;
9
use Startwind\Forrest\History\HistoryHandler;
10
use Startwind\Forrest\Logger\ForrestLogger;
11
use Startwind\Forrest\Logger\OutputLogger;
12
use Startwind\Forrest\Repository\Loader\CompositeLoader;
13
use Startwind\Forrest\Repository\Loader\LocalComposerRepositoryLoader;
14
use Startwind\Forrest\Repository\Loader\LocalPackageRepositoryLoader;
15
use Startwind\Forrest\Repository\Loader\LocalRepositoryLoader;
16
use Startwind\Forrest\Repository\Loader\RepositoryLoader;
17
use Startwind\Forrest\Repository\Loader\YamlLoader;
18
use Startwind\Forrest\Repository\RepositoryCollection;
19
use Startwind\Forrest\Util\OutputHelper;
20
use Symfony\Component\Console\Command\Command as SymfonyCommand;
21
use Symfony\Component\Console\Helper\QuestionHelper;
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Input\InputOption;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Console\Question\Question;
26
27
abstract class ForrestCommand extends SymfonyCommand
28
{
29
    public const DEFAULT_CONFIG_FILE = __DIR__ . '/../../config/repository.yml';
30
31
    public const DEFAULT_LOCAL_CONFIG_FILE = '.forrest.yml';
32
    public const USER_CONFIG_DIR = '.forrest';
33
    public const USER_CONFIG_FILE = self::USER_CONFIG_DIR . '/config.yml';
34
    public const USER_CHECKSUM_FILE = self::USER_CONFIG_DIR . '/checksum.json';
35
36
    public const USER_RECENT_FILE = self::USER_CONFIG_DIR . '/recent.json';
37
    public const USER_HISTORY_FILE = self::USER_CONFIG_DIR . '/history';
38
39
    private RepositoryCollection $repositoryCollection;
40
41
    private ?RepositoryLoader $repositoryLoader = null;
42
43
    private InputInterface $input;
44
    private OutputInterface $output;
45
    private RecentParameterMemory $recentParameterMemory;
46
47
    private Client $client;
48
49
    private bool $enriched = false;
50
51
    protected function configure()
52
    {
53
        $this->addOption('debug', 'd', InputOption::VALUE_NONE, 'Show logs.');
54
    }
55
56
    protected function execute(InputInterface $input, OutputInterface $output): int
57
    {
58
        ForrestLogger::addLogger('output', new OutputLogger($output));
59
60
        if ($input->getOption('debug')) {
61
            ForrestLogger::setLogLevel(ForrestLogger::LEVEL_INFO);
62
        }
63
64
        $this->input = $input;
65
        $this->output = $output;
66
67
68
        $this->initClient();
69
70
        $home = getenv("HOME");
71
72
        $this->recentParameterMemory = new RecentParameterMemory($home . DIRECTORY_SEPARATOR . self::USER_RECENT_FILE);
73
74
        return $this->doExecute($input, $output);
75
    }
76
77
    private function initClient()
78
    {
79
        $this->client = new Client();
80
    }
81
82
    protected function getRecentParameterMemory(): RecentParameterMemory
83
    {
84
        return $this->recentParameterMemory;
85
    }
86
87
    /**
88
     * Do the actual execution.
89
     */
90
    protected function doExecute(InputInterface $input, OutputInterface $output): int
91
    {
92
        return SymfonyCommand::SUCCESS;
93
    }
94
95
    protected function getInput(): InputInterface
96
    {
97
        return $this->input;
98
    }
99
100
    protected function getOutput(): OutputInterface
101
    {
102
        return $this->output;
103
    }
104
105
    protected function getRepositoryLoader(): RepositoryLoader
106
    {
107
        return $this->repositoryLoader;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->repositoryLoader could return the type null which is incompatible with the type-hinted return Startwind\Forrest\Reposi...Loader\RepositoryLoader. Consider adding an additional type-check to rule them out.
Loading history...
108
    }
109
110
    protected function getUserConfigFile(): string
111
    {
112
        $home = getenv("HOME");
113
        return $home . DIRECTORY_SEPARATOR . self::USER_CONFIG_FILE;
114
    }
115
116
    private function getUserChecksumsFile(): string
117
    {
118
        $home = getenv("HOME");
119
        return $home . DIRECTORY_SEPARATOR . self::USER_CHECKSUM_FILE;
120
    }
121
122
    protected function getConfigHandler(): ConfigFileHandler
123
    {
124
        return new ConfigFileHandler($this->getUserConfigFile(), $this->getUserChecksumsFile());
125
    }
126
127
    protected function getHistoryHandler(): HistoryHandler
128
    {
129
        $home = getenv("HOME");
130
        return new HistoryHandler($home . DIRECTORY_SEPARATOR . self::USER_HISTORY_FILE);
131
    }
132
133
    private function createUserConfig(): void
134
    {
135
        $userConfigFile = $this->getUserConfigFile();
136
137
        if (!file_exists($userConfigFile)) {
138
            $dir = dirname($userConfigFile);
139
            if (!file_exists($dir)) {
140
                mkdir($dir, 0777, true);
141
            }
142
            file_put_contents($userConfigFile, file_get_contents(self::DEFAULT_CONFIG_FILE));
143
        }
144
    }
145
146
    protected function initRepositoryLoader(): void
147
    {
148
        $this->createUserConfig();
149
150
        if (!$this->repositoryLoader) {
151
            $repositoryLoader = new CompositeLoader();
152
153
            $repositoryLoader->addLoader('defaultConfig', new YamlLoader($this->getUserConfigFile(), self::DEFAULT_CONFIG_FILE, $this->getClient()));
154
155
            if (file_exists(self::DEFAULT_LOCAL_CONFIG_FILE)) {
156
                $repositoryLoader->addLoader('localConfig', new LocalRepositoryLoader(self::DEFAULT_LOCAL_CONFIG_FILE));
157
            }
158
159
            if (LocalComposerRepositoryLoader::isApplicable()) {
160
                $repositoryLoader->addLoader('localComposer', new LocalComposerRepositoryLoader());
161
            }
162
163
            if (LocalPackageRepositoryLoader::isApplicable()) {
164
                $repositoryLoader->addLoader('localPackagist', new LocalPackageRepositoryLoader());
165
            }
166
167
            $this->repositoryLoader = $repositoryLoader;
168
        }
169
    }
170
171
    protected function enrichRepositories(): void
172
    {
173
        if (!$this->enriched) {
174
            $this->initRepositoryLoader();
175
            $this->repositoryCollection = new RepositoryCollection();
176
            $this->repositoryLoader->enrich($this->repositoryCollection);
177
            $this->enriched = true;
178
        }
179
    }
180
181
    /**
182
     * Return the command from the fully qualified command identifier.
183
     */
184
    protected function getCommand(string $fullyQualifiedCommandName): Command
185
    {
186
        $this->enrichRepositories();
187
        return $this->getRepositoryCollection()->getCommand($fullyQualifiedCommandName);
188
    }
189
190
    /**
191
     * Write an error message in a beautiful box
192
     */
193
    protected function renderErrorBox(string|array $message): void
194
    {
195
        OutputHelper::writeErrorBox($this->getOutput(), $message);
196
    }
197
198
    /**
199
     * Write an info message in a beautiful box
200
     */
201
    protected function renderInfoBox(string|array $message): void
202
    {
203
        OutputHelper::writeInfoBox($this->getOutput(), $message);
204
    }
205
206
    /**
207
     * Write a warning message in a beautiful box
208
     */
209
    protected function renderWarningBox(string|array $message): void
210
    {
211
        OutputHelper::writeWarningBox($this->getOutput(), $message);
212
    }
213
214
    protected function getRepositoryCollection(): RepositoryCollection
215
    {
216
        return $this->repositoryCollection;
217
    }
218
219
    protected function askQuestion($questionToAsk, bool $notEmpty = true): string
220
    {
221
        /** @var QuestionHelper $questionHelper */
222
        $questionHelper = $this->getHelper('question');
223
        $answer = $questionHelper->ask($this->getInput(), $this->getOutput(), new Question($questionToAsk));
224
225
        if ($notEmpty && !$answer) {
226
            $this->getOutput()->writeln('The value must not be empty.');
227
            return $this->askQuestion($questionToAsk, $notEmpty);
228
        }
229
230
        return $answer;
231
    }
232
233
    /**
234
     * Return an initialized HTTP client. Be sure that every command uses this client
235
     * as caching and other things are already configured here.
236
     */
237
    protected function getClient(): Client
238
    {
239
        return $this->client;
240
    }
241
}
242