annotate vendor/psy/psysh/src/Psy/Compiler.php @ 7:848c88cfe644

More layout
author Chris Cannam
date Fri, 05 Jan 2018 13:59:44 +0000
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of Psy Shell.
Chris@0 5 *
Chris@0 6 * (c) 2012-2017 Justin Hileman
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Psy;
Chris@0 13
Chris@0 14 use Symfony\Component\Finder\Finder;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * A Psy Shell Phar compiler.
Chris@0 18 */
Chris@0 19 class Compiler
Chris@0 20 {
Chris@0 21 /**
Chris@0 22 * Compiles psysh into a single phar file.
Chris@0 23 *
Chris@0 24 * @param string $pharFile The full path to the file to create
Chris@0 25 */
Chris@0 26 public function compile($pharFile = 'psysh.phar')
Chris@0 27 {
Chris@0 28 if (file_exists($pharFile)) {
Chris@0 29 unlink($pharFile);
Chris@0 30 }
Chris@0 31
Chris@0 32 $this->version = Shell::VERSION;
Chris@0 33
Chris@0 34 $phar = new \Phar($pharFile, 0, 'psysh.phar');
Chris@0 35 $phar->setSignatureAlgorithm(\Phar::SHA1);
Chris@0 36
Chris@0 37 $phar->startBuffering();
Chris@0 38
Chris@0 39 $finder = Finder::create()
Chris@0 40 ->files()
Chris@0 41 ->ignoreVCS(true)
Chris@0 42 ->name('*.php')
Chris@0 43 ->notName('Compiler.php')
Chris@0 44 ->notName('Autoloader.php')
Chris@0 45 ->in(__DIR__ . '/..');
Chris@0 46
Chris@0 47 foreach ($finder as $file) {
Chris@0 48 $this->addFile($phar, $file);
Chris@0 49 }
Chris@0 50
Chris@0 51 $finder = Finder::create()
Chris@0 52 ->files()
Chris@0 53 ->ignoreVCS(true)
Chris@0 54 ->name('*.php')
Chris@0 55 ->exclude('Tests')
Chris@0 56 ->exclude('tests')
Chris@0 57 ->exclude('Test')
Chris@0 58 ->exclude('test')
Chris@0 59 ->in(__DIR__ . '/../../build-vendor');
Chris@0 60
Chris@0 61 foreach ($finder as $file) {
Chris@0 62 $this->addFile($phar, $file);
Chris@0 63 }
Chris@0 64
Chris@0 65 // Stubs
Chris@0 66 $phar->setStub($this->getStub());
Chris@0 67
Chris@0 68 $phar->stopBuffering();
Chris@0 69
Chris@0 70 unset($phar);
Chris@0 71 }
Chris@0 72
Chris@0 73 /**
Chris@0 74 * Add a file to the psysh Phar.
Chris@0 75 *
Chris@0 76 * @param \Phar $phar
Chris@0 77 * @param \SplFileInfo $file
Chris@0 78 * @param bool $strip (default: true)
Chris@0 79 */
Chris@0 80 private function addFile($phar, $file, $strip = true)
Chris@0 81 {
Chris@0 82 $path = str_replace(dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR, '', $file->getRealPath());
Chris@0 83
Chris@0 84 $content = file_get_contents($file);
Chris@0 85 if ($strip) {
Chris@0 86 $content = $this->stripWhitespace($content);
Chris@0 87 } elseif ('LICENSE' === basename($file)) {
Chris@0 88 $content = "\n" . $content . "\n";
Chris@0 89 }
Chris@0 90
Chris@0 91 $phar->addFromString($path, $content);
Chris@0 92 }
Chris@0 93
Chris@0 94 /**
Chris@0 95 * Removes whitespace from a PHP source string while preserving line numbers.
Chris@0 96 *
Chris@0 97 * @param string $source A PHP string
Chris@0 98 *
Chris@0 99 * @return string The PHP string with the whitespace removed
Chris@0 100 */
Chris@0 101 private function stripWhitespace($source)
Chris@0 102 {
Chris@0 103 if (!function_exists('token_get_all')) {
Chris@0 104 return $source;
Chris@0 105 }
Chris@0 106
Chris@0 107 $output = '';
Chris@0 108 foreach (token_get_all($source) as $token) {
Chris@0 109 if (is_string($token)) {
Chris@0 110 $output .= $token;
Chris@0 111 } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
Chris@0 112 $output .= str_repeat("\n", substr_count($token[1], "\n"));
Chris@0 113 } elseif (T_WHITESPACE === $token[0]) {
Chris@0 114 // reduce wide spaces
Chris@0 115 $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
Chris@0 116 // normalize newlines to \n
Chris@0 117 $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
Chris@0 118 // trim leading spaces
Chris@0 119 $whitespace = preg_replace('{\n +}', "\n", $whitespace);
Chris@0 120 $output .= $whitespace;
Chris@0 121 } else {
Chris@0 122 $output .= $token[1];
Chris@0 123 }
Chris@0 124 }
Chris@0 125
Chris@0 126 return $output;
Chris@0 127 }
Chris@0 128
Chris@0 129 private static function getStubLicense()
Chris@0 130 {
Chris@0 131 $license = file_get_contents(__DIR__ . '/../../LICENSE');
Chris@0 132 $license = str_replace('The MIT License (MIT)', '', $license);
Chris@0 133 $license = str_replace("\n", "\n * ", trim($license));
Chris@0 134
Chris@0 135 return $license;
Chris@0 136 }
Chris@0 137
Chris@0 138 const STUB_AUTOLOAD = <<<'EOS'
Chris@0 139 Phar::mapPhar('psysh.phar');
Chris@0 140 require 'phar://psysh.phar/build-vendor/autoload.php';
Chris@0 141 EOS;
Chris@0 142
Chris@0 143 /**
Chris@0 144 * Get a Phar stub for psysh.
Chris@0 145 *
Chris@0 146 * This is basically the psysh bin, with the autoload require statements swapped out.
Chris@0 147 *
Chris@0 148 * @return string
Chris@0 149 */
Chris@0 150 private function getStub()
Chris@0 151 {
Chris@0 152 $content = file_get_contents(__DIR__ . '/../../bin/psysh');
Chris@0 153 if (version_compare(PHP_VERSION, '5.4', '<')) {
Chris@0 154 $content = str_replace('#!/usr/bin/env php', '#!/usr/bin/env php -d detect_unicode=Off', $content);
Chris@0 155 }
Chris@0 156 $content = preg_replace('{/\* <<<.*?>>> \*/}sm', self::STUB_AUTOLOAD, $content);
Chris@0 157 $content = preg_replace('/\\(c\\) .*?with this source code./sm', self::getStubLicense(), $content);
Chris@0 158
Chris@0 159 $content .= '__HALT_COMPILER();';
Chris@0 160
Chris@0 161 return $content;
Chris@0 162 }
Chris@0 163 }