Completed
Push — master ( 84ba14...b9d126 )
by Andrii
02:15
created

PackageManager::hasDependencies()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.0741

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.2
cc 4
eloc 5
nc 3
nop 0
crap 4.0741
1
<?php
2
3
/*
4
 * Composer plugin for bower/npm assets
5
 *
6
 * @link      https://github.com/hiqdev/composer-asset-plugin
7
 * @package   composer-asset-plugin
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\composerassetplugin;
13
14
use Composer\Json\JsonFile;
15
use Composer\Package\CompletePackageInterface;
16
17
/**
18
 * Abstract package manager class.
19
 *
20
 * @author Andrii Vasyliev <[email protected]>
21
 */
22
abstract class PackageManager
23
{
24
    /**
25
     * @var Plugin the plugin instance
26
     */
27
    protected $plugin;
28
29
    /**
30
     * @var string Package manager name: `bower` or `npm`
31
     */
32
    protected $name;
33
34
    /**
35
     * @var string Package config file name: `bower.json` or `package.json`
36
     */
37
    public $file;
38
39
    /**
40
     * @var string Path to package manager binary
41
     */
42
    public $bin;
43
44
    /**
45
     * @var string Package name of the PHP version of the package manager
46
     */
47
    public $phpPackage;
48
49
    /**
50
     * @var string Binary name of PHP version of package manager
51
     */
52
    protected $phpBin;
53
54
    /**
55
     * @var array Package config. Initially holds default config
56
     */
57
    protected $config = [];
58
59
    /**
60
     * @var array List of keys holding dependencies
61
     */
62
    protected $dependencies = ['dependencies', 'devDependencies'];
63
64
    /**
65
     * Reads config file or dist config if exists, merges with default config.
66
     * @param Plugin $plugin
67
     * @void
68
     */
69 3
    public function __construct(Plugin $plugin)
70
    {
71 3
        $this->plugin = $plugin;
72
        //$dist = $this->file . '.dist';
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
73 3
        $this->config = array_merge(
74 3
            $this->config,
75 3
            $this->readConfig($this->file)
76
            //$this->readConfig(file_exists($dist) ? $dist : $this->file)
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
77 3
        );
78 3
    }
79
80
    /**
81
     * Reads the JSON config from the $path.
82
     *
83
     * @param string $path path to the Json file
84
     * @return array|mixed
85
     */
86 3
    public function readConfig($path)
87
    {
88 3
        $jsonFile = new JsonFile($path);
89 3
        $config = $jsonFile->exists() ? $jsonFile->read() : [];
90 3
        foreach ($this->dependencies as $key) {
91 3
            if (!isset($config[$key])) {
92 3
                $config[$key] = [];
93 3
            }
94 3
        }
95 3
        return $config;
96
    }
97
98
    /**
99
     * Saves JSON config to the given path.
100
     *
101
     * @param string $path
102
     * @param array $config
103
     * @throws \Exception
104
     */
105
    public function writeConfig($path, array $config)
106
    {
107
        foreach ($this->dependencies as $key) {
108
            if (isset($config[$key]) && !$config[$key]) {
109
                unset($config[$key]);
110
            }
111
        }
112
        $jsonFile = new JsonFile($path);
113
        $jsonFile->write($config);
114
    }
115
116
    /**
117
     * Scans the $package and extracts dependencies to the [[config]].
118
     *
119
     * @param CompletePackageInterface $package
120
     * @see mergeConfig()
121
     * @void
122
     */
123
    public function scanPackage(CompletePackageInterface $package)
124
    {
125
        $extra = $package->getExtra();
126
        $config = [];
127
        foreach ($this->dependencies as $key) {
128
            $name = $this->name . '-' . $key;
129
            if (isset($extra[$name])) {
130
                $config[$key] = $extra[$name];
131
            }
132
        }
133
        if (!empty($config)) {
134
            $this->mergeConfig($config);
135
        }
136
    }
137
138
    /**
139
     * Merges the $config over the [[config]], doesn't resolve version conflicts.
140
     * @param array $config
141
     * @see mergeVersions()
142
     * @void
143
     */
144
    protected function mergeConfig(array $config)
145
    {
146
        foreach ($config as $key => $packages) {
147
            foreach ($packages as $name => $version) {
148
                if (isset($this->config[$key][$name])) {
149
                    $this->config[$key][$name] = $this->mergeVersions($this->config[$key][$name], $version);
150
                } else {
151
                    $this->config[$key][$name] = $version;
152
                }
153
            }
154
        }
155
    }
156
157
    /**
158
     * @param $a
159
     * @param $b
160
     * @return string
161
     */
162
    protected function mergeVersions($a, $b)
163
    {
164
        $a = trim($a);
165
        $b = trim($b);
166
167
        if ($a === $b || $this->isMoreVersion($b, $a)) {
168
            return $a;
169
        } elseif ($this->isMoreVersion($a, $b)) {
170
            return $b;
171
        } else {
172
            return $a . ' ' . $b;
173
        }
174
    }
175
176
    /**
177
     * Check if $a is more then $b, like: a="1.1 || 2.2" b="1.1"
178
     * Possible optimization.
179
     * // TODO Rename and implement.
180
     * @param string $a
181
     * @param string $b
182
     * @return boolean
183
     */
184
    public function isMoreVersion($a, $b)
0 ignored issues
show
Unused Code introduced by
The parameter $b is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
185
    {
186
        return $this->isAnyVersion($a);
187
    }
188
189
    /**
190
     * Checks whether the $version represents any possible version.
191
     *
192
     * @param string $version
193
     * @return boolean
194
     */
195
    public function isAnyVersion($version)
196
    {
197
        return $version === '' || $version === '*' || $version === '>=0.0.0';
198
    }
199
200
    /**
201
     * Set config.
202
     * @param array $config
203
     */
204
    public function setConfig(array $config)
205
    {
206
        $this->config = $config;
207
    }
208
209
    /**
210
     * Returns if the package manager has nonempty dependency list.
211
     * @return bool
212
     */
213 1
    public function hasDependencies()
214
    {
215 1
        foreach ($this->dependencies as $key) {
216 1
            if (isset($this->config[$key]) && $this->config[$key]) {
217
                return true;
218
            }
219 1
        }
220
221 1
        return false;
222
    }
223
224
    /**
225
     * Run the given action: show notice, write config and run `perform`.
226
     * @param string $action the action name
227
     * @void
228
     */
229
    public function runAction($action)
230
    {
231
        $doing = ucfirst(trim($action, 'e')) . 'ing';
232
        $this->plugin->io->writeError('<info>' . $doing . ' ' . $this->name . ' dependencies...</info>');
233
        $this->writeConfig($this->file, $this->config);
234
        $this->perform($action);
235
    }
236
237
    /**
238
     * Run installation. Specific for every package manager.
239
     * @param string $action the action name
240
     * @void
241
     */
242
    protected function perform($action)
243
    {
244
        if ($this->passthru([$action])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->passthru(array($action)) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
245
            $this->plugin->io->writeError('<error>failed ' . $this->name . ' ' . $action . '</error>');
246
        }
247
    }
248
249
    /**
250
     * Prepares arguments and runs the command with [[passthru()]].
251
     * @param array $arguments
252
     * @return integer the exit code
253
     */
254
    public function passthru(array $arguments = [])
255
    {
256
        passthru($this->getBin() . $this->prepareCommand($arguments), $exitCode);
257
        return $exitCode;
258
    }
259
260
    /**
261
     * Prepares given command arguments.
262
     * @param array $arguments
263
     * @return string
264
     */
265
    public function prepareCommand(array $arguments = [])
266
    {
267
        $result = '';
268
        foreach ($arguments as $a) {
269
            $result .= ' ' . escapeshellarg($a);
270
        }
271
272
        return $result;
273
    }
274
275
    /**
276
     * Set path to binary executable file.
277
     * @param $bin
278
     * @internal param string $value
279
     */
280
    public function setBin($bin)
281
    {
282
        $this->bin = $bin;
283
    }
284
285
    /**
286
     * Get path to the binary executable file.
287
     * @return string
288
     */
289
    public function getBin()
290
    {
291
        if ($this->bin === null) {
292
            $this->bin = $this->detectBin();
293
        }
294
295
        return $this->bin;
296
    }
297
298
    /**
299
     * Find path to the binary.
300
     * @return string
301
     */
302
    public function detectBin()
303
    {
304
        if (isset($this->plugin->getPackages()[$this->phpPackage])) {
305
            return $this->plugin->getVendorDir() . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . $this->phpBin;
306
        }
307
308
        return $this->name;
309
    }
310
}
311