芝麻web文件管理V1.00
编辑当前文件:/home/conskgoa/doughi.co.uk/clue.zip
PK g(\Bv/6 6 ! phar-composer/.github/FUNDING.ymlnu [ github: clue custom: https://clue.engineering/support PK g(\TiE: : phar-composer/LICENSEnu [ The MIT License (MIT) Copyright (c) 2013 Christian Lück Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK g(\V phar-composer/CHANGELOG.mdnu [ # Changelog ## 1.4.0 (2022-02-14) * Feature: Windows support, improve package path detection, and retry rename to fix slow network drives. (#129 and #130 by @clue) * Feature / Fix: Escape binary path when executing system binaries (git, php, composer). (#128 by @clue) * Drop legacy HHVM support due to lack of support. (#127 by @clue) ## 1.3.0 (2021-12-29) * Feature: Support Symfony 6 and PHP 8.1 release. (#122 and #123 by @clue) * Feature: Bundle `StubGenerator` and `Extract` from legacy herrera-io/box v1.6.1. (#119 by @clue) * Feature / Fix: Fix check for valid package URL. (#117 by @icedream) * Update project setup, use PSR-4 autoloading, drop `composer.lock` and instead lock PHP version when building phar. (#120 and #124 by @clue and #118 by @PaulRotmann) * Improve test suite and add `.gitattributes` to exclude dev files from exports. Update test suite to support PHPUnit 9 and test against PHP 8.1 release. (#121 and #125 by @clue) ## 1.2.0 (2020-12-11) * Feature: Support Composer 2.0! (#114 by @thojou and @clue) * Minor documentation improvements and simplify install instructions. (#98 and #99 by @clue) * Use GitHub actions for continuous integration (CI). (#112 by @SimonFrings and #113 by @szepeviktor) ## 1.1.0 (2019-11-22) * Feature: Update all dependencies and improve forward compatibility with symfony/console v5 through legacy v2.5. (#87 by @clue) * Feature: Significantly improve performance when adding phar contents. (#90 by @clue) * Feature: Support cloning projects from git SSH URLs. (#96 by @clue) * Feature: Ignore packages without autoload definition and missing vendor directory. (#94 by @clue) * Feature: Write phar to temporary file to support any extension and overwriting. (#93 by @clue) * Feature / Fix: Disable install subcommand on Windows. (#95 by @clue) * Improve test suite by adding PHPUnit to require-dev and support legacy PHP 5.3 through PHP 7.2 and HHVM, add tests for all commands and perform some minor code cleanup/maintenance, minor internal refactoring to clean up some unneeded code duplication and unneeded references and remove dedicated bundler classes, always bundle complete package. (#85, #86, #89 and #92 by @clue) * Add build script removing uneeded files and update development docs. (#91 by @clue) ## 1.0.0 (2015-11-15) * First stable release, now following SemVer. * Feature: Can now be installed as a `require-dev` Composer dependency and supports running as `./vendor/bin/phar-composer`. (#36 by @radford) * Fix: Actually exclude `vendor/` directory. This prevents processing all vendor files twice and reduces build time by 50%. (#38 by @radford) * Fix: Fix error reporting when processing invalid project paths. (#56 by @staabm and @clue) * Fix: Fix description of `phar-composer install` command. (#47 by @staabm) * Updated documentation, tests and project structure. (#54, #57, #58 and #59 by @clue) ## 0.5.0 (2014-07-10) * Feature: The `search` command is the new default if you do not pass any command ([#13](https://github.com/clue/phar-composer/pull/13)). You can now use the following command to get started: ```bash $ phar-composer ``` * Fix: Pass through STDERR output of child processes instead of aborting ([#33](https://github.com/clue/phar-composer/pull/33)) * Fix: Do not timeout when child process takes longer than 60s. This also helps users with slower internet connections. ([#31](https://github.com/clue/phar-composer/pull/31)) * Fix: Update broken dependencies ([#18](https://github.com/clue/phar-composer/pull/18)) * Fix: Fixed an undocumented config key ([#14](https://github.com/clue/phar-composer/pull/14), thanks @mikey179) ## 0.4.0 (2013-09-12) * Feature: New `install` command will now both build the given package and then install it into the system-wide bin directory `/usr/local/bin` (usually already in your `$PATH`). This works for any package name or URL just like with the `build` command, e.g.: ```bash $ phar-composer install phpunit/phpunit ``` After some (lengthy) build output, you should now be able to run it by just issuing: ```bash $ phpunit ``` * Feature: New `search` command provides an interactive command line search. It will ask for the package name and issue an search via packagist.org's API and present a list of matching packages. So if you don't know the exact package name, you can now use the following command: ```bash $ phar-composer search boris ``` * Feature: Both `build` and `install` commands now also optionally accept an additional target directory to place the resulting phar into. ## 0.3.0 (2013-08-21) * Feature: Resulting phar files can now be executed on systems without ext-phar (#8). This vastly improves portability for legacy setups by including a small startup script which self-extracts the current archive into a temporary directory. * Feature: Resulting phar files can now be executed without the phar file name extension. E.g. this convenient feature now allows you to move your `~demo.phar` to `/usr/bin/demo` for easy system wide installations. * Fix: Resolving absolute paths to `vendor/autoload.php` ## 0.2.0 (2013-08-15) * Feature: Packages can now also be cloned from any git URLs (#9), like this: ```bash $ phar-composer build https://github.com/clue/phar-composer.git ``` The above will clone the repository and check out the default branch. You can also specify either a tag or branch name very similar to how composer works: ```bash $ phar-composer build https://github.com/clue/phar-composer.git:dev-master ``` ## 0.1.0 (2013-08-12) * Feature: Packages listed on packagist.org can now automatically be downloaded and installed prior to generating phar (#7), like this: ```bash $ phar-composer build clue/phar-composer ``` The above will download and install the latest stable tagged release (if any). You can also specify a tagged version like this: ```bash $ phar-composer build clue/phar-composer:0.1.* ``` Or you can specify to install the head of a given branch like this: ```bash $ phar-composer build clue/phar-composer:dev-master ``` ## 0.0.2 (2013-05-25) * Feature: Bundle complete project directories ## 0.0.1 (2013-05-18) * First tagged release PK g(\t phar-composer/composer.jsonnu [ { "name": "clue/phar-composer", "description": "Simple phar creation for any project managed via Composer", "keywords": ["executable phar", "build process", "bundle dependencies", "phar", "composer"], "homepage": "https://github.com/clue/phar-composer", "license": "MIT", "authors": [ { "name": "Christian Lück", "email": "christian@clue.engineering" } ], "require": { "php": ">=5.3.6", "knplabs/packagist-api": "^1.0", "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.0 || ^2.5", "symfony/finder": "^6.0 || ^5.0 || ^4.0 || ^3.0 || ^2.5", "symfony/process": "^6.0 || ^5.0 || ^4.0 || ^3.0 || ^2.5" }, "require-dev": { "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" }, "autoload": { "psr-4": {"Clue\\PharComposer\\": "src/"} }, "bin": ["bin/phar-composer"], "scripts": { "build": "@php bin/build.php" } } PK g(\F # phar-composer/src/Command/Build.phpnu [ packager = $packager; } protected function configure() { $this->setName('build') ->setDescription('Build phar for the given composer project') ->addArgument('project', InputArgument::OPTIONAL, 'Path to project directory or composer.json', '.') ->addArgument('target', InputArgument::OPTIONAL, 'Path to write phar output to (defaults to project name)'); } protected function execute(InputInterface $input, OutputInterface $output) { $this->packager->setOutput($output); $this->packager->coerceWritable(); $pharer = $this->packager->getPharer($input->getArgument('project')); $target = $input->getArgument('target'); if ($target !== null) { $pharer->setTarget($target); } $pharer->build(); return 0; } } PK g(\*:4 $ phar-composer/src/Command/Search.phpnu [ packager = $packager; $this->packagist = $packagist; $this->isWindows = $isWindows; parent::__construct(); } protected function configure() { $this->setName('search') ->setDescription('Interactive search for project name') ->addArgument('project', InputArgument::OPTIONAL, 'Project name or path', null); } /** * @param InputInterface $input * @param OutputInterface $output * @param string $label * @param array
$choices * @param ?string $abortable * @return ?string */ protected function select(InputInterface $input, OutputInterface $output, $label, array $choices, $abortable = null) { $helper = $this->getHelper('question'); assert($helper instanceof QuestionHelper); if (!$choices) { $output->writeln('
No matching packages found
'); return null; } // use numeric keys for all options $select = array_merge(array(0 => $abortable), array_values($choices)); if ($abortable === null) { unset($select[0]); } $question = new ChoiceQuestion($label, $select); $index = array_search($helper->ask($input, $output, $question), $select); if ($index === 0) { return null; } $indices = array_keys($choices); return $indices[$index - 1]; } protected function execute(InputInterface $input, OutputInterface $output) { $this->packager->setOutput($output); $this->packager->coerceWritable(); $helper = $this->getHelper('question'); assert($helper instanceof QuestionHelper); $project = $input->getArgument('project'); do { if ($project === null) { // ask for input $question = new Question('Enter (partial) project name > ', ''); $project = $helper->ask($input, $output, $question); } else { $output->writeln('Searching for
' . $project . '
...'); } $choices = array(); foreach ($this->packagist->search($project) as $result) { assert($result instanceof Result); $label = str_pad($result->getName(), 39) . ' '; $label = str_replace($project, '
' . $project . '
', $label); $label .= $result->getDescription(); $label .= ' (⤓' . $result->getDownloads() . ')'; $choices[$result->getName()] = $label; } $project = $this->select($input, $output, 'Select matching package', $choices, 'Start new search'); } while ($project === null); $output->writeln('Selected
' . $project . '
, listing versions...'); $package = $this->packagist->get($project); assert($package instanceof Package); $choices = array(); foreach ($package->getVersions() as $version) { assert($version instanceof Version); $label = $version->getVersion(); /* @var ?string $bin */ $bin = $version->getBin(); $label .= $bin !== null ? ' (☑ executable bin)' : ' (
no executable bin
)'; $choices[$version->getVersion()] = $label; } $version = $this->select($input, $output, 'Select available version', $choices); $action = $this->select( $input, $output, 'Action', array_filter(array( 'build' => 'Build project', 'install' => $this->isWindows ? null : 'Install project system-wide' )), 'Quit' ); if ($action === null) { return 0; } $pharer = $this->packager->getPharer($project, $version); if ($action === 'install') { $path = $this->packager->getSystemBin($pharer->getPackageRoot()); $this->packager->install($pharer, $path); } else { $pharer->build(); } return 0; } } PK g(\2$+_ _ % phar-composer/src/Command/Install.phpnu [ packager = $packager; $this->isWindows = $isWindows; parent::__construct(); } protected function configure() { $this->setName('install') ->setDescription('Install phar into system wide binary directory' . ($this->isWindows ? ' (not available on Windows)' : '')) ->addArgument('project', InputArgument::OPTIONAL, 'Project name or path', '.') ->addArgument('target', InputArgument::OPTIONAL, 'Path to install to', '/usr/local/bin'); } protected function execute(InputInterface $input, OutputInterface $output) { if ($this->isWindows) { $output->writeln('
Command not available on this platform. Please use the "build" command and place Phar in your $PATH manually.
'); return 1; } $this->packager->setOutput($output); $this->packager->coerceWritable(); $pharer = $this->packager->getPharer($input->getArgument('project')); $path = $this->packager->getSystemBin($pharer->getPackageRoot(), $input->getArgument('target')); if (is_file($path)) { $helper = $this->getHelper('question'); assert($helper instanceof QuestionHelper); $question = new ConfirmationQuestion('Overwrite existing file
' . $path . '
? [y] > ', true); if (!$helper->ask($input, $output, $question)) { $output->writeln('Aborting'); return 0; } } $this->packager->install($pharer, $path); return 0; } } PK g(\- % phar-composer/src/Package/Package.phpnu [ package = $package; $this->directory = rtrim($directory, '/') . '/'; } /** * get package name as defined in composer.json * * @return ?string */ public function getName() { return isset($this->package['name']) ? $this->package['name'] : null; } /** * @return string */ public function getShortName() { // skip vendor name from package name or default to last directory component $name = $this->getName(); if ($name === null) { $name = realpath($this->directory); if ($name === false) { $name = $this->directory; } } return basename($name); } /** * Get path to vendor directory (relative to package directory, always ends with slash) * * @return string */ public function getPathVendor() { $vendor = 'vendor'; if (isset($this->package['config']['vendor-dir'])) { $vendor = $this->package['config']['vendor-dir']; } return $vendor . '/'; } /** * Get package directory (the directory containing its composer.json, always ends with slash) * * @return string */ public function getDirectory() { return $this->directory; } /** * @return \Clue\PharComposer\Package\Bundle */ public function bundle() { $bundle = new Bundle(); // return empty bundle if this package does not define any files and directory does not exist if (empty($this->package['autoload']) && !is_dir($this->directory . $this->getPathVendor())) { return $bundle; } $iterator = Finder::create() ->files() ->ignoreVCS(true) ->exclude(rtrim($this->getPathVendor(), '/')) ->notPath('/^composer\.phar/') ->notPath('/^phar-composer\.phar/') ->in($this->getDirectory()); return $bundle->addDir($iterator); } /** * Get list of files defined as "bin" (relative to package directory) * * @return string[] */ public function getBins() { return isset($this->package['bin']) ? $this->package['bin'] : array(); } } PK g(\N $ phar-composer/src/Package/Bundle.phpnu [ resources[] = $file; return $this; } /** * add given directory to bundle * * @param Finder $dir * @return Bundle */ public function addDir(Finder $dir) { $this->resources[] = $dir; return $this; } /** * checks if a bundle contains given resource * * @param string $resource * @return bool */ public function contains($resource) { foreach ($this->resources as $containedResource) { if (is_string($containedResource) && $containedResource == $resource) { return true; } if ($containedResource instanceof Finder && $this->directoryContains($containedResource, $resource)) { return true; } } return false; } /** * checks if given directory contains given resource * * @param Finder $dir * @param string $resource * @return bool */ private function directoryContains(Finder $dir, $resource) { foreach ($dir as $containedResource) { /* @var $containedResource \SplFileInfo */ if (substr($containedResource->getRealPath(), 0, strlen($resource)) == $resource) { return true; } } return false; } /** * returns list of resources * * @return \Traversable */ #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->resources); } } PK g(\"6f* f* # phar-composer/src/Phar/Packager.phpnu [ setOutput(true); } private function log($message) { $fn = $this->output; $fn($message . PHP_EOL); } public function setBinSudo($bin) { $this->binSudo = $bin; } /** * @param OutputInterface|bool|callable $fn */ public function setOutput($fn) { if ($fn instanceof OutputInterface) { $fn = function ($line) use ($fn) { $fn->write($line); }; } elseif ($fn === true) { $fn = function ($line) { echo $line; }; } elseif ($fn === false) { $fn = function () { }; } $this->output = $fn; } /** * ensure writing phar files is enabled or respawn with PHP setting which allows writing * * @param int $wait * @return void * @uses assertWritable() */ public function coerceWritable($wait = 1) { try { $this->assertWritable(); } catch (UnexpectedValueException $e) { if (!function_exists('pcntl_exec')) { $this->log('
' . $e->getMessage() . '
'); return; } $this->log('
' . $e->getMessage() . ', trying to re-spawn with correct config
'); if ($wait) { sleep($wait); } $args = array_merge(array('php', '-d phar.readonly=off'), $_SERVER['argv']); if (pcntl_exec('/usr/bin/env', $args) === false) { $this->log('
Unable to switch into new configuration
'); return; } } } /** * ensure writing phar files is enabled or throw an exception * * @throws UnexpectedValueException */ public function assertWritable() { if (ini_get('phar.readonly') === '1') { throw new UnexpectedValueException('Your configuration disabled writing phar files (phar.readonly = On), please update your configuration or run with "php -d phar.readonly=off ' . $_SERVER['argv'][0].'"'); } } /** * @param string $path * @param string $version * @return PharComposer * @throws UnexpectedValueException * @throws InvalidArgumentException * @throws RuntimeException */ public function getPharer($path, $version = null) { if ($version !== null) { // TODO: should be the other way around $path .= ':' . $version; } $step = 1; $steps = 1; if ($this->isPackageUrl($path)) { $url = $path; $version = null; $steps = 3; if (preg_match('/(.+)\:((?:dev\-|v\d)\S+)$/i', $url, $match)) { $url = $match[1]; $version = $match[2]; if (substr($version, 0, 4) === 'dev-') { $version = substr($version, 4); } } $path = $this->getDirTemporary(); $finder = new ExecutableFinder(); $git = escapeshellarg($finder->find('git', 'git')); $that = $this; $this->displayMeasure( '[' . $step++ . '/' . $steps.'] Cloning
' . $url . '
into temporary directory
' . $path . '
', function() use ($that, $url, $path, $version, $git) { $that->exec($git . ' clone ' . escapeshellarg($url) . ' ' . escapeshellarg($path)); if ($version !== null) { $this->exec($git . ' checkout ' . escapeshellarg($version) . ' 2>&1', $path); } }, 'Cloning base repository completed' ); $pharcomposer = new PharComposer($path . '/composer.json'); $package = $pharcomposer->getPackageRoot()->getName(); if (is_file('composer.phar')) { $command = escapeshellarg($finder->find('php', 'php')) . ' composer.phar'; } else { $command = escapeshellarg($finder->find('composer', 'composer')); } $command .= ' install --no-dev --no-progress --no-scripts'; $this->displayMeasure( '[' . $step++ . '/' . $steps.'] Installing dependencies for
' . $package . '
into
' . $path . '
(using
' . $command . '
)', function () use ($that, $command, $path) { try { $that->exec($command, $path); } catch (UnexpectedValueException $e) { throw new UnexpectedValueException('Installing dependencies via composer failed', 0, $e); } }, 'Downloading dependencies completed' ); } elseif ($this->isPackageName($path)) { if (is_dir($path)) { $this->log('
There\'s also a directory with the given name
'); } $steps = 2; $package = $path; $path = $this->getDirTemporary(); $finder = new ExecutableFinder(); if (is_file('composer.phar')) { $command = escapeshellarg($finder->find('php', 'php')) . ' composer.phar'; } else { $command = escapeshellarg($finder->find('composer', 'composer')); } $command .= ' create-project ' . escapeshellarg($package) . ' ' . escapeshellarg($path) . ' --no-dev --no-progress --no-scripts'; $that = $this; $this->displayMeasure( '[' . $step++ . '/' . $steps.'] Installing
' . $package . '
to temporary directory
' . $path . '
(using
' . $command . '
)', function () use ($that, $command) { try { $that->exec($command); } catch (UnexpectedValueException $e) { throw new UnexpectedValueException('Installing package via composer failed', 0, $e); } }, 'Downloading package completed' ); } if (is_dir($path)) { $path = rtrim($path, '/') . '/composer.json'; } if (!is_file($path)) { throw new InvalidArgumentException('The given path "' . $path . '" is not a readable file'); } $pharer = new PharComposer($path); $pharer->setOutput($this->output); $pharer->setStep($step); $pathVendor = $pharer->getPackageRoot()->getDirectory() . $pharer->getPackageRoot()->getPathVendor(); if (!is_dir($pathVendor)) { throw new RuntimeException('Project is not installed via composer. Run "composer install" manually'); } return $pharer; } public function measure($fn) { $time = microtime(true); $fn(); return max(microtime(true) - $time, 0); } public function displayMeasure($title, $fn, $success) { $this->log($title); $time = $this->measure($fn); $this->log(''); $this->log('
OK
- ' . $success .' (after ' . round($time, 1) . 's)'); } /** * @param string $cmd * @param ?string $chdir * @return void * @throws UnexpectedValueException */ public function exec($cmd, $chdir = null) { $nl = true; // $output = $this->output; // Symfony 5+ requires 'fromShellCommandline', older versions support direct instantiation with command line // @codeCoverageIgnoreStart try { new \ReflectionMethod('Symfony\Component\Process\Process', 'fromShellCommandline'); $process = Process::fromShellCommandline($cmd, $chdir); } catch (\ReflectionException $e) { $process = new Process($cmd, $chdir); } // @codeCoverageIgnoreEnd $process->setTimeout(null); $code = $process->run(function($type, $data) use ($output, &$nl) { if ($nl === true) { $data = PHP_EOL . $data; $nl = false; } if (substr($data, -1) === "\n") { $nl = true; $data = substr($data, 0, -strlen(PHP_EOL)); } $data = str_replace("\n", "\n ", $data); $output($data); }); if ($nl) { $this->log(''); } if ($code !== 0) { throw new UnexpectedValueException('Error status code: ' . $process->getExitCodeText() . ' (code ' . $code . ')'); } } public function install(PharComposer $pharer, $path) { $pharer->build(); $this->log('Move resulting phar to
' . $path . '
'); $this->exec($this->binSudo . ' -- mv -f ' . escapeshellarg($pharer->getTarget()) . ' ' . escapeshellarg($path)); $this->log(''); $this->log('
OK
- Moved to
' . $path . '
'); } /** * @param Package $package * @param ?string $path * @return string */ public function getSystemBin(Package $package, $path = null) { // no path given => place in system bin path if ($path === null) { $path = self::PATH_BIN; } // no slash => path is relative to system bin path if (strpos($path, '/') === false) { $path = self::PATH_BIN . '/' . $path; } // path is actually a directory => append package name if (is_dir($path)) { $path = rtrim($path, '/') . '/' . $package->getShortName(); } return $path; } private function isPackageName($path) { return !!preg_match('/^[^\s\/]+\/[^\s\/]+(\:[^\s]+)?$/i', $path); } public function isPackageUrl($path) { return (strpos($path, '://') !== false && @parse_url($path) !== false) || preg_match('/^[^-\/\s][^:\/\s]*:[^\s\\\\]\S*/', $path); } private function getDirTemporary() { $path = sys_get_temp_dir() . '/phar-composer' . mt_rand(0,9); while (is_dir($path)) { $path .= mt_rand(0, 9); } return $path; } } PK g(\># # ' phar-composer/src/Phar/PharComposer.phpnu [ package = new Package($this->loadJson($path), dirname(realpath($path))); $this->logger = new Logger(); } /** * set output function to use to output log messages * * @param callable|boolean $output callable that receives a single $line argument or boolean echo */ public function setOutput($output) { $this->logger->setOutput($output); } /** * Get path to target phar file (absolute path or relative to current directory) * * @return string */ public function getTarget() { if ($this->target === null) { $this->target = $this->package->getShortName() . '.phar'; } return $this->target; } /** * Set path to target phar file (absolute path or relative to current directory) * * If the given path is a directory, the default target (package short name) * will be appended automatically. * * @param string $target * @return $this */ public function setTarget($target) { // path is actually a directory => append package name if (is_dir($target)) { $this->target = null; $target = rtrim($target, '/') . '/' . $this->getTarget(); } $this->target = $target; return $this; } /** * Get path to main bin (relative to package directory) * * @return string * @throws \UnexpectedValueException */ public function getMain() { if ($this->main === null) { foreach ($this->package->getBins() as $path) { if (!file_exists($this->package->getDirectory() . $path)) { throw new \UnexpectedValueException('Bin file "' . $path . '" does not exist'); } $this->main = $path; break; } } return $this->main; } /** * set path to main bin (relative to package directory) * * @param string $main * @return $this */ public function setMain($main) { $this->main = $main; return $this; } /** * * @return Package */ public function getPackageRoot() { return $this->package; } /** * * @return Package[] */ public function getPackagesDependencies() { $packages = array(); $pathVendor = $this->package->getDirectory() . $this->package->getPathVendor(); // load all installed packages (use installed.json which also includes version instead of composer.lock) if (is_file($pathVendor . 'composer/installed.json')) { // file does not exist if there's nothing to be installed $installed = $this->loadJson($pathVendor . 'composer/installed.json'); // Composer 2.0 format wrapped in additional root key if (isset($installed['packages'])) { $installed = $installed['packages']; } foreach ($installed as $package) { $dir = $package['name'] . '/'; if (isset($package['target-dir'])) { $dir .= trim($package['target-dir'], '/') . '/'; } $dir = $pathVendor . $dir; $packages []= new Package($package, $dir); } } return $packages; } public function build() { $this->log('[' . $this->step . '/' . $this->step.'] Creating phar
' . $this->getTarget() . '
'); $time = microtime(true); $pathVendor = $this->package->getDirectory() . $this->package->getPathVendor(); if (!is_dir($pathVendor)) { throw new \RuntimeException('Directory "' . $pathVendor . '" not properly installed, did you run "composer install"?'); } // get target and tempory file name to write to $target = $this->getTarget(); do { $tmp = $target . '.' . mt_rand() . '.phar'; } while (file_exists($tmp)); $targetPhar = new TargetPhar(new \Phar($tmp), $this); $this->log(' - Adding main package "' . $this->package->getName() . '"'); $targetPhar->addBundle($this->package->bundle()); $this->log(' - Adding composer base files'); // explicitly add composer autoloader $targetPhar->addFile($pathVendor . 'autoload.php'); // only add composer base directory (no sub-directories!) $targetPhar->buildFromIterator(new \GlobIterator($pathVendor . 'composer/*.*', \FilesystemIterator::KEY_AS_FILENAME)); foreach ($this->getPackagesDependencies() as $package) { $this->log(' - Adding dependency "' . $package->getName() . '" from "' . $this->getPathLocalToBase($package->getDirectory()) . '"'); $targetPhar->addBundle($package->bundle()); } $this->log(' - Setting main/stub'); $chmod = 0755; $main = $this->getMain(); if ($main === null) { $this->log(' WARNING: No main bin file defined! Resulting phar will NOT be executable'); } else { $generator = StubGenerator::create() ->index($main) ->extract(true) ->banner("Bundled by phar-composer with the help of php-box.\n\n@link https://github.com/clue/phar-composer"); $lines = file($this->package->getDirectory() . $main, FILE_IGNORE_NEW_LINES); if (substr($lines[0], 0, 2) === '#!') { $this->log(' Using referenced shebang "'. $lines[0] . '"'); $generator->shebang($lines[0]); // remove shebang from main file and add (overwrite) unset($lines[0]); $targetPhar->addFromString($main, implode("\n", $lines)); } $targetPhar->setStub($generator->generate()); $chmod = octdec(substr(decoct(fileperms($this->package->getDirectory() . $main)),-4)); $this->log(' Using referenced chmod ' . sprintf('%04o', $chmod)); } // stop buffering contents in memory and write to file // failure to write will emit a warning (ignore) and throw an (uncaught) exception try { @$targetPhar->stopBuffering(); $targetPhar = null; } catch (\PharException $e) { throw new \RuntimeException('Unable to write phar: ' . $e->getMessage()); } if ($chmod !== null) { $this->log(' Applying chmod ' . sprintf('%04o', $chmod)); if (chmod($tmp, $chmod) === false) { throw new \UnexpectedValueException('Unable to chmod target file "' . $target .'"'); } } if (file_exists($target)) { $this->log(' - Overwriting existing file
' . $target . '
(' . $this->getSize($target) . ')'); } if (@rename($tmp, $target) === false) { // retry renaming after sleeping to give slow network drives some time to flush data sleep(5); if (rename($tmp, $target) === false) { throw new \UnexpectedValueException('Unable to rename temporary phar archive to "'.$target.'"'); } } $time = max(microtime(true) - $time, 0); $this->log(''); $this->log('
OK
- Creating
' . $this->getTarget() .'
(' . $this->getSize($this->getTarget()) . ') completed after ' . round($time, 1) . 's'); } private function getSize($path) { return round(filesize($path) / 1024, 1) . ' KiB'; } public function getPathLocalToBase($path) { $root = $this->package->getDirectory(); if (strpos($path, $root) !== 0) { throw new \UnexpectedValueException('Path "' . $path . '" is not within base project path "' . $root . '"'); } return substr($path, strlen($root)); } public function log($message) { $this->logger->log($message); } public function setStep($step) { $this->step = $step; } /** * @param string $path * @return mixed * @throws \InvalidArgumentException */ private function loadJson($path) { $ret = @json_decode(file_get_contents($path), true); if ($ret === null) { throw new \InvalidArgumentException('Unable to parse given path "' . $path . '"', json_last_error()); } return $ret; } } PK g(\'B٩ % phar-composer/src/Phar/TargetPhar.phpnu [ startBuffering(); $this->phar = $phar; $this->pharComposer = $pharComposer; } /** * finalize writing of phar file */ public function stopBuffering() { $this->phar->stopBuffering(); } /** * adds given list of resources to phar * * @param Bundle $bundle */ public function addBundle(Bundle $bundle) { foreach ($bundle as $resource) { if (is_string($resource)) { $this->addFile($resource); } else { $this->buildFromIterator($resource); } } } /** * Adds a file to the Phar * * @param string $file The file name. */ public function addFile($file) { $this->phar->addFile($file, $this->pharComposer->getPathLocalToBase($file)); } public function buildFromIterator(\Traversable $iterator) { $this->phar->buildFromIterator($iterator, $this->pharComposer->getPackageRoot()->getDirectory()); } /** * Used to set the PHP loader or bootstrap stub of a Phar archive * * @param string $stub */ public function setStub($stub) { $this->phar->setStub($stub); } public function addFromString($local, $contents) { $this->phar->addFromString($local, $contents); } } PK g(\c`2 phar-composer/src/App.phpnu [ add(new Command\Build()); $this->add(new Command\Search()); $this->add(new Command\Install()); $this->setDefaultCommand('search'); } } PK g(\t, , ' phar-composer/src/Box/StubGenerator.phpnu [ */ class StubGenerator { /** * The list of server variables that are allowed to be modified. * * @var array */ private static $allowedMung = array( 'PHP_SELF', 'REQUEST_URI', 'SCRIPT_FILENAME', 'SCRIPT_NAME' ); /** * The alias to be used in "phar://" URLs. * * @var string */ private $alias; /** * The top header comment banner text. * * @var string. */ private $banner = 'Generated by Box. @link https://github.com/herrera-io/php-box/'; /** * Embed the Extract class in the stub? * * @var boolean */ private $extract = false; /** * The processed extract code. * * @var array */ private $extractCode = array(); /** * Force the use of the Extract class? * * @var boolean */ private $extractForce = false; /** * The location within the Phar of index script. * * @var string */ private $index; /** * Use the Phar::interceptFileFuncs() method? * * @var boolean */ private $intercept = false; /** * The map for file extensions and their mimetypes. * * @var array */ private $mimetypes = array(); /** * The list of server variables to modify. * * @var array */ private $mung = array(); /** * The location of the script to run when a file is not found. * * @var string */ private $notFound; /** * The rewrite function. * * @var string */ private $rewrite; /** * The shebang line. * * @var string */ private $shebang = '#!/usr/bin/env php'; /** * Use Phar::webPhar() instead of Phar::mapPhar()? * * @var boolean */ private $web = false; /** * Sets the alias to be used in "phar://" URLs. * * @param string $alias The alias. * * @return StubGenerator The stub generator. */ public function alias($alias) { $this->alias = $alias; return $this; } /** * Sets the top header comment banner text. * * @param string $banner The banner text. * * @return StubGenerator The stub generator. */ public function banner($banner) { $this->banner = $banner; return $this; } /** * Creates a new instance of the stub generator. * * @return StubGenerator The stub generator. */ public static function create() { return new static(); } /** * Embed the Extract class in the stub? * * @param boolean $extract Embed the class? * @param boolean $force Force the use of the class? * * @return StubGenerator The stub generator. */ public function extract($extract, $force = false) { $this->extract = $extract; $this->extractForce = $force; if ($extract) { $this->extractCode = array( 'constants' => array(), 'class' => array(), ); $code = file_get_contents(__DIR__ . '/Extract.min.php'); $code = preg_replace('/\n+/', "\n", $code); $code = explode("\n", $code); $code = array_slice($code, 2); foreach ($code as $i => $line) { if ((0 === strpos($line, 'use')) && (false === strpos($line, '\\')) ) { unset($code[$i]); } elseif (0 === strpos($line, 'define')) { $this->extractCode['constants'][] = $line; } else { $this->extractCode['class'][] = $line; } } } return $this; } /** * Sets location within the Phar of index script. * * @param string $index The index file. * * @return StubGenerator The stub generator. */ public function index($index) { $this->index = $index; return $this; } /** * Use the Phar::interceptFileFuncs() method in the stub? * * @param boolean $intercept Use interceptFileFuncs()? * * @return StubGenerator The stub generator. */ public function intercept($intercept) { $this->intercept = $intercept; return $this; } /** * Generates the stub. * * @return string The stub. */ public function generate() { $stub = array(); if ('' !== $this->shebang) { $stub[] = $this->shebang; } $stub[] = 'banner) { $stub[] = $this->getBanner(); } if ($this->extract) { $stub[] = join("\n", $this->extractCode['constants']); if ($this->extractForce) { $stub = array_merge($stub, $this->getExtractSections()); } } $stub = array_merge($stub, $this->getPharSections()); if ($this->extract) { if ($this->extractForce) { if ($this->index && !$this->web) { $stub[] = "require \"\$dir/{$this->index}\";"; } } else { end($stub); $stub[key($stub)] .= ' else {'; $stub = array_merge($stub, $this->getExtractSections()); if ($this->index) { $stub[] = "require \"\$dir/{$this->index}\";"; } $stub[] = '}'; } $stub[] = join("\n", $this->extractCode['class']); } $stub[] = "__HALT_COMPILER();"; return join("\n", $stub); } /** * Sets the map for file extensions and their mimetypes. * * @param array $mimetypes The map. * * @return StubGenerator The stub generator. */ public function mimetypes(array $mimetypes) { $this->mimetypes = $mimetypes; return $this; } /** * Sets the list of server variables to modify. * * @param array $list The list. * * @return StubGenerator The stub generator. * * @throws \InvalidArgumentException If the list contains an invalid value. */ public function mung(array $list) { foreach ($list as $value) { if (false === in_array($value, self::$allowedMung)) { throw new \InvalidArgumentException(sprintf( 'The $_SERVER variable "%s" is not allowed.', $value )); } } $this->mung = $list; return $this; } /** * Sets the location of the script to run when a file is not found. * * @param string $script The script. * * @return StubGenerator The stub generator. */ public function notFound($script) { $this->notFound = $script; return $this; } /** * Sets the rewrite function. * * @param string $function The function. * * @return StubGenerator The stub generator. */ public function rewrite($function) { $this->rewrite = $function; return $this; } /** * Sets the shebang line. * * @param string $shebang The shebang line. * * @return StubGenerator The stub generator. */ public function shebang($shebang) { $this->shebang = $shebang; return $this; } /** * Use Phar::webPhar() instead of Phar::mapPhar()? * * @param boolean $web Use Phar::webPhar()? * * @return StubGenerator The stub generator. */ public function web($web) { $this->web = $web; return $this; } /** * Escapes an argument so it can be written as a string in a call. * * @param string $arg The argument. * @param string $quote The quote. * * @return string The escaped argument. */ private function arg($arg, $quote = "'") { return $quote . addcslashes($arg, $quote) . $quote; } /** * Returns the alias map. * * @return string The alias map. */ private function getAlias() { $stub = ''; $prefix = ''; if ($this->extractForce) { $prefix = '$dir/'; } if ($this->web) { $stub .= 'Phar::webPhar(' . $this->arg($this->alias); if ($this->index) { $stub .= ', ' . $this->arg($prefix . $this->index, '"'); if ($this->notFound) { $stub .= ', ' . $this->arg($prefix . $this->notFound, '"'); if ($this->mimetypes) { $stub .= ', ' . var_export( $this->mimetypes, true ); if ($this->rewrite) { $stub .= ', ' . $this->arg($this->rewrite); } } } } $stub .= ');'; } else { $stub .= 'Phar::mapPhar(' . $this->arg($this->alias) . ');'; } return $stub; } /** * Returns the banner after it has been processed. * * @return string The processed banner. */ private function getBanner() { $banner = "/**\n * "; $banner .= str_replace( " \n", "\n", str_replace("\n", "\n * ", $this->banner) ); $banner .= "\n */"; return $banner; } /** * Returns the self extracting sections of the stub. * * @return array The stub sections. */ private function getExtractSections() { return array( '$extract = new Extract(__FILE__, Extract::findStubLength(__FILE__));', '$dir = $extract->go();', 'set_include_path($dir . PATH_SEPARATOR . get_include_path());', ); } /** * Returns the sections of the stub that use the Phar class. * * @return array The stub sections. */ private function getPharSections() { $stub = array( 'if (class_exists(\'Phar\')) {', $this->getAlias(), ); if ($this->intercept) { $stub[] = "Phar::interceptFileFuncs();"; } if ($this->mung) { $stub[] = 'Phar::mungServer(' . var_export($this->mung, true) . ");"; } if ($this->index && !$this->web && !$this->extractForce) { $stub[] = "require 'phar://' . __FILE__ . '/{$this->index}';"; } $stub[] = '}'; return $stub; } } PK g(\<