2 namespace Robo\Task\Development;
4 use Robo\Contract\ProgressIndicatorAwareInterface;
5 use Robo\Contract\PrintedInterface;
7 use Robo\Task\BaseTask;
14 * $pharTask = $this->taskPackPhar('package/codecept.phar')
16 * ->stub('package/stub.php');
18 * $finder = Finder::create()
22 * foreach ($finder as $file) {
23 * $pharTask->addFile('src/'.$file->getRelativePathname(), $file->getRealPath());
26 * $finder = Finder::create()->files()
30 * foreach ($finder as $file) {
31 * $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath());
35 * // verify Phar is packed correctly
36 * $code = $this->_exec('php package/codecept.phar');
40 class PackPhar extends BaseTask implements PrintedInterface, ProgressIndicatorAwareInterface
50 protected $compileDir = null;
60 protected $compress = false;
69 protected $stubTemplate = <<<EOF
80 protected $files = [];
85 public function getPrinted()
91 * @param string $filename
93 public function __construct($filename)
95 $file = new \SplFileInfo($filename);
96 $this->filename = $filename;
97 if (file_exists($file->getRealPath())) {
98 @unlink($file->getRealPath());
100 $this->phar = new \Phar($file->getPathname(), 0, $file->getFilename());
104 * @param bool $compress
108 public function compress($compress = true)
110 $this->compress = $compress;
115 * @param string $stub
119 public function stub($stub)
121 $this->phar->setStub(file_get_contents($stub));
128 public function progressIndicatorSteps()
130 // run() will call advanceProgressIndicator() once for each
131 // file, one after calling stopBuffering, and again after compression.
132 return count($this->files)+2;
138 public function run()
140 $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]);
141 $this->phar->setSignatureAlgorithm(\Phar::SHA1);
142 $this->phar->startBuffering();
144 $this->printTaskInfo('Packing {file-count} files into phar', ['file-count' => count($this->files)]);
146 $this->startProgressIndicator();
147 foreach ($this->files as $path => $content) {
148 $this->phar->addFromString($path, $content);
149 $this->advanceProgressIndicator();
151 $this->phar->stopBuffering();
152 $this->advanceProgressIndicator();
154 if ($this->compress and in_array('GZ', \Phar::getSupportedCompression())) {
155 if (count($this->files) > 1000) {
156 $this->printTaskInfo('Too many files. Compression DISABLED');
158 $this->printTaskInfo('{filename} compressed', ['filename' => $this->filename]);
159 $this->phar = $this->phar->compressFiles(\Phar::GZ);
162 $this->advanceProgressIndicator();
163 $this->stopProgressIndicator();
164 $this->printTaskSuccess('{filename} produced', ['filename' => $this->filename]);
165 return Result::success($this, '', ['time' => $this->getExecutionTime()]);
169 * @param string $path
170 * @param string $file
174 public function addStripped($path, $file)
176 $this->files[$path] = $this->stripWhitespace(file_get_contents($file));
181 * @param string $path
182 * @param string $file
186 public function addFile($path, $file)
188 $this->files[$path] = file_get_contents($file);
193 * @param \Symfony\Component\Finder\SplFileInfo[] $files
195 public function addFiles($files)
197 foreach ($files as $file) {
198 $this->addFile($file->getRelativePathname(), $file->getRealPath());
203 * @param string $file
207 public function executable($file)
209 $source = file_get_contents($file);
210 if (strpos($source, '#!/usr/bin/env php') === 0) {
211 $source = substr($source, strpos($source, '<?php') + 5);
213 $this->phar->setStub(sprintf($this->stubTemplate, $source));
218 * Strips whitespace from source. Taken from composer
220 * @param string $source
224 private function stripWhitespace($source)
226 if (!function_exists('token_get_all')) {
231 foreach (token_get_all($source) as $token) {
232 if (is_string($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;
246 $output .= $token[1];