%PDF- %PDF-
| Direktori : /opt/cpanel/ea-wappspector/vendor/clue/phar-composer/src/Phar/ |
| Current File : //opt/cpanel/ea-wappspector/vendor/clue/phar-composer/src/Phar/PharComposer.php |
<?php
namespace Clue\PharComposer\Phar;
use Clue\PharComposer\Logger;
use Clue\PharComposer\Package\Package;
use Clue\PharComposer\Box\StubGenerator;
/**
* The PharComposer is responsible for collecting options and then building the target phar
*/
class PharComposer
{
private $package;
private $main = null;
private $target = null;
private $logger;
private $step = '?';
/**
* @param string $path path to composer.json file
* @throws \InvalidArgumentException when given $path can not be parsed as JSON
*/
public function __construct($path)
{
$this->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 <info>' . $this->getTarget() . '</info>');
$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 <info>' . $target . '</info> (' . $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(' <info>OK</info> - Creating <info>' . $this->getTarget() .'</info> (' . $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;
}
}