|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace SymfonyDocsBuilder\Phar; |
| 4 | + |
| 5 | +use Symfony\Component\Finder\Finder; |
| 6 | +use Symfony\Component\Process\Process; |
| 7 | + |
| 8 | +/** |
| 9 | + * The Compiler class compiles composer into a phar. |
| 10 | + * |
| 11 | + * Originally adapted from Composer. |
| 12 | + * |
| 13 | + * @author Fabien Potencier <fabien@symfony.com> |
| 14 | + * @author Jordi Boggiano <j.boggiano@seld.be> |
| 15 | + * @author Ryan Weaver <ryan@knplabs.com> |
| 16 | + */ |
| 17 | +class Compiler |
| 18 | +{ |
| 19 | + private $version; |
| 20 | + private $versionDate; |
| 21 | + |
| 22 | + /** |
| 23 | + * Compiles composer into a single phar file |
| 24 | + * |
| 25 | + * @throws \RuntimeException |
| 26 | + * @param string $pharFile The full path to the file to create |
| 27 | + */ |
| 28 | + public function compile($pharFile = 'docs.phar') |
| 29 | + { |
| 30 | + if (file_exists($pharFile)) { |
| 31 | + unlink($pharFile); |
| 32 | + } |
| 33 | + |
| 34 | + $process = new Process('git log --pretty="%H" -n1 HEAD', __DIR__); |
| 35 | + if ($process->run() != 0) { |
| 36 | + throw new \RuntimeException('Can\'t run git log.'); |
| 37 | + } |
| 38 | + $this->version = trim($process->getOutput()); |
| 39 | + |
| 40 | + $process = new Process('git log -n1 --pretty=%ci HEAD', __DIR__); |
| 41 | + if ($process->run() != 0) { |
| 42 | + throw new \RuntimeException('Can\'t run git log.'); |
| 43 | + } |
| 44 | + $date = new \DateTime(trim($process->getOutput())); |
| 45 | + $date->setTimezone(new \DateTimeZone('UTC')); |
| 46 | + $this->versionDate = $date->format('Y-m-d H:i:s'); |
| 47 | + |
| 48 | + $process = new Process('git describe --tags HEAD'); |
| 49 | + if ($process->run() == 0) { |
| 50 | + $this->version = trim($process->getOutput()); |
| 51 | + } |
| 52 | + |
| 53 | + $phar = new \Phar($pharFile, 0, $pharFile); |
| 54 | + $phar->setSignatureAlgorithm(\Phar::SHA1); |
| 55 | + |
| 56 | + $phar->startBuffering(); |
| 57 | + |
| 58 | + $finder = new Finder(); |
| 59 | + $finder->files() |
| 60 | + ->ignoreVCS(true) |
| 61 | + ->name('*.php') |
| 62 | + ->notName('Compiler.php') |
| 63 | + ->in(__DIR__.'/..') |
| 64 | + ; |
| 65 | + |
| 66 | + foreach ($finder as $file) { |
| 67 | + $this->addFile($phar, $file); |
| 68 | + } |
| 69 | + |
| 70 | + $finder = new Finder(); |
| 71 | + $finder->files() |
| 72 | + ->ignoreVCS(true) |
| 73 | + ->name('*.php') |
| 74 | + ->exclude('Tests') |
| 75 | + ->in(__DIR__.'/../../vendor/doctrine/') |
| 76 | + ->in(__DIR__.'/../../vendor/psr/') |
| 77 | + ->in(__DIR__.'/../../vendor/scrivo/') |
| 78 | + ->in(__DIR__.'/../../vendor/symfony/') |
| 79 | + ->in(__DIR__.'/../../vendor/twig/') |
| 80 | + ->in(__DIR__.'/../../vendor/guzzlehttp/') |
| 81 | + ->in(__DIR__.'/../../vendor/ralouphie/') |
| 82 | + ; |
| 83 | + |
| 84 | + foreach ($finder as $file) { |
| 85 | + $this->addFile($phar, $file); |
| 86 | + } |
| 87 | + |
| 88 | + |
| 89 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/autoload.php')); |
| 90 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_namespaces.php')); |
| 91 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_psr4.php')); |
| 92 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_classmap.php')); |
| 93 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_files.php')); |
| 94 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_real.php')); |
| 95 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_static.php')); |
| 96 | + if (file_exists(__DIR__.'/../../vendor/composer/include_paths.php')) { |
| 97 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/include_paths.php')); |
| 98 | + } |
| 99 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/ClassLoader.php')); |
| 100 | + $this->addConsoleBin($phar); |
| 101 | + |
| 102 | + // Stubs |
| 103 | + $phar->setStub($this->getStub()); |
| 104 | + |
| 105 | + $phar->stopBuffering(); |
| 106 | + |
| 107 | + // disabled for interoperability with systems without gzip ext |
| 108 | + // $phar->compressFiles(\Phar::GZ); |
| 109 | + |
| 110 | + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../LICENSE'), false); |
| 111 | + |
| 112 | + unset($phar); |
| 113 | + } |
| 114 | + |
| 115 | + private function addFile($phar, $file, $strip = true) |
| 116 | + { |
| 117 | + $path = strtr(str_replace(dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR, '', $file->getRealPath()), '\\', '/'); |
| 118 | + |
| 119 | + $content = file_get_contents($file); |
| 120 | + if ($strip) { |
| 121 | + $content = $this->stripWhitespace($content); |
| 122 | + } |
| 123 | + |
| 124 | + $phar->addFromString($path, $content); |
| 125 | + } |
| 126 | + |
| 127 | + private function addConsoleBin($phar) |
| 128 | + { |
| 129 | + $content = file_get_contents(__DIR__.'/../../bin/console'); |
| 130 | + $content = preg_replace('{^#!/usr/bin/env php\s*}', '', $content); |
| 131 | + $phar->addFromString('bin/console', $content); |
| 132 | + } |
| 133 | + |
| 134 | + /** |
| 135 | + * Removes whitespace from a PHP source string while preserving line numbers. |
| 136 | + * |
| 137 | + * @param string $source A PHP string |
| 138 | + * @return string The PHP string with the whitespace removed |
| 139 | + */ |
| 140 | + private function stripWhitespace($source) |
| 141 | + { |
| 142 | + if (!function_exists('token_get_all')) { |
| 143 | + return $source; |
| 144 | + } |
| 145 | + |
| 146 | + $output = ''; |
| 147 | + foreach (token_get_all($source) as $token) { |
| 148 | + if (is_string($token)) { |
| 149 | + $output .= $token; |
| 150 | + } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { |
| 151 | + $output .= str_repeat("\n", substr_count($token[1], "\n")); |
| 152 | + } elseif (T_WHITESPACE === $token[0]) { |
| 153 | + // reduce wide spaces |
| 154 | + $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); |
| 155 | + // normalize newlines to \n |
| 156 | + $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); |
| 157 | + // trim leading spaces |
| 158 | + $whitespace = preg_replace('{\n +}', "\n", $whitespace); |
| 159 | + $output .= $whitespace; |
| 160 | + } else { |
| 161 | + $output .= $token[1]; |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + return $output; |
| 166 | + } |
| 167 | + |
| 168 | + private function getStub() |
| 169 | + { |
| 170 | + $stub = <<<'EOF' |
| 171 | +#!/usr/bin/env php |
| 172 | +<?php |
| 173 | +/* |
| 174 | + * This file is part of the Docs Builder. |
| 175 | + * |
| 176 | + * For the full copyright and license information, please view |
| 177 | + * the license that is located at the bottom of this file. |
| 178 | + */ |
| 179 | +
|
| 180 | +Phar::mapPhar('docs.phar'); |
| 181 | + |
| 182 | +EOF; |
| 183 | + |
| 184 | + return $stub . <<<'EOF' |
| 185 | +require 'phar://docs.phar/bin/console'; |
| 186 | +
|
| 187 | +__HALT_COMPILER(); |
| 188 | +EOF; |
| 189 | + } |
| 190 | +} |
0 commit comments