GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Push — master ( 31f734...513d45 )
by Anton
06:23
created

Deployer::__get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/* (c) Anton Medvedev <[email protected]>
3
 *
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace Deployer;
9
10
use Deployer\Collection\Collection;
11
use Deployer\Console\Application;
12
use Deployer\Console\AutocompleteCommand;
13
use Deployer\Console\CommandEvent;
14
use Deployer\Console\DebugCommand;
15
use Deployer\Console\InitCommand;
16
use Deployer\Console\Output\Informer;
17
use Deployer\Console\Output\OutputWatcher;
18
use Deployer\Console\RunCommand;
19
use Deployer\Console\SshCommand;
20
use Deployer\Console\TaskCommand;
21
use Deployer\Console\WorkerCommand;
22
use Deployer\Executor\ParallelExecutor;
23
use Deployer\Executor\SeriesExecutor;
24
use Deployer\Logger\Handler\FileHandler;
25
use Deployer\Logger\Handler\NullHandler;
26
use Deployer\Logger\Logger;
27
use function Deployer\Support\array_merge_alternate;
28
use Deployer\Task;
29
use Deployer\Utility\ProcessOutputPrinter;
30
use Deployer\Utility\ProcessRunner;
31
use Deployer\Utility\Reporter;
32
use Deployer\Utility\Rsync;
33
use Pimple\Container;
34
use Symfony\Component\Console;
35
use Symfony\Component\Console\Input\ArgvInput;
36
use Symfony\Component\Console\Output\ConsoleOutput;
37
use Symfony\Component\Console\Style\SymfonyStyle;
38
39
/**
40
 * Deployer class represents DI container for configuring
41
 *
42
 * @property Application $console
43
 * @property Task\TaskCollection|Task\Task[] $tasks
44
 * @property Host\HostCollection|Collection|Host\Host[] $hosts
45
 * @property Collection $config
46
 * @property Rsync $rsync
47
 * @property Ssh\Client $sshClient
48
 * @property ProcessRunner $processRunner
49
 * @property Task\ScriptManager $scriptManager
50
 * @property Host\HostSelector $hostSelector
51
 * @property SeriesExecutor $seriesExecutor
52
 * @property ParallelExecutor $parallelExecutor
53
 * @property Informer $informer
54
 * @property Logger $logger
55
 * @property ProcessOutputPrinter $pop
56
 * @property Collection $fail
57
 */
58
class Deployer extends Container
59
{
60
    /**
61
     * Global instance of deployer. It's can be accessed only after constructor call.
62
     * @var Deployer
63
     */
64
    private static $instance;
65
66
    /**
67
     * @param Application $console
68
     */
69 15
    public function __construct(Application $console)
70
    {
71 15
        parent::__construct();
72
73
        /******************************
74
         *           Console          *
75
         ******************************/
76
77
        $this['console'] = function () use ($console) {
78
            $console->catchIO(function ($input, $output) {
79
                $this['input'] = $input;
80
                $this['output'] =  new OutputWatcher($output);
81
                return [$this['input'], $this['output']];
82
            });
83
            return $console;
84
        };
85
86
        /******************************
87
         *           Config           *
88
         ******************************/
89
90
        $this['config'] = function () {
91 15
            return new Collection();
92
        };
93 15
        $this->config['ssh_multiplexing'] = true;
94 15
        $this->config['default_stage'] = null;
95
96
        /******************************
97
         *            Core            *
98
         ******************************/
99
100
        $this['pop'] = function ($c) {
101 1
            return new ProcessOutputPrinter($c['output'], $c['logger']);
102
        };
103
        $this['sshClient'] = function ($c) {
104
            return new Ssh\Client($c['output'], $c['pop'], $c['config']['ssh_multiplexing']);
105
        };
106
        $this['rsync'] = function ($c) {
107
            return new Rsync($c['pop']);
108
        };
109
        $this['processRunner'] = function ($c) {
110 1
            return new ProcessRunner($c['pop']);
111
        };
112
        $this['tasks'] = function () {
113 4
            return new Task\TaskCollection();
114
        };
115
        $this['hosts'] = function () {
116 4
            return new Host\HostCollection();
117
        };
118
        $this['scriptManager'] = function ($c) {
119 2
            return new Task\ScriptManager($c['tasks']);
120
        };
121
        $this['hostSelector'] = function ($c) {
122
            $defaultStage = $c['config']['default_stage'];
123
            if (is_object($defaultStage) && ($defaultStage instanceof \Closure)) {
124
                $defaultStage = call_user_func($defaultStage);
125
            }
126
            return new Host\HostSelector($c['hosts'], $defaultStage);
127
        };
128
        $this['fail'] = function () {
129
            return new Collection();
130
        };
131
        $this['informer'] = function ($c) {
132
            return new Informer($c['output']);
133
        };
134
        $this['seriesExecutor'] = function ($c) {
135
            return new SeriesExecutor($c['input'], $c['output'], $c['informer']);
136
        };
137
        $this['parallelExecutor'] = function ($c) {
138
            return new ParallelExecutor($c['input'], $c['output'], $c['informer'], $c['console']);
139
        };
140
141
        /******************************
142
         *           Logger           *
143
         ******************************/
144
145
        $this['log_handler'] = function () {
146 1
            return !empty($this->config['log_file'])
147
                ? new FileHandler($this->config['log_file'])
148 1
                : new NullHandler();
149
        };
150
        $this['logger'] = function () {
151 1
            return new Logger($this['log_handler']);
152
        };
153
154
        /******************************
155
         *        Init command        *
156
         ******************************/
157
158
        $this['init_command'] = function () {
159
            return new InitCommand();
160
        };
161
162 15
        self::$instance = $this;
163 15
    }
164
165
    /**
166
     * @return Deployer
167
     */
168 17
    public static function get()
169
    {
170 17
        return self::$instance;
171
    }
172
173
    /**
174
     * @param string $name
175
     * @param mixed $value
176
     */
177 3
    public static function setDefault($name, $value)
178
    {
179 3
        Deployer::get()->config[$name] = $value;
180 3
    }
181
182
    /**
183
     * @param string $name
184
     * @param mixed $default
185
     * @return mixed
186
     */
187 6
    public static function getDefault($name, $default = null)
188
    {
189 6
        return self::hasDefault($name) ? Deployer::get()->config[$name] : $default;
190
    }
191
192
    /**
193
     * @param string $name
194
     * @return boolean
195
     */
196 6
    public static function hasDefault($name)
197
    {
198 6
        return isset(Deployer::get()->config[$name]);
199
    }
200
201
    /**
202
     * @param string $name
203
     * @param array $array
204
     */
205 2
    public static function addDefault($name, $array)
206
    {
207 2
        if (self::hasDefault($name)) {
208 2
            $config = self::getDefault($name);
209 2
            if (!is_array($config)) {
210 1
                throw new \RuntimeException("Configuration parameter `$name` isn't array.");
211
            }
212 1
            self::setDefault($name, array_merge_alternate($config, $array));
213
        } else {
214
            self::setDefault($name, $array);
215
        }
216 1
    }
217
218
    /**
219
     * Init console application
220
     */
221
    public function init()
222
    {
223
        $this->addConsoleCommands();
224
        $this->getConsole()->add(new WorkerCommand($this));
225
        $this->getConsole()->add($this['init_command']);
226
        $this->getConsole()->add(new SshCommand($this));
227
        $this->getConsole()->add(new RunCommand($this));
228
        $this->getConsole()->add(new DebugCommand($this));
229
        $this->getConsole()->add(new AutocompleteCommand());
230
        $this->getConsole()->afterRun([$this, 'collectAnonymousStats']);
231
    }
232
233
    /**
234
     * Transform tasks to console commands.
235
     */
236
    public function addConsoleCommands()
237
    {
238
        $this->getConsole()->addUserArgumentsAndOptions();
239
240
        foreach ($this->tasks as $name => $task) {
241
            if ($task->isPrivate()) {
242
                continue;
243
            }
244
245
            $this->getConsole()->add(new TaskCommand($name, $task->getDescription(), $this));
246
        }
247
    }
248
249
    /**
250
     * @param string $name
251
     * @return mixed
252
     * @throws \InvalidArgumentException
253
     */
254 20
    public function __get($name)
255
    {
256 20
        if (isset($this[$name])) {
257 20
            return $this[$name];
258
        } else {
259 1
            throw new \InvalidArgumentException("Property \"$name\" does not exist.");
260
        }
261
    }
262
263
    /**
264
     * @return Application
265
     */
266
    public function getConsole()
267
    {
268
        return $this['console'];
269
    }
270
271
    /**
272
     * @return Console\Input\InputInterface
273
     */
274
    public function getInput()
275
    {
276
        return $this['input'];
277
    }
278
279
    /**
280
     * @return Console\Output\OutputInterface
281
     */
282
    public function getOutput()
283
    {
284
        return $this['output'];
285
    }
286
287
    /**
288
     * @param string $name
289
     * @return Console\Helper\HelperInterface
290
     */
291
    public function getHelper($name)
292
    {
293
        return $this->getConsole()->getHelperSet()->get($name);
294
    }
295
296
    /**
297
     * Run Deployer
298
     *
299
     * @param string $version
300
     * @param string $deployFile
301
     */
302
    public static function run($version, $deployFile)
303
    {
304
        // Init Deployer
305
        $console = new Application('Deployer', $version);
306
        $input = new ArgvInput();
307
        $output = new ConsoleOutput();
308
        $deployer = new self($console);
309
310
        // Pretty-print uncaught exceptions in symfony-console
311
        set_exception_handler(function ($e) use ($input, $output, $deployer) {
312
            $io = new SymfonyStyle($input, $output);
313
            $io->block($e->getMessage(), get_class($e), 'fg=white;bg=red', ' ', true);
314
            $io->block($e->getTraceAsString());
315
316
            $deployer->logger->log('['. get_class($e) .'] '. $e->getMessage());
317
            $deployer->logger->log($e->getTraceAsString());
318
            exit(1);
319
        });
320
321
        // Require deploy.php file
322
        self::loadRecipe($deployFile);
323
324
        // Run Deployer
325
        $deployer->init();
326
        $console->run($input, $output);
327
    }
328
329
    /**
330
     * Collect anonymous stats about Deployer usage for improving developer experience.
331
     * If you are not comfortable with this, you will always be able to disable this
332
     * by setting `allow_anonymous_stats` to false in your deploy.php file.
333
     *
334
     * @param CommandEvent $commandEvent
335
     * @codeCoverageIgnore
336
     */
337
    public function collectAnonymousStats(CommandEvent $commandEvent)
338
    {
339
        if ($this->config->has('allow_anonymous_stats') && $this->config['allow_anonymous_stats'] === false) {
340
            return;
341
        }
342
343
        $stats = [
344
            'status' => 'success',
345
            'command_name' => $commandEvent->getCommand()->getName(),
346
            'project_hash' => empty($this->config['repository']) ? null : sha1($this->config['repository']),
347
            'hosts_count' => $this->hosts->count(),
348
            'deployer_version' => $this->getConsole()->getVersion(),
349
            'deployer_phar' => $this->getConsole()->isPharArchive(),
350
            'php_version' => phpversion(),
351
            'extension_pcntl' => extension_loaded('pcntl'),
352
            'extension_curl' => extension_loaded('curl'),
353
            'os' => defined('PHP_OS_FAMILY') ? PHP_OS_FAMILY : (stristr(PHP_OS, 'DAR') ? 'OSX' : (stristr(PHP_OS, 'WIN') ? 'WIN' : (stristr(PHP_OS, 'LINUX') ? 'LINUX' : PHP_OS))),
354
            'exception' => null,
355
        ];
356
357
        if ($commandEvent->getException() !== null) {
358
            $stats['status'] = 'error';
359
            $stats['exception'] = get_class($commandEvent->getException());
360
        }
361
362
        if ($stats['command_name'] === 'init') {
363
            $stats['allow_anonymous_stats'] = $GLOBALS['allow_anonymous_stats'] ?? false;
364
        }
365
366
        if (in_array($stats['command_name'], ['worker', 'list', 'help'], true)) {
367
            return;
368
        }
369
370
        Reporter::report($stats);
371
    }
372
373
    /**
374
     * Load recipe file
375
     *
376
     * @param string $deployFile
377
     *
378
     * @return void
379
     * @codeCoverageIgnore
380
     */
381
    public static function loadRecipe($deployFile)
382
    {
383
        if (is_readable($deployFile)) {
384
            // Prevent variable leak into deploy.php file
385
            call_user_func(function () use ($deployFile) {
386
                // reorder autoload stack.
387
                $originStack = spl_autoload_functions();
388
                require $deployFile;
389
                $newStack = spl_autoload_functions();
390
                if ($originStack[0] !== $newStack[0]) {
391
                    foreach (array_reverse($originStack) as $loader) {
392
                        spl_autoload_unregister($loader);
393
                        spl_autoload_register($loader, true, true);
394
                    }
395
                }
396
            });
397
        }
398
    }
399
}
400