Skip to content

Commit

Permalink
Manually link to composer-bin-plugin installed commands
Browse files Browse the repository at this point in the history
Otherwise there is no guarantee which version of the library the link was created for, as there might be still multiple versions installed. The plugin will link to the first one that was installed. It might not be the one we expected.

i.e. rector installed phpstan in version 0.11.3 as one of its dependencies. phpstan 0.11.4 was also directly requested to be installed in a different composer-bin-plugin namespace. Since rectors phpstan was installed first, the link was pointing to the 0.11.3 version instead of 0.11.4 we expected. As a consequence no phpstan plugins could be loaded.
  • Loading branch information
jakzal committed Mar 23, 2019
1 parent 21d4f77 commit 618ee92
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 27 deletions.
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ Thanks to the isolation we're less likely to run into problem with conflicting d
"command": {
"composer-bin-plugin": {
"package": "behat/behat",
"namespace": "behat"
"namespace": "behat",
"links": {"/tools/behat": "behat"}
}
}
}
```

The `links` attribute is optional, but it's recommended for packages that provide commands.

#### phar-download

Downloads a phar from the given URL and puts it into the specified location.
Expand Down
5 changes: 4 additions & 1 deletion resources/pre-installation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"command": {
"composer-global-install": {
"package": "bamarni/composer-bin-plugin"
},
"sh": {
"command": "composer global config extra.bamarni-bin.bin-links false"
}
},
"test": "composer global show bamarni/composer-bin-plugin",
Expand All @@ -37,4 +40,4 @@
"tags": ["pre-installation"]
}
]
}
}
42 changes: 28 additions & 14 deletions resources/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"command": {
"composer-bin-plugin": {
"package": "bmitch/churn-php",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/churn": "churn"}
}
},
"test": "churn list",
Expand Down Expand Up @@ -106,7 +107,8 @@
"command": {
"composer-bin-plugin": {
"package": "exussum12/coverage-checker",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/diffFilter": "diffFilter"}
}
},
"test": "diffFilter -v"
Expand Down Expand Up @@ -160,7 +162,8 @@
"command": {
"composer-bin-plugin": {
"package": "brianium/paratest",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/paratest": "paratest"}
}
},
"test": "paratest --version"
Expand Down Expand Up @@ -198,7 +201,8 @@
"command": {
"composer-bin-plugin": {
"package": "akeneo/php-coupling-detector",
"namespace": "php-coupling-detector"
"namespace": "php-coupling-detector",
"links": {"%target-dir%/php-coupling-detector": "php-coupling-detector"}
}
},
"test": "php-coupling-detector list"
Expand Down Expand Up @@ -278,7 +282,8 @@
"command": {
"composer-bin-plugin": {
"package": "rskuipers/php-assumptions",
"namespace": "php-assumptions"
"namespace": "php-assumptions",
"links": {"%target-dir%/phpa": "phpa"}
}
},
"test": "phpa --version",
Expand All @@ -291,7 +296,8 @@
"command": {
"composer-bin-plugin": {
"package": "wapmorgan/php-code-analyzer",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/phpca": "phpca"}
}
},
"test": "phpca -h"
Expand Down Expand Up @@ -327,7 +333,8 @@
"command": {
"composer-bin-plugin": {
"package": "wapmorgan/php-code-fixer",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/phpcf": "phpcf"}
}
},
"test": "phpcf -h"
Expand Down Expand Up @@ -405,7 +412,8 @@
"command": {
"composer-bin-plugin": {
"package": "overtrue/phplint",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/phplint": "phplint"}
}
},
"test": "phplint -V"
Expand Down Expand Up @@ -454,7 +462,8 @@
"command": {
"composer-bin-plugin": {
"package": "povils/phpmnd",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/phpmnd": "phpmnd"}
}
},
"test": "phpmnd -V"
Expand All @@ -479,7 +488,8 @@
"command": {
"composer-bin-plugin": {
"package": "phpstan/phpstan",
"namespace": "phpstan"
"namespace": "phpstan",
"links": {"%target-dir%/phpstan": "phpstan"}
}
},
"test": "phpstan --version",
Expand Down Expand Up @@ -642,7 +652,8 @@
"command": {
"composer-bin-plugin": {
"package": "psecio/parse:dev-master",
"namespace": "psecio-parse"
"namespace": "psecio-parse",
"links": {"%target-dir%/psecio-parse": "psecio-parse"}
}
},
"test": "psecio-parse --version"
Expand All @@ -654,7 +665,8 @@
"command": {
"composer-bin-plugin": {
"package": "rector/rector",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/rector": "rector"}
}
},
"test": "rector --version"
Expand Down Expand Up @@ -692,7 +704,8 @@
"command": {
"composer-bin-plugin": {
"package": "symfony/phpunit-bridge",
"namespace": "symfony"
"namespace": "symfony",
"links": {"%target-dir%/simple-phpunit": "simple-phpunit"}
},
"sh": {
"command": "simple-phpunit install"
Expand All @@ -707,7 +720,8 @@
"command": {
"composer-bin-plugin": {
"package": "edsonmedina/php_testability:dev-master",
"namespace": "tools"
"namespace": "tools",
"links": {"%target-dir%/testability": "testability"}
}
},
"test": "testability --help"
Expand Down
16 changes: 15 additions & 1 deletion src/Json/Factory/ComposerBinPluginCommandFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,29 @@

namespace Zalas\Toolbox\Json\Factory;

use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Command;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginCommand;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginLinkCommand;

final class ComposerBinPluginCommandFactory
{
public static function import(array $command): Command
{
Assert::requireFields(['package', 'namespace'], $command, 'ComposerBinPluginCommand');

return new ComposerBinPluginCommand($command['package'], $command['namespace']);
return new ComposerBinPluginCommand($command['package'], $command['namespace'], self::importLinks($command));
}

private static function importLinks(array $command): Collection
{
$links = $command['links'] ?? [];
$namespace = $command['namespace'];

return Collection::create(
\array_map(function (string $source, string $target) use ($namespace) {
return new ComposerBinPluginLinkCommand($source, $target, $namespace);
}, \array_values($links), \array_keys($links))
);
}
}
21 changes: 19 additions & 2 deletions src/Tool/Command/ComposerBinPluginCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@

namespace Zalas\Toolbox\Tool\Command;

use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Command;

final class ComposerBinPluginCommand implements Command
{
private $package;

private $namespace;

public function __construct(string $package, string $namespace)
private $links;

public function __construct(string $package, string $namespace, Collection $links)
{
$this->package = $package;
$this->namespace = $namespace;
$this->links = $links;
}

public function __toString(): string
{
return \sprintf('composer global bin %s require --no-suggest --prefer-dist --update-no-dev -n %s', $this->namespace, $this->package);
return \sprintf('composer global bin %s require --no-suggest --prefer-dist --update-no-dev -n %s%s', $this->namespace, $this->package, $this->linkCommand());
}

public function package(): string
Expand All @@ -29,4 +34,16 @@ public function namespace(): string
{
return $this->namespace;
}

public function links(): Collection
{
return $this->links;
}

private function linkCommand(): string
{
return $this->links->reduce('', function (string $command, ComposerBinPluginLinkCommand $link) {
return $command.' && '.$link;
});
}
}
29 changes: 29 additions & 0 deletions src/Tool/Command/ComposerBinPluginLinkCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types=1);

namespace Zalas\Toolbox\Tool\Command;

use Zalas\Toolbox\Tool\Command;

final class ComposerBinPluginLinkCommand implements Command
{
private $source;
private $target;
private $namespace;

public function __construct(string $source, string $target, string $namespace)
{
$this->source = $source;
$this->target = $target;
$this->namespace = $namespace;
}

public function __toString(): string
{
return \sprintf(
'ln -sf ${COMPOSER_HOME:-"~/.composer"}/vendor-bin/%s/vendor/bin/%s %s',
$this->namespace,
$this->source,
$this->target
);
}
}
16 changes: 15 additions & 1 deletion src/Tool/Command/OptimisedComposerBinPluginCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function __construct(Collection $commands)

public function __toString(): string
{
return \implode(' && ', $this->commandsToRun($this->packagesGroupedByNamespace()));
return \implode(' && ', \array_merge($this->commandsToRun($this->packagesGroupedByNamespace()), $this->linksToCreate()));
}

private function packagesGroupedByNamespace(): array
Expand All @@ -44,4 +44,18 @@ private function commandsToRun(array $packagesGrouped): array
{
return \array_map([$this, 'commandToRun'], \array_keys($packagesGrouped), $packagesGrouped);
}

private function linksToCreate(): array
{
return $this->commands
->filter(function (ComposerBinPluginCommand $command) {
return !$command->links()->empty();
})
->map(function (ComposerBinPluginCommand $command) {
return $command->links()->reduce('', function (string $command, ComposerBinPluginLinkCommand $link) {
return !empty($command) ? $command.' && '.$link : $link;
});
})
->toArray();
}
}
19 changes: 19 additions & 0 deletions tests/Json/Factory/ComposerBinPluginCommandFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use PHPUnit\Framework\TestCase;
use Zalas\Toolbox\Json\Factory\ComposerBinPluginCommandFactory;
use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginCommand;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginLinkCommand;

class ComposerBinPluginCommandFactoryTest extends TestCase
{
Expand All @@ -21,6 +23,23 @@ public function test_it_creates_a_command()
$this->assertInstanceOf(ComposerBinPluginCommand::class, $command);
}

public function test_it_creates_a_command_with_links_in_tools()
{
$command = ComposerBinPluginCommandFactory::import([
'package' => self::PACKAGE,
'namespace' => self::NAMESPACE,
'links' => ['/tools/phpstan' => 'phpstan'],
]);

$this->assertInstanceOf(ComposerBinPluginCommand::class, $command);
$this->assertEquals(
Collection::create([
new ComposerBinPluginLinkCommand('phpstan', '/tools/phpstan', self::NAMESPACE)
]),
$command->links()
);
}

/**
* @dataProvider provideRequiredProperties
*/
Expand Down
25 changes: 24 additions & 1 deletion tests/Tool/Command/ComposerBinPluginCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Zalas\Toolbox\Tests\Tool\Command;

use PHPUnit\Framework\TestCase;
use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Command;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginCommand;
use Zalas\Toolbox\Tool\Command\ComposerBinPluginLinkCommand;

class ComposerBinPluginCommandTest extends TestCase
{
Expand All @@ -18,7 +20,11 @@ class ComposerBinPluginCommandTest extends TestCase

protected function setUp()
{
$this->command = new ComposerBinPluginCommand(self::PACKAGE, self::NAMESPACE);
$this->command = new ComposerBinPluginCommand(
self::PACKAGE,
self::NAMESPACE,
Collection::create([])
);
}

public function test_it_is_a_command()
Expand All @@ -36,4 +42,21 @@ public function test_it_exposes_the_package_and_namespace()
$this->assertSame(self::PACKAGE, $this->command->package());
$this->assertSame(self::NAMESPACE, $this->command->namespace());
}

public function test_it_optionally_creates_a_symlink()
{
$links = Collection::create([
new ComposerBinPluginLinkCommand('phpstan', '/tools/phpstan', self::NAMESPACE)
]);
$this->command = new ComposerBinPluginCommand(self::PACKAGE, self::NAMESPACE, $links);

$this->assertSame($links, $this->command->links());
$this->assertRegExp('#composer global bin tools require .*? phpstan/phpstan#', (string) $this->command);
$this->assertRegExp('# && ln -sf.*?phpstan /tools/phpstan#', (string) $this->command);
}

public function test_it_does_not_create_a_symlink_if_links_option_was_not_given()
{
$this->assertNotRegExp('#ln -s#', (string) $this->command);
}
}
Loading

0 comments on commit 618ee92

Please sign in to comment.