From abb3478ba50f26936b0f0a536ab0adb1d63d72f4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 Jun 2022 17:32:28 +0200 Subject: [PATCH] Allow packs to embed their recipe --- src/Downloader.php | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/Recipe.php | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/Downloader.php b/src/Downloader.php index 4e2195a52..f1bf5ad99 100644 --- a/src/Downloader.php +++ b/src/Downloader.php @@ -18,6 +18,7 @@ use Composer\DependencyResolver\Operation\UpdateOperation; use Composer\IO\IOInterface; use Composer\Json\JsonFile; +use Composer\Package\PackageInterface; use Composer\Util\Http\Response as ComposerResponse; use Composer\Util\HttpDownloader; use Composer\Util\Loop; @@ -51,6 +52,7 @@ class Downloader private $caFile; private $enabled = true; private $composer; + private $vendorDir; public function __construct(Composer $composer, IoInterface $io, $rfs) { @@ -94,6 +96,7 @@ public function __construct(Composer $composer, IoInterface $io, $rfs) $this->cache = new ComposerCache($io, $config->get('cache-repo-dir').'/flex'); $this->sess = bin2hex(random_bytes(16)); $this->composer = $composer; + $this->vendorDir = $config->get('vendor-dir'); } public function getSessionId(): string @@ -155,6 +158,7 @@ public function getRecipes(array $operations): array $this->conflicts = []; } + $localRecipes = []; $data = []; $urls = []; $chunk = ''; @@ -175,6 +179,11 @@ public function getRecipes(array $operations): array } } + if ('symfony-pack' === $package->getType() && is_file($this->vendorDir.'/'.$package->getName().'/manifest.json')) { + $localRecipes[$package->getName()] = $package; + continue; + } + $version = $package->getPrettyVersion(); if ($operation instanceof InformationOperation && $operation->getVersion()) { $version = $operation->getVersion(); @@ -310,6 +319,14 @@ public function getRecipes(array $operations): array } } + foreach ($localRecipes as $name => $package) { + $data['locks'][$name] = [ + 'version' => $package->getPrettyVersion(), + ]; + + $data['manifests'][$name] = $this->getLocalRecipe($package); + } + return $data; } @@ -328,6 +345,10 @@ public function removeRecipeFromIndex(string $packageName, string $version) */ private function get(array $urls, bool $isRecipe = false, int $try = 3): array { + if (!$urls) { + return []; + } + $responses = []; $retries = []; $options = []; @@ -481,6 +502,47 @@ private function initialize() } } + private function getLocalRecipe(PackageInterface $package): array + { + $name = $package->getName(); + $path = $this->vendorDir.'/'.$name; + $manifest = json_decode(file_get_contents($path.'/manifest.json'), true); + if (!\is_array($manifest)) { + throw new \LogicException(sprintf('Invalid recipe manifest in "%s".', $path)); + } + $files = []; + $it = new \RecursiveDirectoryIterator($path); + $it->setFlags($it::SKIP_DOTS | $it::FOLLOW_SYMLINKS | $it::UNIX_PATHS); + + foreach (new \RecursiveIteratorIterator($it) as $path => $file) { + $file = substr($path, 1 + \strlen($name)); + if (is_dir($path) || 'manifest.json' === $file || 'composer.json') { + continue; + } + if ('post-install.txt' === $file) { + $manifest['post-install-output'] = explode("\n", rtrim(str_replace("\r", '', file_get_contents($path)), "\n")); + continue; + } + if ('Makefile' === $file) { + $manifest['makefile'] = explode("\n", rtrim(str_replace("\r", '', file_get_contents($path)), "\n")); + continue; + } + $contents = file_get_contents($path); + $files[$file] = [ + 'contents' => preg_match('//u', $contents) ? explode("\n", $contents) : base64_encode($contents), + 'executable' => is_executable($path), + ]; + } + + return [ + 'manifest' => $manifest, + 'files' => $files, + 'package' => $name, + 'origin' => sprintf('%s:%s@vendor:manifest.json', $name, $package->getPrettyVersion()), + 'is_contrib' => false, + ]; + } + private static function generateCacheKey(string $url): string { $url = preg_replace('{^https://api.github.com/repos/([^/]++/[^/]++)/contents/}', '$1/', $url); diff --git a/src/Recipe.php b/src/Recipe.php index 3c8697245..8051bcd44 100644 --- a/src/Recipe.php +++ b/src/Recipe.php @@ -83,7 +83,7 @@ public function getFormattedOrigin(): string public function getURL(): string { - if (!$this->data['origin']) { + if (empty($this->data['origin'])) { return ''; }