Skip to content

Commit e235dfb

Browse files
Klaas SangersJan-Marten de Boer
Klaas Sangers
authored and
Jan-Marten de Boer
committed
Merged in feature/PD-594 (pull request #1)
Feature/PD-594
2 parents 5e4b0c1 + 075dab7 commit e235dfb

File tree

3 files changed

+349
-42
lines changed

3 files changed

+349
-42
lines changed

composer.json

+46-42
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,51 @@
11
{
2-
"name": "mediact/composer-dependency-installer",
3-
"description": "Install Composer dependencies.",
4-
"type": "library",
5-
"license": "proprietary",
6-
"authors": [
7-
{
8-
"name": "MediaCT",
9-
"email": "[email protected]"
2+
"name": "mediact/composer-dependency-installer",
3+
"description": "Install Composer dependencies.",
4+
"type": "library",
5+
"license": "proprietary",
6+
"authors": [
7+
{
8+
"name": "MediaCT",
9+
"email": "[email protected]"
10+
},
11+
{
12+
"name": "Klaas Sangers",
13+
"role": "developer"
14+
},
15+
{
16+
"name": "Jan-Marten de Boer",
17+
"role": "developer"
18+
}
19+
],
20+
"repositories": {
21+
"0": {
22+
"type": "composer",
23+
"url": "https://composer.mediact.nl"
24+
},
25+
"mediact": {
26+
"type": "composer",
27+
"url": "https://composer.mediact.nl"
28+
}
1029
},
11-
{
12-
"name": "Klaas Sangers",
13-
"role": "developer"
30+
"minimum-stability": "stable",
31+
"prefer-stable": true,
32+
"require": {
33+
"php": "^7.0",
34+
"composer/composer": "<2.0.0"
1435
},
15-
{
16-
"name": "Jan-Marten de Boer",
17-
"role": "developer"
18-
}
19-
],
20-
"repositories": [
21-
{
22-
"type": "composer",
23-
"url": "https://composer.mediact.nl"
24-
}
25-
],
26-
"minimum-stability": "stable",
27-
"prefer-stable": true,
28-
"require": {
29-
"php": "^7.0",
30-
"composer/composer": "@stable"
31-
},
32-
"require-dev": {
33-
"phpunit/phpunit": "@stable",
34-
"mediact/testing-suite": "@stable",
35-
"kint-php/kint": "@stable"
36-
},
37-
"autoload": {
38-
"psr-4": {
39-
"Mediact\\Composer\\DependencyInstaller\\": "src"
40-
}
41-
},
42-
"autoload-dev": {
43-
"psr-4": {
44-
"Mediact\\Composer\\DependencyInstaller\\Tests\\": "tests"
36+
"require-dev": {
37+
"phpunit/phpunit": "@stable",
38+
"mediact/testing-suite": "@stable",
39+
"kint-php/kint": "@stable"
40+
},
41+
"autoload": {
42+
"psr-4": {
43+
"Mediact\\Composer\\DependencyInstaller\\": "src"
44+
}
45+
},
46+
"autoload-dev": {
47+
"psr-4": {
48+
"Mediact\\Composer\\DependencyInstaller\\Tests\\": "tests"
49+
}
4550
}
46-
}
4751
}

src/DependencyInstaller.php

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
/**
3+
* Copyright MediaCT. All rights reserved.
4+
* https://www.mediact.nl
5+
*/
6+
7+
namespace Mediact\Composer\DependencyInstaller;
8+
9+
use Composer\Command\ConfigCommand;
10+
use Composer\Command\RequireCommand;
11+
use Composer\Console\Application;
12+
use Composer\Factory;
13+
use Composer\Json\JsonFile;
14+
use Symfony\Component\Console\Input\ArrayInput;
15+
use Symfony\Component\Console\Output\OutputInterface;
16+
17+
class DependencyInstaller
18+
{
19+
/**
20+
* @var array
21+
*/
22+
private $definition;
23+
24+
/**
25+
* @var string
26+
*/
27+
private $workingDir;
28+
29+
/**
30+
* @var null|OutputInterface
31+
*/
32+
private $output;
33+
34+
/**
35+
* Constructor.
36+
*
37+
* @param string|null $composerFile
38+
* @param OutputInterface|null $output
39+
*/
40+
public function __construct(
41+
string $composerFile = null,
42+
OutputInterface $output = null
43+
) {
44+
$composerFile = $composerFile ?: Factory::getComposerFile();
45+
$composerJson = new JsonFile($composerFile);
46+
$this->definition = $composerJson->read();
47+
$this->workingDir = dirname($composerFile);
48+
$this->output = $output;
49+
}
50+
51+
/**
52+
* Install a repository.
53+
*
54+
* @param string $name
55+
* @param string $type
56+
* @param string $url
57+
*
58+
* @return void
59+
*/
60+
public function installRepository(string $name, string $type, string $url)
61+
{
62+
if (array_key_exists('repositories', $this->definition)
63+
&& array_key_exists($name, $this->definition['repositories'])
64+
) {
65+
return;
66+
}
67+
68+
$application = new Application();
69+
$command = new ConfigCommand();
70+
71+
$definition = clone $application->getDefinition();
72+
$definition->addArguments($command->getDefinition()->getArguments());
73+
$definition->addOptions($command->getDefinition()->getOptions());
74+
75+
$input = new ArrayInput(
76+
[
77+
'command' => 'config',
78+
'setting-key' => 'repositories.' . $name,
79+
'setting-value' => [
80+
$type,
81+
$url
82+
],
83+
'--working-dir' => $this->workingDir
84+
],
85+
$definition
86+
);
87+
88+
$application->setAutoExit(false);
89+
$application->run($input, $this->output);
90+
}
91+
92+
/**
93+
* Install a composer package.
94+
*
95+
* @param string $name
96+
* @param string $version
97+
* @param bool $dev
98+
*
99+
* @return void
100+
*
101+
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
102+
*/
103+
public function installPackage(string $name, string $version, bool $dev = true)
104+
{
105+
$node = $dev ? 'require-dev' : 'require';
106+
107+
if (array_key_exists($node, $this->definition)
108+
&& array_key_exists($name, $this->definition[$node])
109+
) {
110+
return;
111+
}
112+
113+
$application = new Application();
114+
$command = new RequireCommand();
115+
116+
$definition = clone $application->getDefinition();
117+
$definition->addArguments($command->getDefinition()->getArguments());
118+
$definition->addOptions($command->getDefinition()->getOptions());
119+
120+
$input = new ArrayInput(
121+
[
122+
'command' => 'require',
123+
'packages' => [$name . ':' . $version],
124+
'--dev' => $dev,
125+
'--no-scripts' => true,
126+
'--no-interaction' => true,
127+
'--no-plugins' => true,
128+
'--working-dir' => $this->workingDir
129+
],
130+
$definition
131+
);
132+
133+
$application->setAutoExit(false);
134+
$application->run($input, $this->output);
135+
}
136+
}

tests/DependencyInstallerTest.php

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
/**
3+
* Copyright MediaCT. All rights reserved.
4+
* https://www.mediact.nl
5+
*/
6+
7+
namespace Mediact\Composer\DependencyInstaller\Tests;
8+
9+
use Composer\Json\JsonFile;
10+
use Mediact\Composer\DependencyInstaller\DependencyInstaller;
11+
use PHPUnit\Framework\TestCase;
12+
use Symfony\Component\Console\Output\OutputInterface;
13+
14+
/**
15+
* @coversDefaultClass \Mediact\Composer\DependencyInstaller\DependencyInstaller
16+
*/
17+
class DependencyInstallerTest extends TestCase
18+
{
19+
/** @var string */
20+
private static $directory = __DIR__ . DIRECTORY_SEPARATOR . 'tmp';
21+
22+
/**
23+
* @return void
24+
*/
25+
public static function setUpBeforeClass()
26+
{
27+
static::tearDownAfterClass();
28+
29+
mkdir(static::$directory);
30+
chdir(static::$directory);
31+
file_put_contents('composer.json', '{}');
32+
}
33+
34+
/**
35+
* @return void
36+
*/
37+
public static function tearDownAfterClass()
38+
{
39+
if (is_dir(static::$directory)) {
40+
static::rrmdir(static::$directory);
41+
}
42+
}
43+
44+
/**
45+
* @param string $src
46+
*
47+
* @return void
48+
*/
49+
private static function rrmdir(string $src)
50+
{
51+
$dir = opendir($src);
52+
while (false !== ($file = readdir($dir))) {
53+
if (($file != '.') && ($file != '..')) {
54+
$full = $src . '/' . $file;
55+
if (is_dir($full)) {
56+
static::rrmdir($full);
57+
} else {
58+
unlink($full);
59+
}
60+
}
61+
}
62+
closedir($dir);
63+
rmdir($src);
64+
}
65+
66+
67+
/**
68+
* @return DependencyInstaller
69+
* @covers ::__construct
70+
*/
71+
public function testConstructor(): DependencyInstaller
72+
{
73+
$installer = new DependencyInstaller(
74+
'composer.json',
75+
$this->createMock(OutputInterface::class)
76+
);
77+
78+
$this->assertInstanceOf(
79+
DependencyInstaller::class,
80+
$installer
81+
);
82+
83+
return $installer;
84+
}
85+
86+
/**
87+
* @depends testConstructor
88+
* @dataProvider repositoryProvider
89+
*
90+
* @param string $name
91+
* @param string $type
92+
* @param string $url
93+
* @param DependencyInstaller $dependencyInstaller
94+
*
95+
* @return void
96+
* @covers ::installRepository
97+
*/
98+
public function testInstallRepository(
99+
string $name,
100+
string $type,
101+
string $url,
102+
DependencyInstaller $dependencyInstaller
103+
) {
104+
$dependencyInstaller->installRepository($name, $type, $url);
105+
106+
$jsonFile = new JsonFile('composer.json');
107+
$definition = $jsonFile->read();
108+
109+
$this->assertArrayHasKey('repositories', $definition);
110+
$this->assertArrayHasKey($name, $definition['repositories']);
111+
$this->assertArrayHasKey('type', $definition['repositories'][$name]);
112+
$this->assertArrayHasKey('url', $definition['repositories'][$name]);
113+
$this->assertEquals($type, $definition['repositories'][$name]['type']);
114+
$this->assertEquals($url, $definition['repositories'][$name]['url']);
115+
}
116+
117+
/**
118+
* @return array
119+
*/
120+
public function repositoryProvider(): array
121+
{
122+
return [
123+
['mediact', 'composer', 'https://composer.mediact.nl']
124+
];
125+
}
126+
127+
/**
128+
* @depends testConstructor
129+
* @dataProvider packageProvider
130+
*
131+
* @param string $name
132+
* @param string $version
133+
* @param bool $dev
134+
* @param DependencyInstaller $dependencyInstaller
135+
*
136+
* @return void
137+
* @covers ::installPackage
138+
*/
139+
public function testInstallPackage(
140+
string $name,
141+
string $version,
142+
bool $dev,
143+
DependencyInstaller $dependencyInstaller
144+
) {
145+
$dependencyInstaller->installPackage($name, $version, $dev);
146+
147+
$jsonFile = new JsonFile('composer.json');
148+
$definition = $jsonFile->read();
149+
150+
$node = $dev ? 'require-dev' : 'require';
151+
152+
$this->assertArrayHasKey($node, $definition);
153+
$this->assertArrayHasKey($name, $definition[$node]);
154+
$this->assertEquals($version, $definition[$node][$name]);
155+
}
156+
157+
/**
158+
* @return array
159+
*/
160+
public function packageProvider(): array
161+
{
162+
return [
163+
['psr/log', '@stable', true],
164+
['psr/log', '@stable', false]
165+
];
166+
}
167+
}

0 commit comments

Comments
 (0)