Skip to content

Commit 9c6a442

Browse files
committed
Add distribution builder
1 parent e764646 commit 9c6a442

File tree

5 files changed

+142
-8
lines changed

5 files changed

+142
-8
lines changed

src/DependencyInjection/DirigentConfiguration.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public function getConfigTreeBuilder(): TreeBuilder
3737
->scalarNode('periodic_update_interval')->defaultValue('P1W')->end()
3838
->end()
3939
->end()
40+
->arrayNode('dist_builder')
41+
->canBeEnabled()
42+
->children()
43+
->booleanNode('dev_packages')->defaultFalse()->end()
44+
->end()
45+
->end()
4046
->arrayNode('dist_mirroring')
4147
->canBeEnabled()
4248
->children()

src/DependencyInjection/DirigentExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
3333
$container->setParameter('dirigent.packages.periodic_updates', $mergedConfig['packages']['periodic_updates']);
3434
$container->setParameter('dirigent.packages.periodic_update_interval', $mergedConfig['packages']['periodic_update_interval']);
3535

36+
$container->setParameter('dirigent.dist_builder.enabled', $mergedConfig['dist_builder']['enabled']);
37+
$container->setParameter('dirigent.dist_builder.dev_packages', $mergedConfig['dist_builder']['dev_packages']);
38+
3639
$container->setParameter('dirigent.dist_mirroring.enabled', $mergedConfig['dist_mirroring']['enabled']);
3740
$container->setParameter('dirigent.dist_mirroring.preferred', $mergedConfig['dist_mirroring']['preferred']);
3841
$container->setParameter('dirigent.dist_mirroring.dev_packages', $mergedConfig['dist_mirroring']['dev_packages']);

src/Doctrine/Entity/Version.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace CodedMonkey\Dirigent\Doctrine\Entity;
44

55
use CodedMonkey\Dirigent\Doctrine\Repository\VersionRepository;
6+
use Composer\Package\Package as ComposerPackage;
7+
use Composer\Package\PackageInterface;
68
use Composer\Package\Version\VersionParser;
79
use Composer\Pcre\Preg;
810
use Doctrine\Common\Collections\ArrayCollection;
@@ -512,6 +514,21 @@ public function setReleasedAt(?\DateTimeInterface $releasedAt): void
512514
$this->releasedAt = $releasedAt;
513515
}
514516

517+
public function getSourceReference(): ?string
518+
{
519+
return $this->source['reference'] ?? null;
520+
}
521+
522+
public function getSourceType(): ?string
523+
{
524+
return $this->source['type'] ?? null;
525+
}
526+
527+
public function getSourceUrl(): ?string
528+
{
529+
return $this->source['url'] ?? null;
530+
}
531+
515532
public function getDistReference(): ?string
516533
{
517534
return $this->dist['reference'] ?? null;
@@ -703,6 +720,16 @@ public function toComposerArray(): array
703720
return $data;
704721
}
705722

723+
public function toComposerPackage(): PackageInterface
724+
{
725+
$cp = new ComposerPackage($this->getName(), $this->getNormalizedVersion(), $this->getVersion());
726+
727+
$cp->setSourceReference($this->getSourceReference());
728+
$cp->setSourceUrl($this->getSourceUrl());
729+
730+
return $cp;
731+
}
732+
706733
private function sortAuthorKeys(string $a, string $b): int
707734
{
708735
static $order = ['name' => 1, 'email' => 2, 'homepage' => 3, 'role' => 4];

src/Package/PackageDistributionResolver.php

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,33 @@
33
namespace CodedMonkey\Dirigent\Package;
44

55
use CodedMonkey\Dirigent\Composer\ComposerClient;
6+
use CodedMonkey\Dirigent\Composer\ConfigFactory;
67
use CodedMonkey\Dirigent\Doctrine\Entity\Version;
8+
use Composer\IO\NullIO;
9+
use Composer\Pcre\Preg;
10+
use Composer\Util\Filesystem as ComposerFilesystem;
11+
use Composer\Util\Git as GitUtility;
12+
use Composer\Util\ProcessExecutor;
13+
use Composer\Util\Url;
714
use Symfony\Component\DependencyInjection\Attribute\Autowire;
815
use Symfony\Component\Filesystem\Filesystem;
916

1017
readonly class PackageDistributionResolver
1118
{
1219
private Filesystem $filesystem;
13-
private string $storagePath;
20+
private string $distributionStoragePath;
1421

1522
public function __construct(
1623
private ComposerClient $composer,
1724
#[Autowire(param: 'dirigent.storage.path')]
1825
string $storagePath,
26+
#[Autowire(param: 'dirigent.dist_builder.enabled')]
27+
private bool $buildDistributions,
28+
#[Autowire(param: 'dirigent.dist_builder.dev_packages')]
29+
private bool $buildDevDistributions,
1930
) {
2031
$this->filesystem = new Filesystem();
21-
$this->storagePath = "$storagePath/distribution";
32+
$this->distributionStoragePath = "$storagePath/distribution";
2233
}
2334

2435
public function exists(string $packageName, string $packageVersion, string $reference, string $type): bool
@@ -28,7 +39,7 @@ public function exists(string $packageName, string $packageVersion, string $refe
2839

2940
public function path(string $packageName, string $packageVersion, string $reference, string $type): string
3041
{
31-
return "{$this->storagePath}/{$packageName}/{$packageVersion}-{$reference}.{$type}";
42+
return "$this->distributionStoragePath/$packageName/$packageVersion-$reference.$type";
3243
}
3344

3445
public function resolve(Version $version, string $reference, string $type): bool
@@ -41,17 +52,77 @@ public function resolve(Version $version, string $reference, string $type): bool
4152
return true;
4253
}
4354

44-
if ($reference !== $version->getDistReference() || $type !== $version->getDistType()) {
55+
if (
56+
null === $version->getDist()
57+
&& $this->buildDistributions
58+
&& (!$version->isDevelopment() || $this->buildDevDistributions)
59+
) {
60+
return $this->build($version, $reference, $type);
61+
} elseif (null !== $version->getDist()) {
62+
return $this->mirror($version, $reference, $type);
63+
}
64+
65+
return false;
66+
}
67+
68+
private function build(Version $version, string $reference, string $type): bool
69+
{
70+
// Skip building of outdated references for now
71+
if ($reference !== $version->getSourceReference()) {
72+
return false;
73+
}
74+
75+
// Only provide .zip support for now
76+
if ('zip' !== $type) {
77+
return false;
78+
}
79+
80+
$package = $version->getPackage();
81+
$repositoryUrl = $package->getRepositoryUrl();
82+
$distributionPath = $this->path($package->getName(), $version->getNormalizedVersion(), $reference, $type);
83+
84+
$io = new NullIO();
85+
$config = ConfigFactory::createForVcsRepository($repositoryUrl, $package->getRepositoryCredentials());
86+
87+
$gitUtility = new GitUtility(
88+
$io,
89+
$config,
90+
$process = new ProcessExecutor($io),
91+
new ComposerFilesystem($process),
92+
);
93+
94+
$cacheRepositoryName = Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($repositoryUrl));
95+
$cachePath = $config->get('cache-vcs-dir') . '/' . $cacheRepositoryName . '/';
96+
97+
$this->filesystem->mkdir(dirname($distributionPath));
98+
99+
$gitUtility->runCommands([
100+
['git', 'archive', '--format=zip', "--output=$distributionPath", $reference],
101+
], $repositoryUrl, $cachePath);
102+
103+
return true;
104+
}
105+
106+
private function mirror(Version $version, string $reference, string $type): bool
107+
{
108+
// Skip mirroring of outdated references for now
109+
if ($reference !== $version->getDistReference()) {
110+
return false;
111+
}
112+
113+
// The distribution type must match the origin format
114+
if ($type !== $version->getDistType()) {
45115
return false;
46116
}
47117

48-
$distUrl = $version->getDistUrl();
49-
$path = $this->path($packageName, $packageVersion, $reference, $type);
118+
$package = $version->getPackage();
119+
$distributionUrl = $version->getDistUrl();
120+
$distributionPath = $this->path($package->getName(), $version->getNormalizedVersion(), $reference, $type);
50121

51-
$this->filesystem->mkdir(dirname($path));
122+
$this->filesystem->mkdir(dirname($distributionPath));
52123

53124
$httpDownloader = $this->composer->createHttpDownloader();
54-
$httpDownloader->copy($distUrl, $path);
125+
$httpDownloader->copy($distributionUrl, $distributionPath);
55126

56127
return true;
57128
}

src/Package/PackageProviderManager.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@
66
use Composer\MetadataMinifier\MetadataMinifier;
77
use Symfony\Component\DependencyInjection\Attribute\Autowire;
88
use Symfony\Component\Filesystem\Filesystem;
9+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10+
use Symfony\Component\Routing\RouterInterface;
911

1012
readonly class PackageProviderManager
1113
{
1214
private Filesystem $filesystem;
1315
private string $storagePath;
1416

1517
public function __construct(
18+
private RouterInterface $router,
1619
#[Autowire(param: 'dirigent.storage.path')]
1720
string $storagePath,
21+
#[Autowire(param: 'dirigent.dist_builder.enabled')]
22+
private bool $buildDistributions,
23+
#[Autowire(param: 'dirigent.dist_builder.dev_packages')]
24+
private bool $buildDevDistributions,
1825
) {
1926
$this->filesystem = new Filesystem();
2027
$this->storagePath = "$storagePath/provider";
@@ -31,6 +38,26 @@ public function dump(Package $package): void
3138
foreach ($versions as $version) {
3239
$versionData = $version->toComposerArray();
3340

41+
if (
42+
!$version->getDist()
43+
&& $this->buildDistributions
44+
&& (!$version->isDevelopment() || $this->buildDevDistributions)
45+
) {
46+
$distributionUrl = $this->router->generate('api_package_distribution', [
47+
'packageName' => $package->getName(),
48+
'packageVersion' => $version->getNormalizedVersion(),
49+
'reference' => $version->getSourceReference(),
50+
'type' => 'zip',
51+
], UrlGeneratorInterface::ABSOLUTE_URL);
52+
53+
$versionData['dist'] = [
54+
'type' => 'zip',
55+
'url' => $distributionUrl,
56+
'reference' => $version->getSourceReference(),
57+
'shasum' => '',
58+
];
59+
}
60+
3461
if (!$version->isDevelopment()) {
3562
$releasePackages[] = $versionData;
3663
} else {

0 commit comments

Comments
 (0)