diff --git a/src/Command/PharCommand.php b/src/Command/PharCommand.php index b93dce6..721576b 100644 --- a/src/Command/PharCommand.php +++ b/src/Command/PharCommand.php @@ -2,6 +2,7 @@ namespace Pogo\Command; +use Pogo\FilteredDirectoryIterator; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -55,7 +56,14 @@ protected function execute(InputInterface $input, OutputInterface $output) { $phar = new \Phar($pharTmp); $phar->setStub($this->createStub($logicalPhar, $mainFile)); - $phar->buildFromDirectory($project->path); + $fileIter = new FilteredDirectoryIterator($project->path, function(string $relPath, \SplFileInfo $file) { + // These are debug-files. Not needed in the PHAR. + $ignore = ['run.php', 'run.sh', 'script.php']; + $result = !in_array($relPath, $ignore) && !$file->isDir(); + return $result; + }); + + $phar->buildFromIterator($fileIter, $project->path); $phar->compressFiles(\Phar::GZ); $fs->chmod($pharTmp, 0777); diff --git a/src/FilteredDirectoryIterator.php b/src/FilteredDirectoryIterator.php new file mode 100644 index 0000000..b3bfaf7 --- /dev/null +++ b/src/FilteredDirectoryIterator.php @@ -0,0 +1,33 @@ +basedir = $basedir; + $this->filter = $filter; + $dirIter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($basedir, + \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS + )); + parent::__construct($dirIter); + } + + public function accept(): bool { + $fs = new Filesystem(); + $current = $this->current(); + $fullPath = $current->getPath() . DIRECTORY_SEPARATOR . $current->getFilename(); + $relPath = rtrim($fs->makePathRelative($fullPath, $this->basedir), DIRECTORY_SEPARATOR); + return call_user_func($this->filter, $relPath, $current); + } + +} diff --git a/src/Php.php b/src/Php.php index f62fb23..620d6aa 100644 --- a/src/Php.php +++ b/src/Php.php @@ -20,6 +20,22 @@ public static function iniToArgv($ini) { return $buf; } + /** + * Convert a list of PHP INI values to PHP code. + * + * @param array $ini + * Ex: ['memory_limit'=>'256m'] + * @return string + * Ex: 'ini_set("memory_limit", "256m");' + */ + public static function iniToCode($ini) { + $buf = ''; + foreach ($ini as $k => $v) { + $buf .= sprintf("ini_set(%s, %s);\n", var_export($k, TRUE), var_export($v, TRUE)); + } + return $buf; + } + /** * @param array $ini * Ex: ['memory_limit'=>'256m'] diff --git a/src/PogoProject.php b/src/PogoProject.php index e9eacf9..95fb7e9 100644 --- a/src/PogoProject.php +++ b/src/PogoProject.php @@ -89,6 +89,43 @@ public function buildHelpers() { foreach (['pogolib'] as $helper) { file_put_contents("$path/.{$helper}.php", file_get_contents(dirname(__DIR__) . "/templates/{$helper}.php")); } + + $realScript = realpath($this->scriptMetadata->file); + $this->createLinkOrCopy($realScript, "$path/script.php"); + + file_put_contents("$path/run.sh", implode("\n", [ + '#!/usr/bin/env bash', + 'export POGO_SCRIPT=' . escapeshellarg($realScript), + 'export POGO_AUTOLOAD=' . escapeshellarg($this->getAutoloader()), + 'export POGO_STDIN=', + sprintf('[ -e %s ] && RUN_SCRIPT=%s || RUN_SCRIPT="$POGO_SCRIPT"', escapeshellarg("$path/script.php"), escapeshellarg("$path/script.php")), + sprintf('exec php %s "$RUN_SCRIPT" "$@"', + \Pogo\Php::iniToArgv($this->scriptMetadata->ini + ['auto_prepend_file' => $this->getAutoloader()]) + ), + '', + ])); + chmod("$path/run.sh", 0755); + + file_put_contents("$path/run.php", implode("\n", [ + '#!/usr/bin/env php', + '<' . '?php', + $this->scriptMetadata->ini ? ('/' . '/ WARNING: ini_set() may not work with all variables') : '', + \Pogo\Php::iniToCode($this->scriptMetadata->ini), + sprintf('$_SERVER["POGO_SCRIPT"] = $_ENV["POGO_SCRIPT"] = %s;', var_export($realScript, TRUE)), + 'putenv("POGO_SCRIPT=" . $_ENV["POGO_SCRIPT"]);', + '', + '$_SERVER["POGO_AUTOLOAD"] = $_ENV["POGO_AUTOLOAD"] = __DIR__ . "/vendor/autoload.php";', + 'putenv("POGO_AUTOLOAD=" . $_ENV["POGO_AUTOLOAD"]);', + '', + 'unset($_SERVER["POGO_STDIN"]);', + 'unset($_ENV["POGO_STDIN"]);', + 'putenv("POGO_STDIN");', + '', + 'require_once __DIR__ . "/vendor/autoload.php";', + 'require_once file_exists(__DIR__ . "/script.php") ? __DIR__ . "/script.php" : $_ENV["POGO_SCRIPT"];', + '', + ])); + chmod("$path/run.php", 0755); } public function buildComposer() { @@ -109,4 +146,16 @@ public function getAutoloader() { return $this->path . '/vendor/autoload.php'; } + private function createLinkOrCopy($in, $out) { + if (file_exists($out)) { + unlink($out); + } + if (preg_match('/(linux|darwin)/i', php_uname())) { + symlink($in, $out); + } + else { + copy($in, $out); + } + } + }