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

Commit 12692d6

Browse files
authored
added a abstract installation manger and moved some files to common (#24)
| Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | -
1 parent 0274c08 commit 12692d6

28 files changed

+444
-393
lines changed

.travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ jobs:
5858
- bash <(curl -s https://codecov.io/bash)
5959

6060
- stage: Subsplit
61-
# Regex for semver
62-
if: (branch = master OR tag =~ /\bv(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?\b/i)
61+
if: (branch = master OR tag IS present)
6362
php: 7.2
6463
before_install:
6564
- echo "skip"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Narrowspark\Discovery\Common\Installer;
4+
5+
use Composer\Composer;
6+
use Composer\DependencyResolver\Pool;
7+
use Composer\Factory;
8+
use Composer\Installer as BaseInstaller;
9+
use Composer\Installer\InstallationManager as BaseInstallationManager;
10+
use Composer\IO\IOInterface;
11+
use Composer\Json\JsonFile;
12+
use Composer\Json\JsonManipulator;
13+
use Composer\Package\Link;
14+
use Composer\Package\RootPackageInterface;
15+
use Composer\Package\Version\VersionParser;
16+
use Composer\Package\Version\VersionSelector;
17+
use Composer\Repository\CompositeRepository;
18+
use Composer\Repository\PlatformRepository;
19+
use Composer\Repository\RepositoryFactory;
20+
use Narrowspark\Discovery\Common\Contract\Package as PackageContract;
21+
use Narrowspark\Discovery\Common\Traits\GetGenericPropertyReaderTrait;
22+
use Narrowspark\Discovery\Exception\InvalidArgumentException;
23+
use Symfony\Component\Console\Input\InputInterface;
24+
25+
abstract class AbstractInstallationManager
26+
{
27+
use GetGenericPropertyReaderTrait;
28+
29+
/**
30+
* @var int
31+
*/
32+
protected const ADD = 1;
33+
34+
/**
35+
* @var int
36+
*/
37+
protected const REMOVE = 0;
38+
39+
/**
40+
* A VersionSelector instance.
41+
*
42+
* @var \Composer\Package\Version\VersionSelector
43+
*/
44+
protected $versionSelector;
45+
46+
/**
47+
* A composer json file instance.
48+
*
49+
* @var \Composer\Json\JsonFile
50+
*/
51+
protected $jsonFile;
52+
53+
/**
54+
* A root package implementation.
55+
*
56+
* @var \Composer\Package\RootPackageInterface
57+
*/
58+
protected $rootPackage;
59+
60+
/**
61+
* The composer instance.
62+
*
63+
* @var \Composer\Composer
64+
*/
65+
protected $composer;
66+
67+
/**
68+
* The composer io implementation.
69+
*
70+
* @var \Composer\IO\IOInterface
71+
*/
72+
protected $io;
73+
74+
/**
75+
* A repository implementation.
76+
*
77+
* @var \Composer\Repository\WritableRepositoryInterface
78+
*/
79+
protected $localRepository;
80+
81+
/**
82+
* A input implementation.
83+
*
84+
* @var \Symfony\Component\Console\Input\InputInterface
85+
*/
86+
protected $input;
87+
88+
/**
89+
* All local installed packages.
90+
*
91+
* @var string[]
92+
*/
93+
protected $installedPackages;
94+
95+
/**
96+
* Get the minimum stability.
97+
*
98+
* @var string
99+
*/
100+
protected $stability;
101+
102+
/**
103+
* Create a new ExtraDependencyInstaller instance.
104+
*
105+
* @param \Composer\Composer $composer
106+
* @param \Composer\IO\IOInterface $io
107+
* @param \Symfony\Component\Console\Input\InputInterface $input
108+
*/
109+
public function __construct(Composer $composer, IOInterface $io, InputInterface $input)
110+
{
111+
$this->composer = $composer;
112+
$this->io = $io;
113+
$this->input = $input;
114+
$this->jsonFile = new JsonFile(Factory::getComposerFile());
115+
116+
$this->rootPackage = $this->composer->getPackage();
117+
$this->stability = $this->rootPackage->getMinimumStability() ?: 'stable';
118+
119+
$pool = new Pool($this->stability);
120+
$pool->addRepository(
121+
new CompositeRepository(\array_merge([new PlatformRepository()], RepositoryFactory::defaultRepos($io)))
122+
);
123+
124+
$this->versionSelector = new VersionSelector($pool);
125+
$this->localRepository = $this->composer->getRepositoryManager()->getLocalRepository();
126+
127+
foreach ($this->localRepository->getPackages() as $package) {
128+
$this->installedPackages[\mb_strtolower($package->getName())] = \ltrim($package->getPrettyVersion(), 'v');
129+
}
130+
}
131+
132+
/**
133+
* Install extra dependencies.
134+
*
135+
* @param \Narrowspark\Discovery\Common\Contract\Package $package
136+
* @param array $dependencies
137+
*
138+
* @throws \Narrowspark\Discovery\Exception\RuntimeException
139+
* @throws \Narrowspark\Discovery\Exception\InvalidArgumentException
140+
* @throws \Exception
141+
*
142+
* @return \Narrowspark\Discovery\Common\Contract\Package[]
143+
*/
144+
abstract public function install(PackageContract $package, array $dependencies): array;
145+
146+
/**
147+
* Uninstall extra dependencies.
148+
*
149+
* @param \Narrowspark\Discovery\Common\Contract\Package $package
150+
* @param array $dependencies
151+
*
152+
* @throws \Exception
153+
*
154+
* @return \Narrowspark\Discovery\Common\Contract\Package[]
155+
*/
156+
abstract public function uninstall(PackageContract $package, array $dependencies): array;
157+
158+
/**
159+
* @codeCoverageIgnore
160+
*
161+
* Get configured installer instance.
162+
*
163+
* @return \Composer\Installer
164+
*/
165+
protected function getInstaller(): BaseInstaller
166+
{
167+
return Installer::create($this->io, $this->composer, $this->input);
168+
}
169+
170+
/**
171+
* Try to find the best version fot the package.
172+
*
173+
* @param string $name
174+
*
175+
* @throws \Narrowspark\Discovery\Exception\InvalidArgumentException
176+
*
177+
* @return string
178+
*/
179+
protected function findVersion(string $name): string
180+
{
181+
// find the latest version allowed in this pool
182+
$package = $this->versionSelector->findBestCandidate($name, null, null, 'stable');
183+
184+
if ($package === false) {
185+
throw new InvalidArgumentException(\sprintf(
186+
'Could not find package %s at any version for your minimum-stability (%s).'
187+
. ' Check the package spelling or your minimum-stability.',
188+
$name,
189+
$this->stability
190+
));
191+
}
192+
193+
return $this->versionSelector->findRecommendedRequireVersion($package);
194+
}
195+
196+
/**
197+
* Update the root composer.json require.
198+
*
199+
* @param array $packages
200+
* @param int $type
201+
*
202+
* @return \Composer\Package\RootPackageInterface
203+
*/
204+
protected function updateRootComposerJson(array $packages, int $type): RootPackageInterface
205+
{
206+
$this->io->writeError('Updating root package');
207+
208+
$requires = $this->rootPackage->getRequires();
209+
210+
if ($type === self::ADD) {
211+
foreach ($packages as $packageName => $version) {
212+
$requires[$packageName] = new Link(
213+
'__root__',
214+
$packageName,
215+
(new VersionParser())->parseConstraints($version),
216+
'requires',
217+
$version
218+
);
219+
}
220+
} elseif ($type === self::REMOVE) {
221+
foreach ($packages as $packageName => $version) {
222+
unset($requires[$packageName]);
223+
}
224+
}
225+
226+
$this->rootPackage->setRequires($requires);
227+
228+
return $this->rootPackage;
229+
}
230+
231+
/**
232+
* Manipulate root composer.json with the new packages and dump it.
233+
*
234+
* @param array $packages
235+
* @param int $type
236+
*
237+
* @throws \Exception happens in the JsonFile class
238+
*
239+
* @return void
240+
*/
241+
protected function updateComposerJson(array $packages, int $type): void
242+
{
243+
$this->io->writeError('Updating composer.json');
244+
245+
if ($type === self::ADD) {
246+
$jsonManipulator = new JsonManipulator(\file_get_contents($this->jsonFile->getPath()));
247+
248+
foreach ($packages as $name => $version) {
249+
$sortPackages = $this->composer->getConfig()->get('sort-packages') ?? false;
250+
251+
$jsonManipulator->addLink('require', $name, $version, $sortPackages);
252+
}
253+
254+
\file_put_contents($this->jsonFile->getPath(), $jsonManipulator->getContents());
255+
} elseif ($type === self::REMOVE) {
256+
$jsonFileContent = $this->jsonFile->read();
257+
258+
foreach ($packages as $packageName => $version) {
259+
unset($jsonFileContent['require'][$packageName]);
260+
}
261+
262+
$this->jsonFile->write($jsonFileContent);
263+
}
264+
}
265+
266+
/**
267+
* Install selected packages.
268+
*
269+
* @param \Composer\Package\RootPackageInterface $rootPackage
270+
* @param array $whitelistPackages
271+
*
272+
* @throws \Exception
273+
*
274+
* @return int
275+
*/
276+
protected function runInstaller(RootPackageInterface $rootPackage, array $whitelistPackages): int
277+
{
278+
$this->io->writeError('Running an update to install dependent packages');
279+
280+
$this->composer->setPackage($rootPackage);
281+
282+
$installer = $this->getInstaller();
283+
$installer->setUpdateWhitelist($whitelistPackages);
284+
285+
return $installer->run();
286+
}
287+
288+
/**
289+
* Adds a modified installation manager to composer.
290+
*
291+
* @param \Composer\Installer\InstallationManager $oldInstallManager
292+
*
293+
* @return void
294+
*/
295+
protected function addDiscoveryInstallationManagerToComposer(BaseInstallationManager $oldInstallManager): void
296+
{
297+
$reader = $this->getGenericPropertyReader();
298+
$installers = (array) $reader($oldInstallManager, 'installers');
299+
300+
$narrowsparkInstaller = new InstallationManager();
301+
302+
foreach ($installers as $installer) {
303+
$narrowsparkInstaller->addInstaller($installer);
304+
}
305+
306+
$this->composer->setInstallationManager($narrowsparkInstaller);
307+
}
308+
309+
/**
310+
* Get merged root requires and dev-requires.
311+
*
312+
* @return \Composer\Package\Link[]
313+
*/
314+
protected function getRootRequires(): array
315+
{
316+
return \array_merge($this->rootPackage->getRequires(), $this->rootPackage->getDevRequires());
317+
}
318+
}

src/Discovery/Installer/InstallationManager.php src/Common/Installer/InstallationManager.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
declare(strict_types=1);
3-
namespace Narrowspark\Discovery\Installer;
3+
namespace Narrowspark\Discovery\Common\Installer;
44

55
use Composer\DependencyResolver\Operation\InstallOperation;
66
use Composer\DependencyResolver\Operation\OperationInterface;

src/Discovery/Installer/Installer.php src/Common/Installer/Installer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
declare(strict_types=1);
3-
namespace Narrowspark\Discovery\Installer;
3+
namespace Narrowspark\Discovery\Common\Installer;
44

55
use Composer\Composer;
66
use Composer\Config;

src/Discovery/Traits/GetGenericPropertyReaderTrait.php src/Common/Traits/GetGenericPropertyReaderTrait.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
declare(strict_types=1);
3-
namespace Narrowspark\Discovery\Traits;
3+
namespace Narrowspark\Discovery\Common\Traits;
44

55
use Closure;
66

src/Discovery/Discovery.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@
2929
use FilesystemIterator;
3030
use Narrowspark\Discovery\Common\Contract\Package as PackageContract;
3131
use Narrowspark\Discovery\Common\Traits\ExpandTargetDirTrait;
32+
use Narrowspark\Discovery\Common\Traits\GetGenericPropertyReaderTrait;
3233
use Narrowspark\Discovery\Installer\ConfiguratorInstaller;
3334
use Narrowspark\Discovery\Installer\QuestionInstallationManager;
3435
use Narrowspark\Discovery\Prefetcher\ParallelDownloader;
3536
use Narrowspark\Discovery\Prefetcher\Prefetcher;
36-
use Narrowspark\Discovery\Traits\GetGenericPropertyReaderTrait;
3737
use RecursiveDirectoryIterator;
3838
use RecursiveIteratorIterator;
3939
use ReflectionClass;

0 commit comments

Comments
 (0)