FestinHegre/vendor/symfony/asset-mapper/ImportMap/RemotePackageDownloader.php
2024-09-26 17:26:04 +02:00

163 lines
5.4 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\AssetMapper\ImportMap;
use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolverInterface;
/**
* @final
*/
class RemotePackageDownloader
{
private array $installed;
public function __construct(
private readonly RemotePackageStorage $remotePackageStorage,
private readonly ImportMapConfigReader $importMapConfigReader,
private readonly PackageResolverInterface $packageResolver,
) {
}
/**
* Downloads all packages.
*
* @return string[] The downloaded packages
*/
public function downloadPackages(?callable $progressCallback = null): array
{
try {
$installed = $this->loadInstalled();
} catch (\InvalidArgumentException) {
$installed = [];
}
$entries = $this->importMapConfigReader->getEntries();
$remoteEntriesToDownload = [];
$newInstalled = [];
foreach ($entries as $entry) {
if (!$entry->isRemotePackage()) {
continue;
}
// if the file exists at the correct version, skip it
if (
isset($installed[$entry->importName])
&& $installed[$entry->importName]['version'] === $entry->version
&& $this->remotePackageStorage->isDownloaded($entry)
&& $this->areAllExtraFilesDownloaded($entry, $installed[$entry->importName]['extraFiles'])
) {
$newInstalled[$entry->importName] = $installed[$entry->importName];
continue;
}
$remoteEntriesToDownload[$entry->importName] = $entry;
}
if (!$remoteEntriesToDownload) {
return [];
}
$contents = $this->packageResolver->downloadPackages($remoteEntriesToDownload, $progressCallback);
$downloadedPackages = [];
foreach ($remoteEntriesToDownload as $package => $entry) {
if (!isset($contents[$package])) {
throw new \LogicException(sprintf('The package "%s" was not downloaded.', $package));
}
$this->remotePackageStorage->save($entry, $contents[$package]['content']);
foreach ($contents[$package]['extraFiles'] as $extraFilename => $extraFileContents) {
$this->remotePackageStorage->saveExtraFile($entry, $extraFilename, $extraFileContents);
}
$newInstalled[$package] = [
'version' => $entry->version,
'dependencies' => $contents[$package]['dependencies'] ?? [],
'extraFiles' => array_keys($contents[$package]['extraFiles']),
];
$downloadedPackages[] = $package;
unset($contents[$package]);
}
if ($contents) {
throw new \LogicException(sprintf('The following packages were unexpectedly downloaded: "%s".', implode('", "', array_keys($contents))));
}
$this->saveInstalled($newInstalled);
return $downloadedPackages;
}
/**
* @return string[]
*/
public function getDependencies(string $importName): array
{
$installed = $this->loadInstalled();
if (!isset($installed[$importName])) {
throw new \InvalidArgumentException(sprintf('The "%s" vendor asset is missing. Run "php bin/console importmap:install".', $importName));
}
return $installed[$importName]['dependencies'];
}
public function getVendorDir(): string
{
return $this->remotePackageStorage->getStorageDir();
}
/**
* @return array<string, array{path: string, version: string, dependencies: array<string, string>, extraFiles: array<string, string>}>
*/
private function loadInstalled(): array
{
if (isset($this->installed)) {
return $this->installed;
}
$installedPath = $this->remotePackageStorage->getStorageDir().'/installed.php';
$installed = is_file($installedPath) ? (static fn () => include $installedPath)() : [];
foreach ($installed as $package => $data) {
if (!isset($data['version'])) {
throw new \InvalidArgumentException(sprintf('The package "%s" is missing its version.', $package));
}
if (!isset($data['dependencies'])) {
throw new \LogicException(sprintf('The package "%s" is missing its dependencies.', $package));
}
if (!isset($data['extraFiles'])) {
$installed[$package]['extraFiles'] = [];
}
}
return $this->installed = $installed;
}
private function saveInstalled(array $installed): void
{
$this->installed = $installed;
file_put_contents($this->remotePackageStorage->getStorageDir().'/installed.php', sprintf('<?php return %s;', var_export($installed, true)));
}
private function areAllExtraFilesDownloaded(ImportMapEntry $entry, array $extraFilenames): bool
{
foreach ($extraFilenames as $extraFilename) {
if (!$this->remotePackageStorage->isExtraFileDownloaded($entry, $extraFilename)) {
return false;
}
}
return true;
}
}