Completed
Push — master ( 6e27f1...d5fec2 )
by Nicolas
03:36
created

Installer::getRepoUrl()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
nc 7
nop 0
dl 0
loc 32
ccs 0
cts 23
cp 0
crap 56
rs 8.4746
c 0
b 0
f 0
1
<?php
2
3
namespace Nwidart\Modules\Process;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Str;
7
use Nwidart\Modules\Contracts\RepositoryInterface;
8
use Symfony\Component\Process\Process;
9
10
class Installer
11
{
12
    /**
13
     * The module name.
14
     *
15
     * @var string
16
     */
17
    protected $name;
18
19
    /**
20
     * The version of module being installed.
21
     *
22
     * @var string
23
     */
24
    protected $version;
25
26
    /**
27
     * The module repository instance.
28
     * @var \Nwidart\Modules\Contracts\RepositoryInterface
29
     */
30
    protected $repository;
31
32
    /**
33
     * The console command instance.
34
     *
35
     * @var \Illuminate\Console\Command
36
     */
37
    protected $console;
38
39
    /**
40
     * The destionation path.
41
     *
42
     * @var string
43
     */
44
    protected $path;
45
46
    /**
47
     * The process timeout.
48
     *
49
     * @var int
50
     */
51
    protected $timeout = 3360;
52
    /**
53
     * @var null|string
54
     */
55
    private $type;
56
    /**
57
     * @var bool
58
     */
59
    private $tree;
60
61
    /**
62
     * The constructor.
63
     *
64
     * @param string $name
65
     * @param string $version
66
     * @param string $type
67
     * @param bool   $tree
68
     */
69
    public function __construct($name, $version = null, $type = null, $tree = false)
70
    {
71
        $this->name = $name;
72
        $this->version = $version;
73
        $this->type = $type;
74
        $this->tree = $tree;
75
    }
76
77
    /**
78
     * Set destination path.
79
     *
80
     * @param string $path
81
     *
82
     * @return $this
83
     */
84
    public function setPath($path)
85
    {
86
        $this->path = $path;
87
88
        return $this;
89
    }
90
91
    /**
92
     * Set the module repository instance.
93
     * @param \Nwidart\Modules\Contracts\RepositoryInterface $repository
94
     * @return $this
95
     */
96
    public function setRepository(RepositoryInterface $repository)
97
    {
98
        $this->repository = $repository;
99
100
        return $this;
101
    }
102
103
    /**
104
     * Set console command instance.
105
     *
106
     * @param \Illuminate\Console\Command $console
107
     *
108
     * @return $this
109
     */
110
    public function setConsole(Command $console)
111
    {
112
        $this->console = $console;
113
114
        return $this;
115
    }
116
117
    /**
118
     * Set process timeout.
119
     *
120
     * @param int $timeout
121
     *
122
     * @return $this
123
     */
124
    public function setTimeout($timeout)
125
    {
126
        $this->timeout = $timeout;
127
128
        return $this;
129
    }
130
131
    /**
132
     * Run the installation process.
133
     *
134
     * @return \Symfony\Component\Process\Process
135
     */
136
    public function run()
137
    {
138
        $process = $this->getProcess();
139
140
        $process->setTimeout($this->timeout);
141
142
        if ($this->console instanceof Command) {
0 ignored issues
show
Bug introduced by
The class Illuminate\Console\Command does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
143
            $process->run(function ($type, $line) {
144
                $this->console->line($line);
145
            });
146
        }
147
148
        return $process;
149
    }
150
151
    /**
152
     * Get process instance.
153
     *
154
     * @return \Symfony\Component\Process\Process
155
     */
156
    public function getProcess()
157
    {
158
        if ($this->type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->type of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
159
            if ($this->tree) {
160
                return $this->installViaSubtree();
161
            }
162
163
            return $this->installViaGit();
164
        }
165
166
        return $this->installViaComposer();
167
    }
168
169
    /**
170
     * Get destination path.
171
     *
172
     * @return string
173
     */
174
    public function getDestinationPath()
175
    {
176
        if ($this->path) {
177
            return $this->path;
178
        }
179
180
        return $this->repository->getModulePath($this->getModuleName());
181
    }
182
183
    /**
184
     * Get git repo url.
185
     *
186
     * @return string|null
187
     */
188
    public function getRepoUrl()
189
    {
190
        switch ($this->type) {
191
            case 'github':
192
                return "[email protected]:{$this->name}.git";
193
194
            case 'github-https':
195
                return "https://github.com/{$this->name}.git";
196
197
            case 'gitlab':
198
                return "[email protected]:{$this->name}.git";
199
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
200
201
            case 'bitbucket':
202
                return "[email protected]:{$this->name}.git";
203
204
            default:
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
205
206
                // Check of type 'scheme://host/path'
207
                if (filter_var($this->type, FILTER_VALIDATE_URL)) {
208
                    return $this->type;
209
                }
210
211
                // Check of type 'user@host'
212
                if (filter_var($this->type, FILTER_VALIDATE_EMAIL)) {
213
                    return "{$this->type}:{$this->name}.git";
214
                }
215
216
                return;
217
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
218
        }
219
    }
220
221
    /**
222
     * Get branch name.
223
     *
224
     * @return string
225
     */
226
    public function getBranch()
227
    {
228
        return is_null($this->version) ? 'master' : $this->version;
229
    }
230
231
    /**
232
     * Get module name.
233
     *
234
     * @return string
235
     */
236
    public function getModuleName()
237
    {
238
        $parts = explode('/', $this->name);
239
240
        return Str::studly(end($parts));
241
    }
242
243
    /**
244
     * Get composer package name.
245
     *
246
     * @return string
247
     */
248
    public function getPackageName()
249
    {
250
        if (is_null($this->version)) {
251
            return $this->name . ':dev-master';
252
        }
253
254
        return $this->name . ':' . $this->version;
255
    }
256
257
    /**
258
     * Install the module via git.
259
     *
260
     * @return \Symfony\Component\Process\Process
261
     */
262 View Code Duplication
    public function installViaGit()
263
    {
264
        return new Process(sprintf(
265
            'cd %s && git clone %s %s && cd %s && git checkout %s',
266
            base_path(),
267
            $this->getRepoUrl(),
268
            $this->getDestinationPath(),
269
            $this->getDestinationPath(),
270
            $this->getBranch()
271
        ));
272
    }
273
274
    /**
275
     * Install the module via git subtree.
276
     *
277
     * @return \Symfony\Component\Process\Process
278
     */
279 View Code Duplication
    public function installViaSubtree()
280
    {
281
        return new Process(sprintf(
282
            'cd %s && git remote add %s %s && git subtree add --prefix=%s --squash %s %s',
283
            base_path(),
284
            $this->getModuleName(),
285
            $this->getRepoUrl(),
286
            $this->getDestinationPath(),
287
            $this->getModuleName(),
288
            $this->getBranch()
289
        ));
290
    }
291
292
    /**
293
     * Install the module via composer.
294
     *
295
     * @return \Symfony\Component\Process\Process
296
     */
297
    public function installViaComposer()
298
    {
299
        return new Process(sprintf(
300
            'cd %s && composer require %s',
301
            base_path(),
302
            $this->getPackageName()
303
        ));
304
    }
305
}
306