Skip to content

Commit

Permalink
Add support of dependencies resolution to solve the conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
francoispluchino committed Feb 19, 2017
1 parent 1baac76 commit d65dabd
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 3 deletions.
2 changes: 2 additions & 0 deletions FxpAssetPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Fxp\Composer\AssetPlugin\Config\Config;
use Fxp\Composer\AssetPlugin\Config\ConfigBuilder;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\ResolutionManager;
use Fxp\Composer\AssetPlugin\Repository\VcsPackageFilter;
use Fxp\Composer\AssetPlugin\Util\AssetPlugin;

Expand Down Expand Up @@ -87,6 +88,7 @@ public function activate(Composer $composer, IOInterface $io)
$this->io = $io;
$this->packageFilter = new VcsPackageFilter($this->config, $composer->getPackage(), $composer->getInstallationManager(), $installedRepository);
$this->assetRepositoryManager = new AssetRepositoryManager($io, $composer->getRepositoryManager(), $this->packageFilter);
$this->assetRepositoryManager->setResolutionManager(new ResolutionManager($this->config->getArray('resolutions')));

AssetPlugin::addRegistryRepositories($this->assetRepositoryManager, $this->packageFilter, $this->config);
AssetPlugin::setVcsTypeRepositories($composer->getRepositoryManager());
Expand Down
2 changes: 1 addition & 1 deletion Package/Loader/LazyAssetPackageLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ protected function preProcess(VcsDriverInterface $driver, array $data, $identifi
$data['source'] = $driver->getSource($identifier);
}

return (array) $data;
return $this->assetRepositoryManager->solveResolutions((array) $data);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions Repository/AbstractAssetVcsRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ protected function preProcessAsset(array $data)

// keep the name of the main identifier for all packages
$data['name'] = $this->packageName ?: $data['name'];
$data = $this->assetType->getPackageConverter()->convert($data, $vcsRepos);
$data = (array) $this->assetType->getPackageConverter()->convert($data, $vcsRepos);

return (array) $data;
return $this->assetRepositoryManager->solveResolutions($data);
}

/**
Expand Down
29 changes: 29 additions & 0 deletions Repository/AssetRepositoryManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class AssetRepositoryManager
*/
protected $pool;

/**
* @var ResolutionManager
*/
protected $resolutionManager;

/**
* @var RepositoryInterface[]
*/
Expand Down Expand Up @@ -86,6 +91,30 @@ public function setPool(Pool $pool)
return $this;
}

/**
* Set the dependency resolution manager.
*
* @param ResolutionManager $resolutionManager The dependency resolution manager
*/
public function setResolutionManager(ResolutionManager $resolutionManager)
{
$this->resolutionManager = $resolutionManager;
}

/**
* Solve the dependency resolutions.
*
* @param array $data
*
* @return array
*/
public function solveResolutions(array $data)
{
return null !== $this->resolutionManager
? $this->resolutionManager->solveResolutions($data)
: $data;
}

/**
* Adds asset vcs repositories.
*
Expand Down
1 change: 1 addition & 0 deletions Repository/NpmRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ protected function createArrayRepositoryConfig(array $packageConfigs)
foreach ($packageConfigs as $version => $config) {
$config['version'] = $version;
$config = $this->assetType->getPackageConverter()->convert($config);
$config = $this->assetRepositoryManager->solveResolutions($config);
$packages[] = $loader->load($config);
}

Expand Down
73 changes: 73 additions & 0 deletions Repository/ResolutionManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fxp\Composer\AssetPlugin\Repository;

/**
* Solve the conflicts of dependencies by the resolutions.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ResolutionManager
{
/**
* @var array
*/
protected $resolutions;

/**
* Constructor.
*
* @param array $resolutions The dependency resolutions
*/
public function __construct(array $resolutions = array())
{
$this->resolutions = $resolutions;
}

/**
* Solve the dependency resolutions.
*
* @param array $data The data of asset composer package
*
* @return array
*/
public function solveResolutions(array $data)
{
$data = $this->doSolveResolutions($data, 'require');
$data = $this->doSolveResolutions($data, 'require-dev');

return $data;
}

/**
* Solve the dependency resolutions.
*
* @param array $data The data of asset composer package
* @param string $section The dependency section in package
*
* @return array
*/
protected function doSolveResolutions(array $data, $section)
{
if (array_key_exists($section, $data) && is_array($data[$section])) {
foreach ($data[$section] as $dependency => &$range) {
foreach ($this->resolutions as $resolutionDependency => $resolutionRange) {
if ($dependency === $resolutionDependency) {
$range = $resolutionRange;
}
}
}
}

return $data;
}
}
45 changes: 45 additions & 0 deletions Resources/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,51 @@ You can further define this option for each package:
With this configuration, all your github packages will use the native Git, except for
the `bower-asset/example-asset1` package.

### Solve the conflicts of asset dependencies

Bower include a [resolution section](https://jaketrent.com/post/bower-resolutions) to
solve the conflicts between 2 same dependencies but with different versions.

As for NPM, it's possible to install several versions of the same dependency by different
dependencies, which is not the case for Bower and Composer. Only the installation of a
single version compatible for all dependencies is possible.

The dependency resolution would force (replace) a version or range version directly in the
root Composer package.

**Example:**
```json
"name": "foo/bar",
"require": {
"bower-asset/jquery": "^2.2.0"
}
```
```json
"name": "bar/baz",
"require": {
"bower-asset/jquery": "2.0.*"
}
```
```json
"name": "root/package",
"require": {
"foo/bar": "^1.0.0",
"bar/baz": "^1.0.0"
}
"config": {
"fxp-asset": {
"resolutions": {
"bower-asset/jquery": "^3.0.0"
}
}
}
```

Result, all asset packages with the `bower-asset/jquery` dependency will use the `^3.0.0` range version.

> **Note:**
> Be careful when replacing the version, and check the compatibility before.
### Define the config for all projects

You can define each option (`config.fxp-asset.*`) in each project in the `composer.json`
Expand Down
6 changes: 6 additions & 0 deletions Tests/Package/Loader/LazyAssetPackageLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ protected function setUp()
$this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)
->disableOriginalConstructor()->getMock();

$this->assetRepositoryManager->expects($this->any())
->method('solveResolutions')
->willReturnCallback(function ($value) {
return $value;
});

$this->lazyPackage
->expects($this->any())
->method('getName')
Expand Down
84 changes: 84 additions & 0 deletions Tests/Repository/AssetRepositoryManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fxp\Composer\AssetPlugin\Tests\Repository;

use Composer\IO\IOInterface;
use Composer\Repository\RepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\ResolutionManager;
use Fxp\Composer\AssetPlugin\Repository\VcsPackageFilter;

/**
* Tests of Asset Repository Manager.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class AssetRepositoryManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ResolutionManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $resolutionManager;

/**
* @var AssetRepositoryManager
*/
protected $assertRepositoryManager;

protected function setUp()
{
/* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject $io */
$io = $this->getMockBuilder(IOInterface::class)->getMock();
/* @var RepositoryManager|\PHPUnit_Framework_MockObject_MockObject $rm */
$rm = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
/* @var VcsPackageFilter|\PHPUnit_Framework_MockObject_MockObject $filter */
$filter = $this->getMockBuilder(VcsPackageFilter::class)->disableOriginalConstructor()->getMock();

$this->resolutionManager = $this->getMockBuilder(ResolutionManager::class)->getMock();
$this->assertRepositoryManager = new AssetRepositoryManager($io, $rm, $filter);
}

public function getDataForSolveResolutions()
{
return array(
array(true),
array(false),
);
}

/**
* @dataProvider getDataForSolveResolutions
*
* @param bool $withResolutionManager
*/
public function testSolveResolutions($withResolutionManager)
{
$expected = array(
'name' => 'foo/bar',
);

if ($withResolutionManager) {
$this->assertRepositoryManager->setResolutionManager($this->resolutionManager);
$this->resolutionManager->expects($this->once())
->method('solveResolutions')
->with($expected)
->willReturn($expected);
} else {
$this->resolutionManager->expects($this->never())
->method('solveResolutions');
}

$data = $this->assertRepositoryManager->solveResolutions($expected);

$this->assertSame($expected, $data);
}
}
6 changes: 6 additions & 0 deletions Tests/Repository/AssetVcsRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ protected function setUp()
$this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)
->disableOriginalConstructor()
->getMock();

$this->assetRepositoryManager->expects($this->any())
->method('solveResolutions')
->willReturnCallback(function ($value) {
return $value;
});
}

protected function tearDown()
Expand Down
54 changes: 54 additions & 0 deletions Tests/Repository/ResolutionManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fxp\Composer\AssetPlugin\Tests\Repository;

use Fxp\Composer\AssetPlugin\Repository\ResolutionManager;

/**
* Tests of Resolution Manager.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ResolutionManagerTest extends \PHPUnit_Framework_TestCase
{
public function testSolveResolutions()
{
$rm = new ResolutionManager(array(
'foo/bar' => '^2.2.0',
'bar/foo' => '^0.2.0',
));

$data = $rm->solveResolutions(array(
'require' => array(
'foo/bar' => '2.0.*',
'foo/baz' => '~1.0',
),
'require-dev' => array(
'bar/foo' => '^0.1.0',
'test/dev' => '~1.0@dev',
),
));

$expected = array(
'require' => array(
'foo/bar' => '^2.2.0',
'foo/baz' => '~1.0',
),
'require-dev' => array(
'bar/foo' => '^0.2.0',
'test/dev' => '~1.0@dev',
),
);

$this->assertSame($expected, $data);
}
}

0 comments on commit d65dabd

Please # to comment.