Binary   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Importance

Changes 17
Bugs 3 Features 3
Metric Value
wmc 37
eloc 98
c 17
b 3
f 3
dl 0
loc 205
rs 9.44

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __destruct() 0 3 1
A packLog() 0 11 2
F create() 0 80 20
A readPackage() 0 11 1
A getMultiExtensionNames() 0 19 4
A composerJsonBak() 0 15 6
A getZipBaseName() 0 11 2
1
<?php
2
3
/*
4
 * Pickle
5
 *
6
 *
7
 * @license
8
 *
9
 * New BSD License
10
 *
11
 * Copyright © 2015-2015, Pickle community. All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *     * Redistributions of source code must retain the above copyright
16
 *       notice, this list of conditions and the following disclaimer.
17
 *     * Redistributions in binary form must reproduce the above copyright
18
 *       notice, this list of conditions and the following disclaimer in the
19
 *       documentation and/or other materials provided with the distribution.
20
 *     * Neither the name of the Hoa nor the names of its contributors may be
21
 *       used to endorse or promote products derived from this software without
22
 *       specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 * POSSIBILITY OF SUCH DAMAGE.
35
 */
36
37
namespace Pickle\Package\PHP\Command\Release\Windows;
38
39
use Closure;
40
use Exception;
41
use Pickle\Base\Archive;
42
use Pickle\Base\Interfaces;
43
use Pickle\Package\PHP\Util\PackageJson;
44
use Pickle\Package\Util\Header;
45
46
class Binary implements Interfaces\Package\Release
47
{
48
    /**
49
     * @var \Pickle\Base\Interfaces\Package
50
     */
51
    protected $pkg;
52
53
    /**
54
     * @var Closure
55
     */
56
    protected $cb;
57
58
    /**
59
     * @var bool
60
     */
61
    protected $noConvert = false;
62
63
    /**
64
     * @var Interfaces\Package\Build
65
     */
66
    protected $build;
67
68
    /**
69
     * Constructor.
70
     *
71
     * @param string $path
72
     * @param Closure $cb
73
     * @param bool $noConvert
74
     */
75
    public function __construct($path, $cb = null, $noConvert = false)
76
    {
77
        $this->pkg = $this->readPackage($path);
78
        $this->cb = $cb;
79
        $this->noConvert = $noConvert;
80
    }
81
82
    public function __destruct()
83
    {
84
        $this->composerJsonBak($this->pkg, true);
85
    }
86
87
    /**
88
     * Create package.
89
     */
90
    public function create(array $args = [])
91
    {
92
        if (!isset($args['build']) || !($args['build'] instanceof Interfaces\Package\Build)) {
93
            throw new Exception('Invalid or NULL object passed as Interfaces\\Package\\Build');
94
        }
95
        $this->build = $build = $args['build'];
96
97
        $info = $build->getInfo();
98
99
        $tmp_dir = $build->getTempDir();
0 ignored issues
show
Bug introduced by
The method getTempDir() does not exist on Pickle\Base\Interfaces\Package\Build. Since it exists in all sub-types, consider adding an abstract or default implementation to Pickle\Base\Interfaces\Package\Build. ( Ignorable by Annotation )

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

99
        /** @scrutinizer ignore-call */ 
100
        $tmp_dir = $build->getTempDir();
Loading history...
100
101
        $tmp = $build->getLog('configure');
0 ignored issues
show
Bug introduced by
The method getLog() does not exist on Pickle\Base\Interfaces\Package\Build. Since it exists in all sub-types, consider adding an abstract or default implementation to Pickle\Base\Interfaces\Package\Build. ( Ignorable by Annotation )

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

101
        /** @scrutinizer ignore-call */ 
102
        $tmp = $build->getLog('configure');
Loading history...
102
        $m = null;
103
        if (preg_match(',Build dir:\\s+([\\:\\-\\.0-9a-zA-Z\\\\_]+),', $tmp, $m)) {
104
            if (preg_match(',^[a-z]\\:\\\\,i', $m[1]) && is_dir($m[1])) {
105
                /* Parsed the fully qualified path */
106
                $build_dir = $m[1];
107
            } else {
108
                /* otherwise construct */
109
                $build_dir = $tmp_dir . DIRECTORY_SEPARATOR . $m[1];
110
            }
111
        } else {
112
            $build_dir = $info['arch'] == 'x86' ? $tmp_dir : $tmp_dir . DIRECTORY_SEPARATOR . 'x64';
113
            $build_dir .= DIRECTORY_SEPARATOR . (($info['is_release'] ?? true) ? 'Release' : 'Debug');
114
            $build_dir .= ($info['thread_safe'] ? '_TS' : '');
115
        }
116
117
        /* Various file paths to pack. */
118
        $composer_json = $this->pkg->getRootDir() . DIRECTORY_SEPARATOR . 'composer.json';
119
120
        if (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'LICENSE')) {
121
            $license = $tmp_dir . DIRECTORY_SEPARATOR . 'LICENSE';
122
        } elseif (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'COPYING')) {
123
            $license = $tmp_dir . DIRECTORY_SEPARATOR . 'COPYING';
124
        } elseif (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'LICENSE.md')) {
125
            $license = $tmp_dir . DIRECTORY_SEPARATOR . 'LICENSE.md';
126
        } elseif (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'COPYING.md')) {
127
            $license = $tmp_dir . DIRECTORY_SEPARATOR . 'COPYING.md';
128
        } else {
129
            throw new Exception("Couldn't find LICENSE");
130
        }
131
132
        $readme = null;
133
        if (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'README')) {
134
            $readme = $tmp_dir . DIRECTORY_SEPARATOR . 'README';
135
        } elseif (file_exists($tmp_dir . DIRECTORY_SEPARATOR . 'README.md')) {
136
            $readme = $tmp_dir . DIRECTORY_SEPARATOR . 'README.md';
137
        }
138
139
        /* pack the outcome */
140
        $zip_name = $this->getZipBaseName($build) . '.zip';
141
142
        $zipClass = Archive\Factory::getZipperClassName();
143
        $zip = new $zipClass($zip_name, Interfaces\Archive\Zipper::FLAG_CREATE_OVERWRITE);
144
        /** @var \Pickle\Base\Interfaces\Archive\Zipper $zip */
145
        $ext_dll_found = false;
146
        $ext_names = $this->getMultiExtensionNames();
147
        foreach ($ext_names as $ext_name) {
148
            $dll_file = $build_dir . DIRECTORY_SEPARATOR . 'php_' . $ext_name . '.dll';
149
150
            if (!file_exists($dll_file)) {
151
                continue;
152
            }
153
            $ext_dll_found = true;
154
            $zip->addFileWithoutPath($dll_file);
155
156
            $pdb_file = $build_dir . DIRECTORY_SEPARATOR . 'php_' . $ext_name . '.pdb';
157
            if (file_exists($pdb_file)) {
158
                $zip->addFileWithoutPath($pdb_file);
159
            }
160
        }
161
162
        if (!$ext_dll_found) {
163
            throw new Exception("Couldn't find extension DLL");
164
        }
165
166
        $zip->addFileWithoutPath($composer_json);
167
        $zip->addFileWithoutPath($license);
168
        if ($readme) {
169
            $zip->addFileWithoutPath($readme);
170
        }
171
    }
172
173
    public function packLog(?Interfaces\Package\Build $build = null)
174
    {
175
        if (!$build) {
176
            $build = $this->build;
177
        }
178
179
        $path = $this->getZipBaseName($build) . '-logs.zip';
180
181
        $build->packLog($path);
0 ignored issues
show
Bug introduced by
The method packLog() does not exist on Pickle\Base\Interfaces\Package\Build. Since it exists in all sub-types, consider adding an abstract or default implementation to Pickle\Base\Interfaces\Package\Build. ( Ignorable by Annotation )

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

181
        $build->/** @scrutinizer ignore-call */ 
182
                packLog($path);
Loading history...
182
183
        return realpath($path);
184
    }
185
186
    public function getMultiExtensionNames()
187
    {
188
        $info = $this->build->getInfo();
189
        $ext_names = [$info['name']];
190
191
        /* config.w32 can contain multiple EXTENTION definitions, which would lead to
192
         multiple DLLs be built. */
193
        $config_w32_path = $this->build->getPackage()->getSourceDir() . DIRECTORY_SEPARATOR . 'config.w32';
0 ignored issues
show
Bug introduced by
The method getPackage() does not exist on Pickle\Base\Interfaces\Package\Build. Since it exists in all sub-types, consider adding an abstract or default implementation to Pickle\Base\Interfaces\Package\Build. ( Ignorable by Annotation )

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

193
        $config_w32_path = $this->build->/** @scrutinizer ignore-call */ getPackage()->getSourceDir() . DIRECTORY_SEPARATOR . 'config.w32';
Loading history...
194
        $config_w32 = file_get_contents($config_w32_path);
195
        $m = null;
196
        if (preg_match_all("/EXTENSION\\s*\\(\\s*('|\")([a-z0-9_]+)('|\")\\s*,/Sm", $config_w32, $m, PREG_SET_ORDER)) {
197
            foreach ($m as $r) {
198
                if (!in_array($r[2], $ext_names)) {
199
                    $ext_names[] = $r[2];
200
                }
201
            }
202
        }
203
204
        return $ext_names;
205
    }
206
207
    protected function composerJsonBak(Interfaces\Package $pkg, $restore = false)
208
    {
209
        $composer_json_orig = $pkg->getRootDir() . DIRECTORY_SEPARATOR . 'composer.json';
210
        $composer_json_bak = $pkg->getRootDir() . DIRECTORY_SEPARATOR . '.composer.json.orig';
211
212
        if ($restore) {
213
            if (file_exists($composer_json_bak)) {
214
                if (!copy($composer_json_bak, $composer_json_orig)) {
215
                    throw new Exception('Failed to restore composer.json');
216
                }
217
            }
218
        } else {
219
            if (file_exists($composer_json_orig)) {
220
                if (!copy($composer_json_orig, $composer_json_bak)) {
221
                    throw new Exception('Failed to backup composer.json');
222
                }
223
            }
224
        }
225
    }
226
227
    protected function readPackage($path)
228
    {
229
        $package = PackageJson::readPackage($path, $this->noConvert);
230
        $this->composerJsonBak($package);
231
232
        /* For the binary release, json badly need the version informatio
233
           to show the meta info. If there's ever a binary release support
234
           for other platforms, this will need to be done, probably. */
235
        (new Header\Version($package))->updateJSON();
236
237
        return $package;
238
    }
239
240
    protected function getZipBaseName(Interfaces\Package\Build $build)
241
    {
242
        $info = $build->getInfo();
243
244
        return 'php_' . $info['name'] . '-'
245
            . $info['version'] . '-'
246
            . $info['php_major'] . '.'
247
            . $info['php_minor'] . '-'
248
            . ($info['thread_safe'] ? 'ts' : 'nts') . '-'
249
            . $info['compiler'] . '-'
250
            . $info['arch'];
251
    }
252
}
253
254
/* vim: set tabstop=4 shiftwidth=4 expandtab: fdm=marker */
255