Completed
Push — master ( bdb3d4...9f5e72 )
by Anatol
03:32
created

Binary::composerJsonBak()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 19
rs 8.8571
cc 6
eloc 11
nc 6
nop 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 Pickle\Base\Interfaces;
40
use Pickle\Package;
41
use Pickle\Package\PHP\Util\PackageXml;
42
use Pickle\Package\Util\Header;
43
44
class Binary implements Interfaces\Package\Release
45
{
46
    /**
47
     * @var \Pickle\Base\Interfaces\Package
48
     */
49
    protected $pkg = null;
50
51
    /*
52
     * @var Closure
53
     */
54
    protected $cb = null;
55
56
    /*
57
     * @var bool
58
     */
59
    protected $noConvert = false;
60
61
    /*
62
     * @var Interfaces\Package\Build
63
     */
64
    protected $build;
65
66
    /**
67
     * Constructor.
68
     *
69
     * @param string  $path
70
     * @param Closure $cb
71
     * @param bool    $noConvert
72
     */
73
    public function __construct($path, $cb = null, $noConvert = false)
74
    {
75
        $this->pkg = $this->readPackage($path);
76
        $this->cb = $cb;
77
        $this->noConvert = $noConvert;
78
    }
79
80
    public function __destruct()
81
    {
82
        $this->composerJsonBak($this->pkg, true);
83
    }
84
85
    protected function composerJsonBak(\Pickle\Base\Interfaces\Package $pkg, $restore = false)
86
    {
87
        $composer_json_orig = $pkg->getRootDir().DIRECTORY_SEPARATOR.'composer.json';
88
        $composer_json_bak = $pkg->getRootDir().DIRECTORY_SEPARATOR.'.composer.json.orig';
89
90
        if ($restore) {
91
            if (file_exists($composer_json_bak)) {
92
                if (!copy($composer_json_bak, $composer_json_orig)) {
93
                    throw new \Exception("Failed to restore composer.json");
94
                }
95
            }
96
        } else {
97
            if (file_exists($composer_json_orig)) {
98
                if (!copy($composer_json_orig, $composer_json_bak)) {
99
                    throw new \Exception("Failed to backup composer.json");
100
                }
101
            }
102
        }
103
    }
104
105
    protected function readPackage($path)
106
    {
107
        $jsonLoader = new Package\Util\JSON\Loader(new Package\Util\Loader());
108
        $package = null;
109
110
        if (file_exists($path.DIRECTORY_SEPARATOR.'composer.json')) {
111
            $package = $jsonLoader->load($path.DIRECTORY_SEPARATOR.'composer.json');
112
        }
113
114
        if (null === $package && $this->noConvert) {
115
            throw new \RuntimeException('XML package are not supported. Please convert it before install');
116
        }
117
118
        if (null === $package) {
119
            try {
120
                $loader = new Package\PHP\Util\XML\Loader(new Package\Util\Loader());
0 ignored issues
show
Unused Code introduced by
$loader is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
121
122
                $pkgXml = new PackageXml($path);
123
                $pkgXml->dump();
124
125
                $jsonPath = $pkgXml->getJsonPath();
126
127
                $package = $jsonLoader->load($jsonPath);
128
            } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Pickle\Package\PHP\Comma...lease\Windows\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
129
                /* pass for now, be compatible */
130
            }
131
        }
132
133
        if (null == $package) {
134
            /* Just ensure it's correct, */
135
            throw new \Exception("Couldn't read package info at '$path'");
136
        }
137
138
        $package->setRootDir(realpath($path));
139
140
        $this->composerJsonBak($package);
0 ignored issues
show
Compatibility introduced by
$package of type object<Composer\Package\PackageInterface> is not a sub-type of object<Pickle\Base\Interfaces\Package>. It seems like you assume a child interface of the interface Composer\Package\PackageInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
141
142
        /* For the binary release, json badly need the version informatio
143
           to show the meta info. If there's ever a binary release support
144
           for other platforms, this will need to be done, probably. */
145
        (new Header\Version($package))->updateJSON();
0 ignored issues
show
Compatibility introduced by
$package of type object<Composer\Package\PackageInterface> is not a sub-type of object<Pickle\Base\Interfaces\Package>. It seems like you assume a child interface of the interface Composer\Package\PackageInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
146
147
        return $package;
148
    }
149
150
    protected function getZipBaseName(Interfaces\Package\Build $build)
151
    {
152
        $info = $build->getInfo();
153
154
        return 'php_'.$info['name'].'-'
155
            .$info['version'].'-'
156
            .$info['php_major'].'.'
157
            .$info['php_minor'].'-'
158
            .($info['thread_safe'] ? 'ts' : 'nts').'-'
159
            .$info['compiler'].'-'
160
            .$info['arch'];
161
    }
162
163
    /**
164
     * Create package.
165
     */
166
    public function create(array $args = array())
167
    {
168
        if (!isset($args['build']) || !($args['build'] instanceof Interfaces\Package\Build)) {
169
            throw new \Exception("Invalid or NULL object passed as Interfaces\Package\Build");
170
        }
171
        $this->build = $build = $args['build'];
172
173
        $info = $build->getInfo();
174
175
        $tmp_dir = $build->getTempDir();
176
177
        $tmp = $build->getLog('configure');
178
        if (preg_match(",Build dir:\s+([\:\-\.0-9a-zA-Z\\\\_]+),", $tmp, $m)) {
179
            if (preg_match(",^[a-z]\:\\\\,i", $m[1]) && is_dir($m[1])) {
180
                /* Parsed the fully qualified path */
181
                $build_dir = $m[1];
182
            } else {
183
                /* otherwise construct */
184
                $build_dir = $tmp_dir.DIRECTORY_SEPARATOR.$m[1];
185
            }
186
        } else {
187
            $build_dir = 'x86' == $info['arch'] ? $tmp_dir : $tmp_dir.DIRECTORY_SEPARATOR.'x64';
188
            $build_dir .= DIRECTORY_SEPARATOR.($is_release ? 'Release' : 'Debug');
0 ignored issues
show
Bug introduced by
The variable $is_release does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
189
            $build_dir .= ($info['thread_safe'] ? '_TS' : '');
190
        }
191
192
        /* Various file paths to pack. */
193
        $composer_json = $this->pkg->getRootDir().DIRECTORY_SEPARATOR.'composer.json';
194
195
        if (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'LICENSE')) {
196
            $license = $tmp_dir.DIRECTORY_SEPARATOR.'LICENSE';
197
        } elseif (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'COPYING')) {
198
            $license = $tmp_dir.DIRECTORY_SEPARATOR.'COPYING';
199
        } elseif (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'LICENSE.md')) {
200
            $license = $tmp_dir.DIRECTORY_SEPARATOR.'LICENSE.md';
201
        } elseif (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'COPYING.md')) {
202
            $license = $tmp_dir.DIRECTORY_SEPARATOR.'COPYING.md';
203
        } else {
204
            throw new \Exception("Couldn't find LICENSE");
205
        }
206
207
        $readme = null;
208
        if (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'README')) {
209
            $readme = $tmp_dir.DIRECTORY_SEPARATOR.'README';
210
        } elseif (file_exists($tmp_dir.DIRECTORY_SEPARATOR.'README.md')) {
211
            $readme = $tmp_dir.DIRECTORY_SEPARATOR.'README.md';
212
        }
213
214
        /* pack the outcome */
215
        $zip_name = $this->getZipBaseName($build).'.zip';
216
217
        $zip = new \ZipArchive();
218
        if (!$zip->open($zip_name, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
219
            throw new \Exception("Failed to open '$zip_name' for writing");
220
        }
221
222
        $ext_dll_found = false;
223
        $ext_names = $this->getMultiExtensionNames();
224
        foreach ($ext_names as $ext_name) {
225
            $dll_name = 'php_'.$ext_name.'.dll';
226
            $dll_file = $build_dir.DIRECTORY_SEPARATOR.$dll_name;
227
228
            if (!file_exists($dll_file)) {
229
                continue;
230
            }
231
            $ext_dll_found = true;
232
            $zip->addFile($dll_file, $dll_name);
233
234
            $pdb_name = 'php_'.$ext_name.'.pdb';
235
            $pdb_file = $build_dir.DIRECTORY_SEPARATOR.$pdb_name;
236
            if (file_exists($pdb_file)) {
237
                $zip->addFile($pdb_file, $pdb_name);
238
            }
239
        }
240
241
        if (!$ext_dll_found) {
242
            throw new \Exception("Couldn't find extension DLL");
243
        }
244
245
        $zip->addFile($composer_json, basename($composer_json));
246
        $zip->addFile($license, basename($license));
247
        if ($readme) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $readme of type string|null 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...
248
            $zip->addFile($readme, basename($readme));
249
        }
250
        $zip->close();
251
    }
252
253
    public function packLog(Interfaces\Package\Build $build = null)
254
    {
255
        if (!$build) {
256
            $build = $this->build;
257
        }
258
259
        $path = $this->getZipBaseName($build).'-logs.zip';
260
261
        $build->packLog($path);
262
263
        return realpath($path);
264
    }
265
266
    public function getMultiExtensionNames()
267
    {
268
        $info = $this->build->getInfo();
269
        $ext_names = array($info['name']);
270
271
        /* config.w32 can contain multiple EXTENTION definitions, which would lead to
272
         multiple DLLs be built. */
273
        $config_w32_path = $this->build->getPackage()->getSourceDir().DIRECTORY_SEPARATOR.'config.w32';
274
        $config_w32 = file_get_contents($config_w32_path);
275
        if (preg_match_all("/EXTENSION\s*\(\s*('|\")([a-z0-9_]+)('|\")\s*,/Sm", $config_w32, $m, PREG_SET_ORDER)) {
276
            foreach ($m as $r) {
277
                if (!in_array($r[2], $ext_names)) {
278
                    $ext_names[] = $r[2];
279
                }
280
            }
281
        }
282
283
        return $ext_names;
284
    }
285
}
286
287
/* vim: set tabstop=4 shiftwidth=4 expandtab: fdm=marker */
288