Issues (11)

src/MystemBinaryInstaller.php (5 issues)

Labels
Severity
1
<?php
2
3
use Composer\Composer;
4
use Composer\IO\IOInterface;
5
use Composer\Installer\InstallationManager;
6
use Composer\DependencyResolver\Operation\InstallOperation;
7
use Composer\Repository\WritableRepositoryInterface;
8
use Composer\Script\Event;
9
use Composer\Package\Package;
10
11
class MystemBinaryInstaller
12
{
13
14
    /**
15
     * @var Composer $composer
0 ignored issues
show
The type Composer\Composer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
     */
17
    public static $composer;
18
19
    /**
20
     * @var IOInterface $io
0 ignored issues
show
The type Composer\IO\IOInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
     */
22
    public static $io;
23
24
    /**
25
     * @var InstallationManager $installer
0 ignored issues
show
The type Composer\Installer\InstallationManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
     */
27
    public static $installer;
28
29
    /**
30
     * @var WritableRepositoryInterface $localRepo
0 ignored issues
show
The type Composer\Repository\WritableRepositoryInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
     */
32
    public static $localRepo;
33
34
    /**
35
     * @var array $config
36
     */
37
    public static $config;
38
39
    /**
40
     * @var Package[] platform-specific packages to install
41
     */
42
    public static $toInstall = array();
43
44
    public static function init(Event $event)
45
    {
46
        self::$composer = $event->getComposer();
47
        self::$io = $event->getIO();
48
        self::$installer = $event->getComposer()->getInstallationManager();
49
        self::$localRepo = $event->getComposer()->getRepositoryManager()->getLocalRepository();
50
51
        $fileName = __DIR__ . '/composer-platform-specific.json';
52
        if (!file_exists($fileName)) {
53
            self::$io->write("<error>File $fileName not exists.</error>");
54
            return false;
55
        }
56
        $content = file_get_contents($fileName);
57
        if (!$content) {
58
            self::$io->write("<error>Can't read $fileName file.</error>");
59
            return false;
60
        }
61
        self::$config = (array)json_decode($content, true);
62
63
        if (!isset(self::$config['extra']['platform-specific-packages'])) {
64
            return false;
65
        }
66
67
        //@TODO: refactor it all to use composer.lock file, to track updated platform-specific packages
68
        self::$toInstall = array();
69
70
        $unresolved = array();
71
        foreach (self::$config['extra']['platform-specific-packages'] as $name => $variants) {
72
            $package = self::createPlatformSpecificPackage($name, $variants);
73
            if ($package) {
74
                self::$toInstall[] = $package;
75
            } else {
76
                $unresolved[] = $name;
77
            }
78
        }
79
80
        if (!empty($unresolved)) {
81
            self::$io->write(
82
                '<error>Your requirements could not be resolved for current OS and/or processor architecture.</error>'
83
            );
84
            self::$io->write("\n  Unresolved platform-specific packages:");
85
            foreach ($unresolved as $name) {
86
                self::$io->write("    - $name");
87
            }
88
        }
89
90
        return true;
91
    }
92
93
    public static function install(Event $event)
94
    {
95
96
        if (!self::init($event)) {
97
            return;
98
        }
99
100
        $notInstalled = 0;
101
        if (!empty(self::$toInstall)) {
102
            self::$io->write('<info>Installing platform-specific dependencies</info>');
103
            foreach (self::$toInstall as $package) {
104
                if (!self::$installer->isPackageInstalled(self::$localRepo, $package)) {
105
                    self::$installer->install(self::$localRepo, new InstallOperation($package));
106
                    self::updateBinary($package);
107
                } else {
108
                    $notInstalled++;
109
                }
110
            }
111
        }
112
        if (empty(self::$toInstall) || $notInstalled > 0) {
113
            self::$io->write('Nothing to install or update in platform-specific dependencies');
114
        }
115
    }
116
117
    public static function update(Event $event)
118
    {
119
        //@TODO: update changed packages
120
        self::install($event);
121
    }
122
123
    public static function updateBinary(Package $package)
124
    {
125
        $binaries = $package->getBinaries();
126
        if (isset($binaries[0]) && self::getOS() !== 'windows') {
127
            $binDir = rtrim(self::$composer->getConfig()->get('bin-dir'), '/') . '/';
128
            if (!@chmod($binDir . 'mystem', 0555)) {
129
                throw new Exception("Can't chmod binary file '{$binDir}mystem'");
130
            }
131
        }
132
    }
133
134
    /**
135
     * @param string $packageName
136
     * @param array $variants
137
     * @return null|Package
0 ignored issues
show
The type Composer\Package\Package was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
138
     */
139
    protected static function createPlatformSpecificPackage($packageName, $variants)
140
    {
141
        foreach ($variants as $variant) {
142
            if (!empty($variant['architecture']) && $variant['architecture'] !== self::getArchitecture()) {
143
                continue;
144
            }
145
146
            if (!empty($variant['os']) && $variant['os'] !== self::getOS()) {
147
                continue;
148
            }
149
150
            reset($variant);
151
            $name = key($variant);
152
            $version = $variant[$name];
153
154
            return self::createPackage($name, $version, $packageName);
155
        }
156
157
        return null;
158
    }
159
160
    /**
161
     * @param string $name
162
     * @param string $version
163
     * @param string $newName
164
     * @return null|Package
165
     */
166
    protected static function createPackage($name, $version, $newName)
167
    {
168
        if (!isset(self::$config['repositories'])) {
169
            return null;
170
        }
171
        $package = null;
172
        foreach (self::$config['repositories'] as $cursor) {
173
            if (isset($cursor['package']['name'], $cursor['package']['version']) &&
174
                $cursor['package']['name'] === $name &&
175
                ($version === '*' || $cursor['package']['version'] === $version)
176
            ) {
177
                $package = $cursor['package'];
178
                break;
179
            }
180
        }
181
        if (!$package) {
182
            return null;
183
        }
184
        $new = self::bindPackageValues($newName, $package);
185
        self::$localRepo->addPackage($new);
186
        return $new;
187
    }
188
189
    /**
190
     * @param string $newName
191
     * @param array $package
192
     * @return Package
193
     */
194
    protected static function bindPackageValues($newName, array $package)
195
    {
196
        $new = new Package($newName, $package['version'], $package['version']);
197
        $new->setType('dist');
198
        if (isset($package['bin'])) {
199
            $new->setBinaries($package['bin']);
200
        }
201
        if (isset($package['dist']['type'])) {
202
            $new->setDistType($package['dist']['type']);
203
        }
204
        if (isset($package['dist']['url'])) {
205
            $new->setDistUrl($package['dist']['url']);
206
        }
207
        if (isset($package['excludes'])) {
208
            $new->setArchiveExcludes($package['excludes']);
209
        }
210
        return $new;
211
    }
212
213
    /**
214
     * Returns the Operating System.
215
     *
216
     * @return string OS, e.g. macosx, freebsd, windows, linux.
217
     */
218
    public static function getOS()
219
    {
220
        $uname = strtolower(php_uname());
221
222
        if (strpos($uname, "darwin") !== false) {
223
            return 'macosx';
224
        } elseif (strpos($uname, "win") !== false) {
225
            return 'windows';
226
        } elseif (strpos($uname, "freebsd") !== false) {
227
            return 'freebsd';
228
        } elseif (strpos($uname, "linux") !== false) {
229
            return 'linux';
230
        } else {
231
            return 'undefined';
232
        }
233
    }
234
235
    /**
236
     * Returns the Architecture.
237
     *
238
     * @return string BitSize, e.g. i386, x64.
239
     */
240
    public static function getArchitecture()
241
    {
242
        switch (PHP_INT_SIZE) {
243
            case 4:
244
                return 'i386';
245
            case 8:
246
                return 'x64';
247
            default:
248
                return 'undefined';
249
        }
250
    }
251
}
252