Completed
Push — master ( d3a073...5737c8 )
by Greg
02:21
created

src/Task/Development/PackPhar.php (1 issue)

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
namespace Robo\Task\Development;
3
4
use Robo\Contract\ProgressIndicatorAwareInterface;
5
use Robo\Contract\PrintedInterface;
6
use Robo\Result;
7
use Robo\Task\BaseTask;
8
9
/**
10
 * Creates Phar.
11
 *
12
 * ``` php
13
 * <?php
14
 * $pharTask = $this->taskPackPhar('package/codecept.phar')
15
 *   ->compress()
16
 *   ->stub('package/stub.php');
17
 *
18
 *  $finder = Finder::create()
19
 *      ->name('*.php')
20
 *        ->in('src');
21
 *
22
 *    foreach ($finder as $file) {
23
 *        $pharTask->addFile('src/'.$file->getRelativePathname(), $file->getRealPath());
24
 *    }
25
 *
26
 *    $finder = Finder::create()->files()
27
 *        ->name('*.php')
28
 *        ->in('vendor');
29
 *
30
 *    foreach ($finder as $file) {
31
 *        $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath());
32
 *    }
33
 *    $pharTask->run();
34
 *
35
 *    // verify Phar is packed correctly
36
 *    $code = $this->_exec('php package/codecept.phar');
37
 * ?>
38
 * ```
39
 */
40
class PackPhar extends BaseTask implements PrintedInterface, ProgressIndicatorAwareInterface
41
{
42
    /**
43
     * @var \Phar
44
     */
45
    protected $phar;
46
47
    /**
48
     * @var null|string
49
     */
50
    protected $compileDir = null;
51
52
    /**
53
     * @var string
54
     */
55
    protected $filename;
56
57
    /**
58
     * @var bool
59
     */
60
    protected $compress = false;
61
62
    protected $stub;
63
64
    protected $bin;
65
66
    /**
67
     * @var string
68
     */
69
    protected $stubTemplate = <<<EOF
70
#!/usr/bin/env php
71
<?php
72
Phar::mapPhar();
73
%s
74
__HALT_COMPILER();
75
EOF;
76
77
    /**
78
     * @var string[]
79
     */
80
    protected $files = [];
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function getPrinted()
86
    {
87
        return true;
88
    }
89
90
    /**
91
     * @param string $filename
92
     */
93
    public function __construct($filename)
94
    {
95
        $file = new \SplFileInfo($filename);
96
        $this->filename = $filename;
97
        if (file_exists($file->getRealPath())) {
98
            @unlink($file->getRealPath());
99
        }
100
        $this->phar = new \Phar($file->getPathname(), 0, $file->getFilename());
101
    }
102
103
    /**
104
     * @param bool $compress
105
     *
106
     * @return $this
107
     */
108
    public function compress($compress = true)
109
    {
110
        $this->compress = $compress;
111
        return $this;
112
    }
113
114
    /**
115
     * @param string $stub
116
     *
117
     * @return $this
118
     */
119
    public function stub($stub)
120
    {
121
        $this->phar->setStub(file_get_contents($stub));
122
        return $this;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function progressIndicatorSteps()
129
    {
130
        // run() will call advanceProgressIndicator() once for each
131
        // file, one after calling stopBuffering, and again after compression.
132
        return count($this->files)+2;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function run()
139
    {
140
        $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]);
141
        $this->phar->setSignatureAlgorithm(\Phar::SHA1);
142
        $this->phar->startBuffering();
143
144
        $this->printTaskInfo('Packing {file-count} files into phar', ['file-count' => count($this->files)]);
145
146
        $this->startProgressIndicator();
147
        foreach ($this->files as $path => $content) {
148
            $this->phar->addFromString($path, $content);
149
            $this->advanceProgressIndicator();
150
        }
151
        $this->phar->stopBuffering();
152
        $this->advanceProgressIndicator();
153
154
        if ($this->compress and in_array('GZ', \Phar::getSupportedCompression())) {
155
            if (count($this->files) > 1000) {
156
                $this->printTaskInfo('Too many files. Compression DISABLED');
157
            } else {
158
                $this->printTaskInfo('{filename} compressed', ['filename' => $this->filename]);
159
                $this->phar = $this->phar->compressFiles(\Phar::GZ);
0 ignored issues
show
Are you sure the assignment to $this->phar is correct as $this->phar->compressFiles(\Phar::GZ) (which targets Phar::compressFiles()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
160
            }
161
        }
162
        $this->advanceProgressIndicator();
163
        $this->stopProgressIndicator();
164
        $this->printTaskSuccess('{filename} produced', ['filename' => $this->filename]);
165
        return Result::success($this, '', ['time' => $this->getExecutionTime()]);
166
    }
167
168
    /**
169
     * @param string $path
170
     * @param string $file
171
     *
172
     * @return $this
173
     */
174
    public function addStripped($path, $file)
175
    {
176
        $this->files[$path] = $this->stripWhitespace(file_get_contents($file));
177
        return $this;
178
    }
179
180
    /**
181
     * @param string $path
182
     * @param string $file
183
     *
184
     * @return $this
185
     */
186
    public function addFile($path, $file)
187
    {
188
        $this->files[$path] = file_get_contents($file);
189
        return $this;
190
    }
191
192
    /**
193
     * @param \Symfony\Component\Finder\SplFileInfo[] $files
194
     */
195
    public function addFiles($files)
196
    {
197
        foreach ($files as $file) {
198
            $this->addFile($file->getRelativePathname(), $file->getRealPath());
199
        }
200
    }
201
202
    /**
203
     * @param string $file
204
     *
205
     * @return $this
206
     */
207
    public function executable($file)
208
    {
209
        $source = file_get_contents($file);
210
        if (strpos($source, '#!/usr/bin/env php') === 0) {
211
            $source = substr($source, strpos($source, '<?php') + 5);
212
        }
213
        $this->phar->setStub(sprintf($this->stubTemplate, $source));
214
        return $this;
215
    }
216
217
    /**
218
     * Strips whitespace from source. Taken from composer
219
     *
220
     * @param string $source
221
     *
222
     * @return string
223
     */
224
    private function stripWhitespace($source)
225
    {
226
        if (!function_exists('token_get_all')) {
227
            return $source;
228
        }
229
230
        $output = '';
231
        foreach (token_get_all($source) as $token) {
232
            if (is_string($token)) {
233
                $output .= $token;
234
            } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
235
                // $output .= $token[1];
236
                $output .= str_repeat("\n", substr_count($token[1], "\n"));
237
            } elseif (T_WHITESPACE === $token[0]) {
238
                // reduce wide spaces
239
                $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
240
                // normalize newlines to \n
241
                $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
242
                // trim leading spaces
243
                $whitespace = preg_replace('{\n +}', "\n", $whitespace);
244
                $output .= $whitespace;
245
            } else {
246
                $output .= $token[1];
247
            }
248
        }
249
250
        return $output;
251
    }
252
}
253