SelfUpdateCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the dotfiles project.
7
 *
8
 *     (c) Anthonius Munthi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Dotfiles\Core\Command;
15
16
use Dotfiles\Core\Application;
17
use Dotfiles\Core\Config\Config;
18
use Dotfiles\Core\Exceptions\InstallFailedException;
19
use Dotfiles\Core\Util\Downloader;
20
use Dotfiles\Core\Util\Toolkit;
21
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Dotfiles\Core\Command\Command. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use Symfony\Component\Filesystem\Filesystem;
25
26
class SelfUpdateCommand extends Command implements CommandInterface
27
{
28
    public const BASE_URL = 'https://raw.githubusercontent.com/dotfilesphp/dotfiles/phar';
29
30
    /**
31
     * @var string
32
     */
33
    private $branchAlias;
34
35
    /**
36
     * @var string
37
     */
38
    private $cacheDir;
39
40
    /**
41
     * @var Config
42
     */
43
    private $config;
44
45
    /**
46
     * @var string
47
     */
48
    private $date;
49
50
    /**
51
     * @var Downloader
52
     */
53
    private $downloader;
54
55
    /**
56
     * @var string
57
     */
58
    private $pharFile;
59
60
    /**
61
     * @var string
62
     */
63
    private $tempDir;
64
65
    /**
66
     * @var string
67
     */
68
    private $version;
69
70
    /**
71
     * @var string
72
     */
73
    private $versionFile;
74
75
    public function __construct(
76
        ?string $name = null,
77
        Downloader $downloader,
78
        Config $config
79
    ) {
80
        parent::__construct($name);
81
82
        $this->config = $config;
83
        $this->downloader = $downloader;
84
        $this->tempDir = $config->get('dotfiles.temp_dir');
85
        $this->cacheDir = $config->get('dotfiles.cache_dir');
86
    }
87
88
    protected function configure(): void
89
    {
90
        $this
91
            ->setName('self-update')
92
            ->setAliases(array('selfupdate'))
93
        ;
94
    }
95
96
    /**
97
     * @param InputInterface  $input
98
     * @param OutputInterface $output
99
     *
100
     * @throws InstallFailedException when version file is invalid
101
     */
102
    protected function execute(InputInterface $input, OutputInterface $output): void
103
    {
104
        $config = $this->config;
105
        $tempDir = $config->get('dotfiles.temp_dir');
106
107
        $output->writeln('Start checking new version');
108
        $url = static::BASE_URL.'/dotfiles.phar.json';
109
        $versionFile = $tempDir.'/update/dotfiles.phar.json';
110
        Toolkit::ensureFileDir($versionFile);
111
        $downloader = $this->downloader;
112
        $downloader->run($url, $versionFile);
113
        $contents = file_get_contents($versionFile);
114
        if ('' === trim($contents)) {
115
            throw new InstallFailedException('Can not parse dotfiles.phar.json file');
116
        }
117
        $json = json_decode($contents, true);
118
119
        $this->versionFile = $versionFile;
120
        $this->version = $json['version'];
121
        $this->branchAlias = $json['branch'];
122
        $this->date = $json['date'];
123
124
        if (Application::VERSION !== $this->version) {
125
            $output->writeln("Begin update into <comment>{$this->version}</comment>");
126
            $this->doUpdate($output);
127
            $this->getApplication()->get('clear-cache')->run($input, $output);
128
        } else {
129
            $output->writeln('You already have latest <comment>dotfiles</comment> version');
130
        }
131
    }
132
133
    private function doUpdate(OutputInterface $output): void
134
    {
135
        $fs = new Filesystem();
136
        $tempDir = $this->tempDir.'/update/'.$this->version;
137
        $fs->copy($this->versionFile, $tempDir.DIRECTORY_SEPARATOR.'VERSION');
138
139
        $targetFile = $tempDir.DIRECTORY_SEPARATOR.'dotfiles.phar';
140
        if (!is_file($targetFile)) {
141
            $url = static::BASE_URL.'/dotfiles.phar';
142
            $downloader = $this->downloader;
143
            $downloader->getProgressBar()->setFormat('Download <comment>dotfiles.phar</comment>: <comment>%percent:3s%%</comment> <info>%estimated:-6s%</info>');
144
            $downloader->run($url, $targetFile);
145
        }
146
147
        $this->pharFile = $targetFile;
148
        $cacheDir = $this->cacheDir;
149
150
        // copy current phar into new dir
151
        // we can't coverage or test phar environment
152
        //@codeCoverageIgnoreStart
153
        $current = \Phar::running(false);
154
        $output->writeln($current);
155
        if (is_file($current)) {
156
            $override = array('override' => true);
157
            $backup = $cacheDir.'/dotfiles_old.phar';
158
            $fs->copy($current, $backup, $override);
0 ignored issues
show
Bug introduced by
$override of type array<string,true> is incompatible with the type boolean expected by parameter $overwriteNewerFiles of Symfony\Component\Filesystem\Filesystem::copy(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

158
            $fs->copy($current, $backup, /** @scrutinizer ignore-type */ $override);
Loading history...
159
            $fs->copy($this->pharFile, $current, $override);
160
            $output->writeln('Your <comment>dotfiles.phar</comment> is updated.');
161
        }
162
        //@codeCoverageIgnoreEnd
163
    }
164
}
165