Skip to content
This repository has been archived by the owner on Mar 1, 2023. It is now read-only.

Commit

Permalink
fixes #50
Browse files Browse the repository at this point in the history
  • Loading branch information
prisis committed Aug 19, 2018
1 parent e3591dc commit 2312c32
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 61 deletions.
35 changes: 28 additions & 7 deletions src/Automatic/Automatic.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,39 @@ public function activate(Composer $composer, IOInterface $io): void
$installationManager->addInstaller($this->container->get(ConfiguratorInstaller::class));
$installationManager->addInstaller($this->container->get(SkeletonInstaller::class));

/** @var \Composer\IO\IOInterface $io */
$io = $this->container->get(IOInterface::class);

$manager = RepositoryFactory::manager(
$this->container->get(IOInterface::class),
$io,
$this->container->get(Config::class),
$this->container->get(Composer::class)->getEventDispatcher(),
$this->container->get(ParallelDownloader::class)
);

if (\getenv('SYMFONY_REQUIRE') !== false) {
$symfonyRequire = \getenv('SYMFONY_REQUIRE');
} else {
$symfonyRequire = $this->container->get('composer-extra')['symfony']['require'] ?? '>=3.4';
/** @var \Narrowspark\Automatic\TagsManager $tagsManager */
$tagsManager = $this->container->get(TagsManager::class);
$extra = $this->container->get('composer-extra');

if (isset($extra['require'])) {
foreach ($extra['require'] as $name => $version) {
if (\is_int($name)) {
$io->writeError(\sprintf('Constrain [%s] skipped, because package name is a number [%s]', $version, $name));

continue;
}

if (\mb_strpos($name, '/') === false) {
$io->writeError(\sprintf('Constrain [%s] skipped, package name [%s] without a slash is not supported', $version, $name));

continue;
}

$tagsManager->addConstraint($name, $version);
}
}

$setRepositories = Closure::bind(function (RepositoryManager $manager) use ($symfonyRequire) {
$setRepositories = Closure::bind(function (RepositoryManager $manager) use ($tagsManager) {
$manager->repositoryClasses = $this->repositoryClasses;
$manager->setRepositoryClass('composer', TruncatedComposerRepository::class);
$manager->repositories = $this->repositories;
Expand All @@ -182,7 +201,7 @@ public function activate(Composer $composer, IOInterface $io): void
$manager->repositories[$i++] = $repo;

if ($repo instanceof TruncatedComposerRepository) {
$repo->setSymfonyRequire($symfonyRequire);
$repo->setTagsManager($tagsManager);
}
}

Expand Down Expand Up @@ -447,6 +466,8 @@ public function onPostUpdate(Event $event, array $operations = []): void
);
}

$io->writeError('<info>Writing automatic lock file</info>');

$lock->write();

if ($this->shouldUpdateComposerLock) {
Expand Down
3 changes: 3 additions & 0 deletions src/Automatic/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ public function __construct(Composer $composer, IOInterface $io)
$container->get('composer-extra')
);
},
TagsManager::class => static function (Container $container) {
return new TagsManager($container->get(IOInterface::class));
},
];
}

Expand Down
63 changes: 12 additions & 51 deletions src/Automatic/Prefetcher/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
namespace Narrowspark\Automatic\Prefetcher;

use Composer\Cache as BaseComposerCache;
use Composer\IO\IOInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\VersionParser;
use Composer\Util\Filesystem;
use Narrowspark\Automatic\TagsManager;

/**
* Ported from symfony flex, see original.
Expand All @@ -18,35 +15,22 @@
class Cache extends BaseComposerCache
{
/**
* A version parser instance.
* A tags manager instance.
*
* @var \Composer\Semver\VersionParser
* @var null|\Narrowspark\Automatic\TagsManager
*/
private $versionParser;
private $tagsManager;

/**
* A composer constraint implementation.
* Set a tags manager instance.
*
* @var \Composer\Semver\Constraint\ConstraintInterface
*/
private $symfonyRequire;

/**
* {@inheritdoc}
*/
public function __construct(IOInterface $io, $cacheDir, $whitelist = 'a-z0-9.', Filesystem $filesystem = null)
{
parent::__construct($io, $cacheDir, $whitelist, $filesystem);

$this->versionParser = new VersionParser();
}

/**
* @param string $symfonyRequire
* @param \Narrowspark\Automatic\TagsManager $tagsManager
*
* @return void
*/
public function setSymfonyRequire(string $symfonyRequire): void
public function setTagsManager(TagsManager $tagsManager): void
{
$this->symfonyRequire = $this->versionParser->parseConstraints($symfonyRequire);
$this->tagsManager = $tagsManager;
}

/**
Expand All @@ -58,7 +42,7 @@ public function read($file)
{
$content = parent::read($file);

if (\mb_strpos($file, 'provider-symfony$') === 0 && \is_array($data = \json_decode($content, true))) {
if ($this->tagsManager !== null && $this->tagsManager->hasProvider($file) && \is_array($data = \json_decode($content, true))) {
$content = \json_encode($this->removeLegacyTags($data));
}

Expand All @@ -74,29 +58,6 @@ public function read($file)
*/
public function removeLegacyTags(array $data): array
{
if ($this->symfonyRequire === null || ! isset($data['packages']['symfony/symfony'])) {
return $data;
}

$symfonyVersions = $data['packages']['symfony/symfony'];

foreach ($data['packages'] as $name => $versions) {
foreach ($versions as $version => $package) {
if ('symfony/symfony' !== $name && ! isset($symfonyVersions[\preg_replace('/^(\d++\.\d++)\..*/', '$1.x-dev', $version)]['replace'][$name])) {
continue;
}

$normalizedVersion = $package['extra']['branch-alias'][$version] ?? null;
$normalizedVersion = $normalizedVersion ? $this->versionParser->normalize($normalizedVersion) : $package['version_normalized'];

$provider = new Constraint('==', $normalizedVersion);

if (! $this->symfonyRequire->matches($provider)) {
unset($data['packages'][$name][$version]);
}
}
}

return $data;
return $this->tagsManager->removeLegacyTags($data);
}
}
11 changes: 8 additions & 3 deletions src/Automatic/Prefetcher/TruncatedComposerRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Composer\IO\IOInterface;
use Composer\Repository\ComposerRepository as BaseComposerRepository;
use Composer\Util\RemoteFilesystem;
use Narrowspark\Automatic\TagsManager;

/**
* Ported from symfony flex, see original.
Expand All @@ -32,11 +33,15 @@ public function __construct(array $repoConfig, IOInterface $io, Config $config,
}

/**
* @param string $symfonyRequire
* Set a tags manager instance.
*
* @param \Narrowspark\Automatic\TagsManager $tagsManager
*
* @return void
*/
public function setSymfonyRequire(string $symfonyRequire): void
public function setTagsManager(TagsManager $tagsManager): void
{
$this->cache->setSymfonyRequire($symfonyRequire);
$this->cache->setTagsManager($tagsManager);
}

/**
Expand Down
112 changes: 112 additions & 0 deletions src/Automatic/TagsManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace Narrowspark\Automatic;

use Composer\IO\IOInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\VersionParser;

final class TagsManager
{
/**
* The composer io implementation.
*
* @var \Composer\IO\IOInterface
*/
private $io;

/**
* A version parser instance.
*
* @var \Composer\Semver\VersionParser
*/
private $versionParser;

/**
* @var \Composer\Semver\Constraint\Constraint[]
*/
private $legacyTags = [];

/**
* TagsManager constructor.
*
* @param IOInterface $io
*/
public function __construct(IOInterface $io)
{
$this->io = $io;
$this->versionParser = new VersionParser();

$this->addConstraint('symfony/symfony', '>=3.4');
}

/**
* Add a legacy package constraint.
*
* @param string $name
* @param string $require
*
* @return void
*/
public function addConstraint(string $name, string $require): void
{
$this->legacyTags[$name] = $this->versionParser->parseConstraints($require);
}

/**
* Check if the provider is supported.
*
* @param string $file the composer provider file name
*
* @return bool
*/
public function hasProvider(string $file): bool
{
foreach ($this->legacyTags as $name => $constraint) {
[$namespace, $packageName] = \explode('/', $name, 2);

if (\mb_strpos($file, \sprintf('provider-%s$', $namespace)) !== false) {
return true;
}
}

return false;
}

/**
* @param array $data
*
* @return array
*/
public function removeLegacyTags(array $data): array
{
if (\count($data) === 0) {
return $data;
}

foreach ($data['packages'] as $name => $versions) {
if (! isset($this->legacyTags[$name])) {
continue;
}

foreach ($versions as $version => $package) {
foreach ($this->legacyTags[$name] as $legacyName => $legacyVersion) {
if (isset($data['packages'][$legacyName]) && $data['packages'][$legacyName][\preg_replace('/^(\d++\.\d++)\..*/', '$1.x-dev', $version)]['replace'][$name] !== 'self.version') {
continue;
}
}

$normalizedVersion = $package['extra']['branch-alias'][$version] ?? null;
$normalizedVersion = $normalizedVersion ? $this->versionParser->normalize($normalizedVersion) : $package['version_normalized'];

if (! $this->legacyTags[$name]->matches(new Constraint('==', $normalizedVersion))) {
$this->io->writeError(\sprintf('<info>Restricting packages listed in [%s] to [%s]</info>', $name, (string) $this->legacyTags[$name]));

unset($data['packages'][$name][$version]);
}
}
}

return $data;
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions tests/Automatic/TagsManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Narrowspark\Automatic\Test;

use Composer\IO\IOInterface;
use Narrowspark\Automatic\TagsManager;
use Narrowspark\TestingHelper\Phpunit\MockeryTestCase;

/**
* @internal
*/
final class TagsManagerTest extends MockeryTestCase
{
/**
* @var array
*/
private $downloadFileList;

/**
* @var \Composer\IO\IOInterface|\Mockery\MockInterface
*/
private $ioMock;

/**
* @var \Narrowspark\Automatic\TagsManager
*/
private $tagsManger;

/**
* {@inheritdoc}
*/
protected function setUp(): void
{
parent::setUp();

$pPath = __DIR__ . \DIRECTORY_SEPARATOR . 'Fixture' . \DIRECTORY_SEPARATOR . 'Packagist';

$this->downloadFileList = [
$pPath . \DIRECTORY_SEPARATOR . 'provider-codeigniter$framework.json',
$pPath . \DIRECTORY_SEPARATOR . 'provider-symfony$security-guard.json',
$pPath . \DIRECTORY_SEPARATOR . 'provider-symfony$symfony.json',
$pPath . \DIRECTORY_SEPARATOR . 'provider-zendframework$zend-diactoros.json',
];

$this->ioMock = $this->mock(IOInterface::class);
$this->tagsManger = new TagsManager($this->ioMock);
}

public function testHasProvider(): void
{
$count = 0;

$this->tagsManger->addConstraint('symfony/security-guard', '>=4.1');

foreach ($this->downloadFileList as $file) {
if ($this->tagsManger->hasProvider($file)) {
$count++;
}
}

static::assertSame(2, $count);
}

public function testRemoveLegacyTagsWithSymfony(): void
{
$originalData = \json_decode(\file_get_contents($this->downloadFileList[3]), true);

$data = $this->tagsManger->removeLegacyTags($originalData);

static::assertNotSame($originalData['packages'], $data['packages']);
}
}

0 comments on commit 2312c32

Please sign in to comment.