Completed
Push — master ( 7a70a9...536f20 )
by Andrii
02:06
created

src/PackageManager.php (2 issues)

Labels
Severity

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
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\CompletePackage;
16
17
/**
18
 * Abstract package manager class.
19
 *
20
 * @author Andrii Vasyliev <[email protected]>
21
 */
22
abstract class PackageManager
23
{
24
    /**
25
     * The plugin.
26
     * @var Plugin
27
     */
28
    protected $plugin;
29
30
    /**
31
     * Package manager name: bower or npm.
32
     * @var string
33
     */
34
    protected $name;
35
36
    /**
37
     * Package config file: bower.json or package.json
38
     * @var string
39
     */
40
    public $file;
41
42
    /**
43
     * Path to package manager binary.
44
     * @var string
45
     */
46
    public $bin;
47
48
    /**
49
     * Package name of PHP version of package manager.
50
     * @var string
51
     */
52
    public $phpPackage;
53
54
    /**
55
     * Binary name of PHP version of package manager.
56
     * @var string
57
     */
58
    protected $phpBin;
59
60
    /**
61
     * Package config. Initially holds default config.
62
     */
63
    protected $config = [];
64
65
    /**
66
     * Conversion table.
67
     * @var string
68
     */
69
    protected $keyTable = [
70
        'require'     => 'dependencies',
71
        'require-dev' => 'devDependencies',
72
    ];
73
74
    /**
75
     * Reads config file or dist config if exists, merges with default config.
76
     */
77
    public function __construct(Plugin $plugin)
78
    {
79
        $this->plugin = $plugin;
80
        $dist = $this->file . '.dist';
81
        $this->config = array_merge(
82
            $this->config,
83
            $this->readConfig(file_exists($dist) ? $dist : $this->file)
84
        );
85
    }
86
87
    public function readConfig($file)
88
    {
89
        $jsonFile = new JsonFile($file);
90
        $config = $jsonFile->exists() ? $jsonFile->read() : [];
91
        foreach ($this->keyTable as $key) {
0 ignored issues
show
The expression $this->keyTable of type string is not traversable.
Loading history...
92
            if (!isset($config[$key])) {
93
                $config[$key] = [];
94
            }
95
        }
96
        return $config;
97
    }
98
99
    public function writeConfig($file, $config)
100
    {
101
        foreach ($this->keyTable as $key) {
0 ignored issues
show
The expression $this->keyTable of type string is not traversable.
Loading history...
102
            if (isset($config[$key]) && !$config[$key]) {
103
                unset($config[$key]);
104
            }
105
        }
106
        $jsonFile = new JsonFile($file);
107
        $jsonFile->write($config);
108
    }
109
110
    public function scanPackage(CompletePackage $package)
111
    {
112
        $extra = $package->getExtra();
113
        $config = [];
114
        foreach (['require', 'require-dev'] as $key) {
115
            $name = $this->name . '-' . $key;
116
            if (isset($extra[$name])) {
117
                $config[$key] = $extra[$name];
118
            }
119
        }
120
        if ($config) {
121
            $this->mergeConfig($config);
122
        }
123
    }
124
125
    protected function mergeConfig($config)
126
    {
127
        foreach ($config as $key => $packages) {
128
            $key = $this->keyTable[$key];
129
            foreach ($packages as $name => $version) {
130
                $this->config[$key][$name] = isset($this->config[$key][$name])
131
                    ? $this->mergeVersions($this->config[$key][$name], $version)
132
                    : $version;
133
            }
134
        }
135
    }
136
137
    protected function mergeVersions($a, $b)
138
    {
139
        $a = trim($a);
140
        $b = trim($b);
141
        if ($a === $b || $this->isMoreVersion($b, $a)) {
142
            return $a;
143
        } elseif ($this->isMoreVersion($a, $b)) {
144
            return $b;
145
        } else {
146
            return $a . ' ' . $b;
147
        }
148
    }
149
150
    /**
151
     * Check if $a is more then $b, like: a="1.1 || 2.2" b="1.1"
152
     * Possible optimization.
153
     */
154
    public function isMoreVersion($a, $b)
155
    {
156
        return $this->isAnyVersion($a);
157
        // WRONG: return strpos($b, $a) !== false;
158
    }
159
160
    public function isAnyVersion($version)
161
    {
162
        return !$version || $version === '*' || $version === '>=0.0.0';
163
    }
164
165
    public function setConfig(array $config)
166
    {
167
        $this->config = $config;
168
    }
169
170
    /**
171
     * Install packages.
172
     */
173
    public function installPackages()
174
    {
175
        $this->plugin->io->write('installing ' . $this->name . ' dependencies...');
176
        $this->writeConfig($this->file, $this->config);
177
        $this->runInstall();
178
    }
179
180
    /**
181
     * Run installation. Specific for every package manager.
182
     */
183
    abstract protected function runInstall();
184
185
    /**
186
     * Prepares given command arguments.
187
     * @param string|array $args
188
     * @return string
189
     */
190
    public function prepareCommand($args = '')
191
    {
192
        if (is_string($args)) {
193
            $res = ' ' . trim($args);
194
        } else {
195
            $res = '';
196
            foreach ($args as $a) {
197
                $res .= ' ' . escapeshellarg($a);
198
            }
199
        }
200
201
        return $res;
202
    }
203
204
    /**
205
     * Prepares arguments and runs it with passthru.
206
     * @param string $args
207
     * @return int exit code
208
     */
209
    public function passthru($args = '')
210
    {
211
        passthru($this->getBin() . $this->prepareCommand($args), $exitcode);
212
        return $exitcode;
213
    }
214
215
    /**
216
     * Set path to binary.
217
     * @param string $value
218
     */
219
    public function setBin($value)
220
    {
221
        $this->bin = $value;
222
    }
223
224
    /**
225
     * Get path to binary.
226
     * @return string
227
     */
228
    public function getBin()
229
    {
230
        if ($this->bin === null) {
231
            $this->bin = $this->detectBin();
232
        }
233
234
        return $this->bin;
235
    }
236
237
    /**
238
     * Find path binary.
239
     * @return string
240
     */
241
    public function detectBin()
242
    {
243
        if (isset($this->plugin->getPackages()[$this->phpPackage])) {
244
            return './vendor/bin/' . $this->phpBin;
245
        }
246
247
        return $this->name;
248
    }
249
}
250