taskPackPhar('package/codecept.phar') * ->compress() * ->stub('package/stub.php'); * * $finder = Finder::create() * ->name('*.php') * ->in('src'); * * foreach ($finder as $file) { * $pharTask->addFile('src/'.$file->getRelativePathname(), $file->getRealPath()); * } * * $finder = Finder::create()->files() * ->name('*.php') * ->in('vendor'); * * foreach ($finder as $file) { * $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath()); * } * $pharTask->run(); * * // verify Phar is packed correctly * $code = $this->_exec('php package/codecept.phar'); * ?> * ``` */ class PackPhar extends BaseTask implements PrintedInterface, ProgressIndicatorAwareInterface { /** * @var \Phar */ protected $phar; /** * @var null|string */ protected $compileDir = null; /** * @var string */ protected $filename; /** * @var bool */ protected $compress = false; protected $stub; protected $bin; /** * @var string */ protected $stubTemplate = <<filename = $filename; if (file_exists($file->getRealPath())) { @unlink($file->getRealPath()); } $this->phar = new \Phar($file->getPathname(), 0, $file->getFilename()); } /** * @param bool $compress * * @return $this */ public function compress($compress = true) { $this->compress = $compress; return $this; } /** * @param string $stub * * @return $this */ public function stub($stub) { $this->phar->setStub(file_get_contents($stub)); return $this; } /** * {@inheritdoc} */ public function progressIndicatorSteps() { // run() will call advanceProgressIndicator() once for each // file, one after calling stopBuffering, and again after compression. return count($this->files)+2; } /** * {@inheritdoc} */ public function run() { $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]); $this->phar->setSignatureAlgorithm(\Phar::SHA1); $this->phar->startBuffering(); $this->printTaskInfo('Packing {file-count} files into phar', ['file-count' => count($this->files)]); $this->startProgressIndicator(); foreach ($this->files as $path => $content) { $this->phar->addFromString($path, $content); $this->advanceProgressIndicator(); } $this->phar->stopBuffering(); $this->advanceProgressIndicator(); if ($this->compress and in_array('GZ', \Phar::getSupportedCompression())) { if (count($this->files) > 1000) { $this->printTaskInfo('Too many files. Compression DISABLED'); } else { $this->printTaskInfo('{filename} compressed', ['filename' => $this->filename]); $this->phar = $this->phar->compressFiles(\Phar::GZ); } } $this->advanceProgressIndicator(); $this->stopProgressIndicator(); $this->printTaskSuccess('{filename} produced', ['filename' => $this->filename]); return Result::success($this, '', ['time' => $this->getExecutionTime()]); } /** * @param string $path * @param string $file * * @return $this */ public function addStripped($path, $file) { $this->files[$path] = $this->stripWhitespace(file_get_contents($file)); return $this; } /** * @param string $path * @param string $file * * @return $this */ public function addFile($path, $file) { $this->files[$path] = file_get_contents($file); return $this; } /** * @param \Symfony\Component\Finder\SplFileInfo[] $files */ public function addFiles($files) { foreach ($files as $file) { $this->addFile($file->getRelativePathname(), $file->getRealPath()); } } /** * @param string $file * * @return $this */ public function executable($file) { $source = file_get_contents($file); if (strpos($source, '#!/usr/bin/env php') === 0) { $source = substr($source, strpos($source, 'phar->setStub(sprintf($this->stubTemplate, $source)); return $this; } /** * Strips whitespace from source. Taken from composer * * @param string $source * * @return string */ private function stripWhitespace($source) { if (!function_exists('token_get_all')) { return $source; } $output = ''; foreach (token_get_all($source) as $token) { if (is_string($token)) { $output .= $token; } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { // $output .= $token[1]; $output .= str_repeat("\n", substr_count($token[1], "\n")); } elseif (T_WHITESPACE === $token[0]) { // reduce wide spaces $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); // normalize newlines to \n $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); // trim leading spaces $whitespace = preg_replace('{\n +}', "\n", $whitespace); $output .= $whitespace; } else { $output .= $token[1]; } } return $output; } }