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.
Completed
Push — master ( e2875b...35ced9 )
by Anton
03:41
created

src/Deployer.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Component\PharUpdate\Console\Command as PharUpdateCommand;
12
use Deployer\Component\PharUpdate\Console\Helper as PharUpdateHelper;
13
use Deployer\Component\ProcessRunner\Printer;
14
use Deployer\Component\ProcessRunner\ProcessRunner;
15
use Deployer\Component\Ssh\Client;
16
use Deployer\Configuration\Configuration;
17
use Deployer\Console\CommandEvent;
18
use Deployer\Console\ConnectCommand;
19
use Deployer\Console\DiceCommand;
20
use Deployer\Console\InitCommand;
21
use Deployer\Console\MainCommand;
22
use Deployer\Console\RunCommand;
23
use Deployer\Console\SshCommand;
24
use Deployer\Console\TreeCommand;
25
use Deployer\Console\WorkerCommand;
26
use Deployer\Executor\Master;
27
use Deployer\Executor\Messenger;
28
use Deployer\Executor\Server;
29
use Deployer\Host\Host;
30
use Deployer\Host\HostCollection;
31
use Deployer\Logger\Handler\FileHandler;
32
use Deployer\Logger\Handler\NullHandler;
33
use Deployer\Logger\Logger;
34
use Deployer\Selector\Selector;
35
use Deployer\Task;
36
use Deployer\Task\ScriptManager;
37
use Deployer\Task\TaskCollection;
38
use Deployer\Utility\Httpie;
39
use Deployer\Utility\Reporter;
40
use Deployer\Utility\Rsync;
41
use Pimple\Container;
42
use Symfony\Component\Console;
43
use Symfony\Component\Console\Application;
44
use Symfony\Component\Console\Input\ArgvInput;
45
use Symfony\Component\Console\Input\InputDefinition;
46
use Symfony\Component\Console\Input\InputInterface;
47
use Symfony\Component\Console\Input\InputOption;
48
use Symfony\Component\Console\Output\ConsoleOutput;
49
use Symfony\Component\Console\Output\OutputInterface;
50
use Throwable;
51
52
/**
53
 * Deployer class represents DI container for configuring
54
 *
55
 * @property Application $console
56
 * @property InputInterface $input
57
 * @property OutputInterface $output
58
 * @property Task\TaskCollection|Task\Task[] $tasks
59
 * @property HostCollection|Host[] $hosts
60
 * @property Configuration $config
61
 * @property Rsync $rsync
62
 * @property Client $sshClient
63
 * @property ProcessRunner $processRunner
64
 * @property Task\ScriptManager $scriptManager
65
 * @property Selector $selector
66
 * @property Master $master
67
 * @property Messenger $messenger
68
 * @property Messenger $logger
69
 * @property Printer $pop
70
 * @property Collection $fail
71
 * @property InputDefinition $inputDefinition
72
 */
73
class Deployer extends Container
74
{
75
    /**
76
     * Global instance of deployer. It's can be accessed only after constructor call.
77
     * @var Deployer
78
     */
79
    private static $instance;
80
81 20
    public function __construct(Application $console)
82
    {
83 20
        parent::__construct();
84
85
        /******************************
86
         *           Console          *
87
         ******************************/
88
89 20
        $console->getDefinition()->addOption(
90 20
            new InputOption('--file', '-f', InputOption::VALUE_OPTIONAL, 'Specify Deployer file')
91
        );
92
93
        $this['console'] = function () use ($console) {
94 12
            return $console;
95
        };
96
        $this['input'] = function () {
97
            throw new \RuntimeException('Uninitialized "input" in Deployer container.');
98
        };
99
        $this['output'] = function () {
100
            throw new \RuntimeException('Uninitialized "output" in Deployer container.');
101
        };
102
        $this['inputDefinition'] = function () {
103 12
            return new InputDefinition();
104
        };
105
        $this['questionHelper'] = function () {
106 12
            return $this->getHelper('question');
107
        };
108
109
        /******************************
110
         *           Config           *
111
         ******************************/
112
113
        $this['config'] = function () {
114 20
            return new Configuration();
115
        };
116 20
        $this->config['shell'] = 'bash -s';
117 20
        $this->config['port'] = '';
118 20
        $this->config['config_file'] = '';
119 20
        $this->config['identity_file'] = '';
120 20
        $this->config['remote_user'] = '';
121 20
        $this->config['forward_agent'] = true;
122 20
        $this->config['ssh_multiplexing'] = true;
123
124
        /******************************
125
         *            Core            *
126
         ******************************/
127
128
        $this['pop'] = function ($c) {
129 14
            return new Printer($c['output']);
130
        };
131
        $this['sshClient'] = function ($c) {
132 12
            return new Client($c['output'], $c['pop'], $c['logger']);
133
        };
134
        $this['rsync'] = function ($c) {
135
            return new Rsync($c['pop'], $c['output']);
136
        };
137
        $this['processRunner'] = function ($c) {
138 10
            return new ProcessRunner($c['pop'], $c['logger']);
139
        };
140
        $this['tasks'] = function () {
141 15
            return new TaskCollection();
142
        };
143
        $this['hosts'] = function () {
144 14
            return new HostCollection();
145
        };
146
        $this['scriptManager'] = function ($c) {
147 14
            return new ScriptManager($c['tasks']);
148
        };
149
        $this['selector'] = function ($c) {
150 10
            return new Selector($c['hosts']);
151
        };
152
        $this['fail'] = function () {
153 8
            return new Collection();
154
        };
155
        $this['messenger'] = function ($c) {
156 12
            return new Messenger($c['input'], $c['output']);
157
        };
158
        $this['server'] = function ($c) {
159 12
            return new Server(
160 12
                $c['input'],
161 12
                $c['output'],
162 12
                $c['questionHelper'],
163
            );
0 ignored issues
show
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
164
        };
165
        $this['master'] = function ($c) {
166 12
            return new Master(
167 12
                $c['input'],
168 12
                $c['output'],
169 12
                $c['server'],
170 12
                $c['messenger'],
171 12
                $c['sshClient'],
172 12
                $c['config']
173
            );
174
        };
175
176
        /******************************
177
         *           Logger           *
178
         ******************************/
179
180
        $this['log_handler'] = function () {
181 14
            return !empty($this->config['log_file'])
182
                ? new FileHandler($this->config['log_file'])
183 14
                : new NullHandler();
184
        };
185
        $this['logger'] = function () {
186 14
            return new Logger($this['log_handler']);
187
        };
188
189 20
        self::$instance = $this;
190 20
    }
191
192
    /**
193
     * @return Deployer
194
     */
195 29
    public static function get()
196
    {
197 29
        return self::$instance;
198
    }
199
200
    /**
201
     * Init console application
202
     */
203 12
    public function init()
204
    {
205 12
        $this->addTaskCommands();
206 12
        $this->getConsole()->add(new ConnectCommand($this));
207 12
        $this->getConsole()->add(new WorkerCommand($this));
208 12
        $this->getConsole()->add(new DiceCommand());
209 12
        $this->getConsole()->add(new InitCommand());
210 12
        $this->getConsole()->add(new TreeCommand($this));
211 12
        $this->getConsole()->add(new SshCommand($this));
212 12
        $this->getConsole()->add(new RunCommand($this));
213 12
        if (self::isPharArchive()) {
214
            $selfUpdate = new PharUpdateCommand('self-update');
215
            $selfUpdate->setDescription('Updates deployer.phar to the latest version');
216
            $selfUpdate->setManifestUri('https://deployer.org/manifest.json');
217
            $this->getConsole()->add($selfUpdate);
218
            $this->getConsole()->getHelperSet()->set(new PharUpdateHelper());
219
        }
220 12
    }
221
222
    /**
223
     * Transform tasks to console commands.
224
     */
225 12
    public function addTaskCommands()
226
    {
227 12
        foreach ($this->tasks as $name => $task) {
228 12
            $command = new MainCommand($name, $task->getDescription(), $this);
229 12
            $command->setHidden($task->isHidden());
230
231 12
            $this->getConsole()->add($command);
232
        }
233 12
    }
234
235
    /**
236
     * @param string $name
237
     * @return mixed
238
     * @throws \InvalidArgumentException
239
     */
240 27
    public function __get($name)
241
    {
242 27
        if (isset($this[$name])) {
243 27
            return $this[$name];
244
        } else {
245
            throw new \InvalidArgumentException("Property \"$name\" does not exist.");
246
        }
247
    }
248
249
    /**
250
     * @param string $name
251
     * @param mixed $value
252
     */
253 12
    public function __set($name, $value)
254
    {
255 12
        $this[$name] = $value;
256 12
    }
257
258
    /**
259
     * @return Application
260
     */
261 12
    public function getConsole()
262
    {
263 12
        return $this['console'];
264
    }
265
266
    /**
267
     * @param string $name
268
     * @return Console\Helper\HelperInterface
269
     */
270 12
    public function getHelper($name)
271
    {
272 12
        return $this->getConsole()->getHelperSet()->get($name);
273
    }
274
275
    /**
276
     * Run Deployer
277
     *
278
     * @param string $version
279
     * @param string $deployFile
280
     */
281
    public static function run($version, $deployFile)
282
    {
283
        $input = new ArgvInput();
284
        $output = new ConsoleOutput();
285
286
        try {
287
            // Init Deployer
288
            $console = new Application('Deployer', $version);
289
            $deployer = new self($console);
290
291
            // Require deploy.php file
292
            self::load($deployFile);
293
294
            // Run Deployer
295
            $deployer->init();
296
            $console->run($input, $output);
297
298
        } catch (Throwable $exception) {
299
            self::printException($output, $exception);
300
        }
301
    }
302
303 12
    public static function load(string $deployFile)
304
    {
305 12
        if (is_readable($deployFile)) {
306
            // Prevent variable leak into deploy.php file
307
            call_user_func(function () use ($deployFile) {
308
                // Reorder autoload stack
309 12
                $originStack = spl_autoload_functions();
310
311 12
                require $deployFile;
312
313 12
                $newStack = spl_autoload_functions();
314 12
                if ($originStack[0] !== $newStack[0]) {
315
                    foreach (array_reverse($originStack) as $loader) {
316
                        spl_autoload_unregister($loader);
317
                        spl_autoload_register($loader, true, true);
318
                    }
319
                }
320 12
            });
321
        }
322 12
    }
323
324
    public static function printException(OutputInterface $output, Throwable $exception)
325
    {
326
        $class = get_class($exception);
327
        $file = basename($exception->getFile());
328
        $output->writeln([
329
            "<fg=white;bg=red> {$class} </> <comment>in {$file} on line {$exception->getLine()}:</>",
330
            "",
331
            implode("\n", array_map(function ($line) {
332
                return "  " . $line;
333
            }, explode("\n", $exception->getMessage()))),
334
            "",
335
        ]);
336
        if ($output->isDebug()) {
337
            $output->writeln($exception->getTraceAsString());
338
        }
339
    }
340
341 1
    public static function isWorker() {
342 1
        return Deployer::get()->config->has('master_url');
343
    }
344
345
    public static function proxyCallToMaster(Host $host, $func, ...$arguments) {
346
        return Httpie::get(get('master_url') . '/proxy')
347
            ->setopt(CURLOPT_TIMEOUT, 0) // no timeout
348
            ->body([
349
                'host' => $host->getAlias(),
350
                'func' => $func,
351
                'arguments' => $arguments,
352
            ])
353
            ->getJson();
354
    }
355
356
    /**
357
     * Collect anonymous stats about Deployer usage for improving developer experience.
358
     * If you are not comfortable with this, you will always be able to disable this
359
     * by setting `allow_anonymous_stats` to false in your deploy.php file.
360
     *
361
     * @param CommandEvent $commandEvent
362
     * @codeCoverageIgnore
363
     */
364
    public function collectAnonymousStats(CommandEvent $commandEvent)
365
    {
366
        if ($this->config->has('allow_anonymous_stats') && $this->config['allow_anonymous_stats'] === false) {
367
            return;
368
        }
369
370
        $stats = [
371
            'status' => 'success',
372
            'command_name' => $commandEvent->getCommand()->getName(),
373
            'project_hash' => empty($this->config['repository']) ? null : sha1($this->config['repository']),
374
            'hosts_count' => $this->hosts->count(),
375
            'deployer_version' => $this->getConsole()->getVersion(),
376
            'deployer_phar' => self::isPharArchive(),
377
            'php_version' => phpversion(),
378
            'extension_pcntl' => extension_loaded('pcntl'),
379
            'extension_curl' => extension_loaded('curl'),
380
            '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))),
381
            'exception' => null,
382
        ];
383
384
        if ($commandEvent->getException() !== null) {
385
            $stats['status'] = 'error';
386
            $stats['exception'] = get_class($commandEvent->getException());
387
        }
388
389
        if ($stats['command_name'] === 'init') {
390
            $stats['allow_anonymous_stats'] = $GLOBALS['allow_anonymous_stats'] ?? false;
391
        }
392
393
        if (in_array($stats['command_name'], ['worker', 'list', 'help'], true)) {
394
            return;
395
        }
396
397
        Reporter::report($stats);
398
    }
399
400 12
    public static function isPharArchive()
401
    {
402 12
        return 'phar:' === substr(__FILE__, 0, 5);
403
    }
404
}
405