这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ tools/deptrac:
curl -Ls http://get.sensiolabs.de/deptrac.phar -o tools/deptrac && chmod +x tools/deptrac

tools/infection: tools/infection.pubkey
curl -Ls https://github.com/infection/infection/releases/download/0.10.1/infection.phar -o tools/infection && chmod +x tools/infection
curl -Ls https://github.com/infection/infection/releases/download/0.10.3/infection.phar -o tools/infection && chmod +x tools/infection

tools/infection.pubkey:
curl -Ls https://github.com/infection/infection/releases/download/0.10.1/infection.phar.pubkey -o tools/infection.pubkey
curl -Ls https://github.com/infection/infection/releases/download/0.10.3/infection.phar.pubkey -o tools/infection.pubkey

tools/box:
curl -Ls https://github.com/humbug/box/releases/download/3.0.0-RC.0/box.phar -o tools/box && chmod +x tools/box
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,28 @@ curl -s https://api.github.com/repos/jakzal/toolbox/releases/latest \
./toolbox install
```

#### Dry run

To only see what commands would be executed, use the dry run mode:

```
./toolbox install --dry-run
```

### Test if installed tools are usable

```
./toolbox test
```

#### Dry run

To only see what commands would be executed, use the dry run mode:

```
./toolbox test --dry-run
```

### Tools definitions

By default `resources/pre-installation.json` and `resources/tools.json` are used to load tool definitions.
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"psr/container": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^7.3"
"phpunit/phpunit": "^7.3",
"zalas/phpunit-globals": "^1.1"
},
"autoload": {
"psr-4": {
Expand Down
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
</whitelist>
</filter>

<listeners>
<listener class="Zalas\PHPUnit\Globals\AnnotationListener" />
</listeners>

<logging>
<log type="coverage-html" target="build/coverage" lowUpperBound="50" highLowerBound="95"/>
<log type="coverage-clover" target="build/coverage.xml"/>
Expand Down
12 changes: 6 additions & 6 deletions src/Cli/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Zalas\Toolbox\Cli;

use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Application as CliApplication;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
Expand All @@ -22,14 +23,13 @@ public function __construct(string $version, ServiceContainer $serviceContainer)

$this->serviceContainer = $serviceContainer;

$this->setCommandLoader($this->createCommandLoader());
$this->setCommandLoader($this->createCommandLoader($serviceContainer));
}

public function doRun(InputInterface $input, OutputInterface $output)
{
$this->serviceContainer->setParameter('toolbox_json', function () use ($input): array {
return $input->getOption('tools');
});
$this->serviceContainer->set(InputInterface::class, $input);
$this->serviceContainer->set(OutputInterface::class, $output);

return parent::doRun($input, $output);
}
Expand All @@ -49,10 +49,10 @@ private function toolsJsonDefault(): array
: [__DIR__.'/../../resources/pre-installation.json', __DIR__.'/../../resources/tools.json'];
}

private function createCommandLoader(): CommandLoaderInterface
private function createCommandLoader(ContainerInterface $container): CommandLoaderInterface
{
return new ContainerCommandLoader(
$this->serviceContainer,
$container,
[
InstallCommand::NAME => InstallCommand::class,
ListCommand::NAME => ListCommand::class,
Expand Down
2 changes: 2 additions & 0 deletions src/Cli/Command/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\UseCase\InstallTools;
Expand All @@ -26,6 +27,7 @@ public function __construct(InstallTools $useCase, Runner $runner)
protected function configure()
{
$this->setDescription('Installs tools');
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it');
}

protected function execute(InputInterface $input, OutputInterface $output)
Expand Down
2 changes: 2 additions & 0 deletions src/Cli/Command/TestCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\UseCase\TestTools;
Expand All @@ -26,6 +27,7 @@ public function __construct(TestTools $useCase, Runner $runner)
protected function configure()
{
$this->setDescription('Runs basic tests to verify tools are installed');
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it');
}

protected function execute(InputInterface $input, OutputInterface $output)
Expand Down
24 changes: 24 additions & 0 deletions src/Cli/Runner/DryRunner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

namespace Zalas\Toolbox\Cli\Runner;

use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\Tool\Command;

final class DryRunner implements Runner
{
private $output;

public function __construct(OutputInterface $output)
{
$this->output = $output;
}

public function run(Command $command): int
{
$this->output->writeln((string) $command);

return 0;
}
}
63 changes: 63 additions & 0 deletions src/Cli/Runner/LazyRunner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types=1);

namespace Zalas\Toolbox\Cli\Runner;

use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Input\InputInterface;
use Zalas\Toolbox\Runner\PassthruRunner;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\Tool\Command;

final class LazyRunner implements Runner
{
private $container;

private $runner;

public function __construct(ContainerInterface $container)
{
$this->guardServiceAvailability($container);

$this->container = $container;
}

public function run(Command $command): int
{
return $this->runner()->run($command);
}

private function runner(): Runner
{
if (null === $this->runner) {
$this->runner = $this->initializeRunner();
}

return $this->runner;
}

private function initializeRunner(): Runner
{
if ($this->container->get(InputInterface::class)->getOption('dry-run')) {
return $this->container->get(DryRunner::class);
}

return $this->container->get(PassthruRunner::class);
}

private function guardServiceAvailability(ContainerInterface $container): void
{
$requiredServices = [
InputInterface::class,
PassthruRunner::class,
DryRunner::class,
];

foreach ($requiredServices as $serviceId) {
if (!$container->has($serviceId)) {
throw new class(\sprintf('The service "%s" is missing.', $serviceId)) extends \LogicException implements ContainerExceptionInterface {
};
}
}
}
}
66 changes: 43 additions & 23 deletions src/Cli/ServiceContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Cli\Command\InstallCommand;
use Zalas\Toolbox\Cli\Command\ListCommand;
use Zalas\Toolbox\Cli\Command\TestCommand;
use Zalas\Toolbox\Cli\Runner\DryRunner;
use Zalas\Toolbox\Cli\Runner\LazyRunner;
use Zalas\Toolbox\Json\JsonTools;
use Zalas\Toolbox\Runner\PassthruRunner;
use Zalas\Toolbox\Runner\Runner;
Expand All @@ -19,53 +23,57 @@

class ServiceContainer implements ContainerInterface
{
private $parameters;

private $services = [
InstallCommand::class => 'createInstallCommand',
ListCommand::class => 'createListCommand',
TestCommand::class => 'createTestCommand',
Runner::class => 'createRunner',
DryRunner::class => 'createDryRunner',
PassthruRunner::class => 'createPassthruRunner',
InstallTools::class => 'createInstallToolsUseCase',
ListTools::class => 'createListToolsUseCase',
TestTools::class => 'createTestToolsUseCase',
Tools::class => 'createTools',
];

/**
* {@inheritdoc}
*/
public function get($id)
private $runtimeServices = [
InputInterface::class => null,
OutputInterface::class => null,
];

public function set(string $id, /*object */$service): void
{
if (!$this->has($id)) {
throw new class(\sprintf('The "%s" service is not registered in the service container.', $id)) extends \RuntimeException implements NotFoundExceptionInterface {
if (!\array_key_exists($id, $this->runtimeServices)) {
throw new class(\sprintf('The "%s" runtime service is not expected.', $id)) extends RuntimeException implements ContainerExceptionInterface {
};
}

return \call_user_func([$this, $this->services[$id]]);
$this->runtimeServices[$id] = $service;
}

/**
* {@inheritdoc}
*/
public function has($id)
public function get($id)
{
return \in_array($id, \array_keys($this->services));
}
if (isset($this->runtimeServices[$id])) {
return $this->runtimeServices[$id];
}

public function setParameter(string $name, $value): void
{
$this->parameters[$name] = $value;
if (isset($this->services[$id])) {
return \call_user_func([$this, $this->services[$id]]);
}

throw new class(\sprintf('The "%s" service is not registered in the service container.', $id)) extends RuntimeException implements NotFoundExceptionInterface {
};
}

private function getParameter(string $name)
/**
* {@inheritdoc}
*/
public function has($id)
{
if (!isset($this->parameters[$name])) {
throw new class(\sprintf('The "%s" parameter is not defined.', $name)) extends RuntimeException implements ContainerExceptionInterface {
};
}

return $this->parameters[$name];
return isset($this->services[$id]) || isset($this->runtimeServices[$id]);
}

private function createInstallCommand(): InstallCommand
Expand All @@ -84,10 +92,20 @@ private function createTestCommand(): TestCommand
}

private function createRunner(): Runner
{
return new LazyRunner($this);
}

private function createPassthruRunner(): Runner
{
return new PassthruRunner();
}

private function createDryRunner(): Runner
{
return new DryRunner($this->get(OutputInterface::class));
}

private function createInstallToolsUseCase(): InstallTools
{
return new InstallTools($this->get(Tools::class));
Expand All @@ -105,6 +123,8 @@ private function createTestToolsUseCase(): TestTools

private function createTools(): Tools
{
return new JsonTools($this->getParameter('toolbox_json'));
return new JsonTools(function (): array {
return $this->get(InputInterface::class)->getOption('tools');
});
}
}
Loading