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

Added functionality to choose one dependency from the list #8

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,18 @@ you'd like to install with your library:
"dependency": [
"package/to-require",
...
]
],
"dependency-or": {
"Question": [
"package/to-choose",
"package/or-this",
...
]
}
},
"require": {
"php": "^5.6 || ^7.0",
"webimpress/composer-extra-dependency": "^0.1 || ^1.0",
"webimpress/composer-extra-dependency": "^0.3 || ^1.0",
...
}
...
Expand Down
132 changes: 107 additions & 25 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory;
use RuntimeException;

class Plugin implements PluginInterface, EventSubscriberInterface
{
Expand Down Expand Up @@ -63,7 +64,7 @@ public function activate(Composer $composer, IOInterface $io)

$installedPackages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
foreach ($installedPackages as $package) {
$this->installedPackages[$package->getName()] = $package->getPrettyVersion();
$this->installedPackages[strtolower($package->getName())] = $package->getPrettyVersion();
}
}

Expand All @@ -85,36 +86,83 @@ public function onPostPackage(PackageEvent $event)
} else {
$package = $operation->getTargetPackage();
}
$extra = $this->getExtraMetadata($package->getExtra());
if (empty($extra)) {
// Package does not define anything of interest; do nothing.
return;

$extra = $package->getExtra();
$packages = $this->andDependencies($extra) + $this->orDependencies($extra);
if ($packages) {
$this->updateComposerJson($packages);

$rootPackage = $this->updateRootPackage($this->composer->getPackage(), $packages);
$this->runInstaller($rootPackage, array_keys($packages));
}
}

private function andDependencies(array $extra)
{
$deps = isset($extra['dependency']) && is_array($extra['dependency'])
? $extra['dependency']
: [];

if (! $deps) {
// No defined any packages to install
return [];
}

$packages = array_flip($extra);
$packages = array_flip($deps);

foreach ($packages as $package => &$constraint) {
if ($this->hasPackage($package)) {
unset($packages[$package]);
continue;
}

// Check if package is currently installed and use installed version.
if ($constraint = $this->getInstalledPackageConstraint($package)) {
continue;
}

// Package is not installed, then prompt user for the version.
$constraint = $this->promptForPackageVersion($package);
}

if ($packages) {
$this->updateComposerJson($packages);

$rootPackage = $this->updateRootPackage($this->composer->getPackage(), $packages);
$this->runInstaller($rootPackage, array_keys($packages));
}
return $packages;
}

private function getExtraMetadata(array $extra)
private function orDependencies(array $extra)
{
return isset($extra['dependency']) && is_array($extra['dependency'])
? $extra['dependency']
$deps = isset($extra['dependency-or']) && is_array($extra['dependency-or'])
? $extra['dependency-or']
: [];

if (! $deps) {
// No any dependencies to choose defined in the package.
return [];
}

$packages = [];
foreach ($deps as $question => $options) {
if (! is_array($options) || count($options) < 2) {
throw new RuntimeException('You must provide at least two optional dependencies.');
}

foreach ($options as $package) {
if ($this->hasPackage($package)) {
// Package from this group has been found in root composer, skipping.
continue 2;
}

// Check if package is currently installed, if so, use installed constraint and skip question.
if ($constraint = $this->getInstalledPackageConstraint($package)) {
$packages[$package] = $constraint;
continue 2;
}
}

$package = $this->promptForPackageSelection($question, $options);
$packages[$package] = $this->promptForPackageVersion($package);
}

return $packages;
}

private function updateRootPackage(RootPackageInterface $rootPackage, array $packages)
Expand Down Expand Up @@ -157,21 +205,55 @@ private function runInstaller(RootPackageInterface $rootPackage, array $packages
return $installer->run();
}

private function promptForPackageVersion($name)
private function getInstalledPackageConstraint($package)
{
$lower = strtolower($package);

// Package is currently installed. Add it to root composer.json
if (isset($this->installedPackages[$name])) {
$this->io->write(sprintf(
'Added package <info>%s</info> to composer.json with constraint <info>%s</info>;'
. ' to upgrade, run <info>composer require %s:VERSION</info>',
$name,
'^' . $this->installedPackages[$name],
$name
));
if (! isset($this->installedPackages[$lower])) {
return null;
}

return '^' . $this->installedPackages[$name];
$constraint = '^' . $this->installedPackages[$lower];
$this->io->write(sprintf(
'Added package <info>%s</info> to composer.json with constraint <info>%s</info>;'
. ' to upgrade, run <info>composer require %s:VERSION</info>',
$package,
$constraint,
$package
));

return $constraint;
}

private function promptForPackageSelection($question, array $packages)
{
$ask = [sprintf('<question>%s</question>' . "\n", $question)];
foreach ($packages as $i => $name) {
$ask[] = sprintf(' [<comment>%d</comment>] %s' . "\n", $i + 1, $name);
}
$ask[] = ' Make your selection: ';

do {
$package = $this->io->askAndValidate(
$ask,
function ($input) use ($packages) {
$input = is_numeric($input) ? (int) trim($input) : 0;

if (isset($packages[$input - 1])) {
return $packages[$input - 1];
}

return null;
}
);
} while (! $package);

return $package;
}

private function promptForPackageVersion($name)
{
$constraint = $this->io->askAndValidate(
sprintf(
'Enter the version of <info>%s</info> to require (or leave blank to use the latest version): ',
Expand Down
Loading