* initial commit
This commit is contained in:
16
src/App/ApplicationFactory.php
Normal file
16
src/App/ApplicationFactory.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
class ApplicationFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): Application
|
||||
{
|
||||
return new Application('Application console');
|
||||
}
|
||||
}
|
||||
82
src/App/Command/BuildPackage.php
Normal file
82
src/App/Command/BuildPackage.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Downloader\SCP;
|
||||
use App\Service\Builder;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class BuildPackage extends Command
|
||||
{
|
||||
use SharedStorage;
|
||||
const NAME = "standalone:build-package";
|
||||
|
||||
/** @var Builder */
|
||||
private $builder;
|
||||
|
||||
public function __construct(Builder $builder, Collection $storage)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->sharedStorage = $storage;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName(self::NAME)
|
||||
->setDescription('Build packages on remote host')
|
||||
->addOption("host", null, InputOption::VALUE_REQUIRED, "", false)
|
||||
->addOption("path", null, InputOption::VALUE_REQUIRED, "", false)
|
||||
;
|
||||
}
|
||||
|
||||
protected function saveToShared(string $name, $value)
|
||||
{
|
||||
$this->sharedStorage->set(sprintf("%s:%s", self::NAME, $name), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$host = $input->getOption("host");
|
||||
$path = $input->getOption("path");
|
||||
if (!$host && !$path) {
|
||||
throw new Exception("Missing arguments");
|
||||
}
|
||||
$this->saveToShared("host", $host);
|
||||
$this->saveToShared("path", $path);
|
||||
$output->writeln("<info>Building package:</info>");
|
||||
// $helper = $this->getHelper('process');
|
||||
// $tableSection = $output->section();
|
||||
// $totalProgressSection = $output->section();
|
||||
// $itemProgressSection = $output->section();
|
||||
// $table = new Table($tableSection);
|
||||
// $table->setHeaders([
|
||||
// 'Title',
|
||||
// 'Pages',
|
||||
// 'Size',
|
||||
// ]);
|
||||
// $table->render();
|
||||
// $totalProgress = new ProgressBar($totalProgressSection);
|
||||
// $itemProgress = new ProgressBar($itemProgressSection);
|
||||
$remotePackage = $this->builder->buildRemotePackage($host, $path);
|
||||
$this->saveToShared("package", $remotePackage);
|
||||
$downloader = new SCP();
|
||||
$downloader->download(sprintf("%s:%s", $host, $remotePackage), ".");
|
||||
}
|
||||
}
|
||||
20
src/App/Command/BuildPackageFactory.php
Normal file
20
src/App/Command/BuildPackageFactory.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\Builder;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Interop\Container\ContainerInterface;
|
||||
|
||||
class BuildPackageFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): BuildPackage
|
||||
{
|
||||
/** @var Builder $builder */
|
||||
$builder = $container->get(Builder::class);
|
||||
$sharedStorage = $container->get(ArrayCollection::class);
|
||||
return new BuildPackage($builder, $sharedStorage);
|
||||
}
|
||||
}
|
||||
63
src/App/Command/ComplexTaskConfig.php
Normal file
63
src/App/Command/ComplexTaskConfig.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\ConfigProvider;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ComplexTaskConfig extends Command
|
||||
{
|
||||
/** @var ConfigProvider */
|
||||
private $configProvider;
|
||||
|
||||
/** @var ArrayCollection */
|
||||
private $sharedStorage;
|
||||
|
||||
public function __construct(ConfigProvider $configProvider, ArrayCollection $sharedStorage)
|
||||
{
|
||||
$this->configProvider = $configProvider;
|
||||
$this->sharedStorage = $sharedStorage;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('complex:task-config')
|
||||
->setDescription('Build using task config');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$taskConfig = $this->configProvider->getTaskConfig();
|
||||
$app = $this->getApplication();
|
||||
foreach ($taskConfig as $task) {
|
||||
$cmd = $app->find($task['command']);
|
||||
$args = [
|
||||
'command' => $task['command']
|
||||
];
|
||||
|
||||
if (isset($task['args']) && is_array($task['args'])) {
|
||||
$args += $task['args'];
|
||||
}
|
||||
|
||||
if (isset($task['stored-args']) && is_array($task['stored-args'])) {
|
||||
foreach ($task['stored-args'] as $key => $storedArg) {
|
||||
$args[$key] = $this->sharedStorage->get($storedArg);
|
||||
}
|
||||
}
|
||||
$cmd->run(new ArrayInput($args), $output);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/App/Command/ComplexTaskConfigFactory.php
Normal file
21
src/App/Command/ComplexTaskConfigFactory.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\ConfigProvider;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Interop\Container\ContainerInterface;
|
||||
|
||||
class ComplexTaskConfigFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): ComplexTaskConfig
|
||||
{
|
||||
/** @var ConfigProvider $configProvider */
|
||||
$configProvider = $container->get(ConfigProvider::class);
|
||||
/** @var ArrayCollection $builder */
|
||||
$builder = $container->get(ArrayCollection::class);
|
||||
return new ComplexTaskConfig($configProvider, $builder);
|
||||
}
|
||||
}
|
||||
57
src/App/Command/GenerateOnboardPackage.php
Normal file
57
src/App/Command/GenerateOnboardPackage.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\Builder;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class GenerateOnboardPackage extends Command
|
||||
{
|
||||
use SharedStorage;
|
||||
const NAME = "standalone:generate-onboard-package";
|
||||
|
||||
/** @var Builder */
|
||||
private $builder;
|
||||
|
||||
public function __construct(Builder $builder, Collection $storage)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->sharedStorage = $storage;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName(self::NAME)
|
||||
->setDescription('Gen onboard package')
|
||||
->addOption("host", null, InputOption::VALUE_REQUIRED, "", false)
|
||||
->addOption("package", null, InputOption::VALUE_REQUIRED, "", false)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$host = $input->getOption("host");
|
||||
$package = $input->getOption("package");
|
||||
if (!$host && !$package) {
|
||||
throw new Exception("Missing arguments");
|
||||
}
|
||||
$this->saveToShared("host", $host);
|
||||
$this->saveToShared("path", $package);
|
||||
$output->writeln("<info>Generate onboard package:</info>");
|
||||
$output->writeln("Got args: " . $input->getOption("host") . $input->getOption("package"));
|
||||
}
|
||||
}
|
||||
20
src/App/Command/GenerateOnboardPackageFactory.php
Normal file
20
src/App/Command/GenerateOnboardPackageFactory.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\Builder;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Interop\Container\ContainerInterface;
|
||||
|
||||
class GenerateOnboardPackageFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): GenerateOnboardPackage
|
||||
{
|
||||
/** @var Builder $builder */
|
||||
$builder = $container->get(Builder::class);
|
||||
$sharedStorage = $container->get(ArrayCollection::class);
|
||||
return new GenerateOnboardPackage($builder, $sharedStorage);
|
||||
}
|
||||
}
|
||||
18
src/App/Command/SharedStorage.php
Normal file
18
src/App/Command/SharedStorage.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
trait SharedStorage
|
||||
{
|
||||
/** @var Collection */
|
||||
protected $sharedStorage;
|
||||
|
||||
protected function saveToShared(string $name, $value)
|
||||
{
|
||||
$this->sharedStorage->set(sprintf("%s:%s", self::NAME, $name), $value);
|
||||
}
|
||||
}
|
||||
67
src/App/ConfigProvider.php
Normal file
67
src/App/ConfigProvider.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Command;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* The configuration provider for the App module
|
||||
*
|
||||
* @see https://docs.zendframework.com/zend-component-installer/
|
||||
*/
|
||||
class ConfigProvider
|
||||
{
|
||||
/**
|
||||
* Returns the configuration array
|
||||
*
|
||||
* To add a bit of a structure, each section is defined in a separate
|
||||
* method which returns an array with its configuration.
|
||||
*
|
||||
*/
|
||||
public function __invoke() : array
|
||||
{
|
||||
return [
|
||||
'dependencies' => $this->getDependencies(),
|
||||
'console' => $this->getConsole(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the container dependencies
|
||||
*/
|
||||
public function getDependencies() : array
|
||||
{
|
||||
return [
|
||||
'invokables' => [
|
||||
ArrayCollection::class,
|
||||
],
|
||||
'factories' => [
|
||||
Service\Builder::class => Service\BuilderFactory::class,
|
||||
Service\ConfigProvider::class => Service\ConfigProviderFactory::class,
|
||||
|
||||
Command\BuildPackage::class => Command\BuildPackageFactory::class,
|
||||
Command\ComplexTaskConfig::class => Command\ComplexTaskConfigFactory::class,
|
||||
Command\GenerateOnboardPackage::class => Command\GenerateOnboardPackageFactory::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the templates configuration
|
||||
*/
|
||||
public function getConsole() : array
|
||||
{
|
||||
return [
|
||||
'commands' => [
|
||||
Command\ComplexTaskConfig::class,
|
||||
],
|
||||
'lazy_commands' => [
|
||||
Command\BuildPackage::NAME => Command\BuildPackage::class,
|
||||
Command\GenerateOnboardPackage::NAME => Command\GenerateOnboardPackage::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
9
src/App/Downloader/DownloaderInterface.php
Normal file
9
src/App/Downloader/DownloaderInterface.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Downloader;
|
||||
|
||||
interface DownloaderInterface {
|
||||
public function download(string $remote, string $local): string;
|
||||
}
|
||||
21
src/App/Downloader/SCP.php
Normal file
21
src/App/Downloader/SCP.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Downloader;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class SCP implements DownloaderInterface
|
||||
{
|
||||
public function download(string $remote, string $local): string
|
||||
{
|
||||
$process = new Process([
|
||||
'scp',
|
||||
$remote,
|
||||
$local
|
||||
]);
|
||||
$process->run();
|
||||
return $process->getOutput();
|
||||
}
|
||||
}
|
||||
19
src/App/Runner/Local.php
Normal file
19
src/App/Runner/Local.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Runner;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class Local implements RunnerInterface
|
||||
{
|
||||
public function execute($command): string
|
||||
{
|
||||
$process = new Process([
|
||||
$command
|
||||
]);
|
||||
$process->run();
|
||||
return $process->getOutput();
|
||||
}
|
||||
}
|
||||
9
src/App/Runner/RunnerInterface.php
Normal file
9
src/App/Runner/RunnerInterface.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Runner;
|
||||
|
||||
interface RunnerInterface {
|
||||
public function execute($command): string;
|
||||
}
|
||||
31
src/App/Runner/SSH.php
Normal file
31
src/App/Runner/SSH.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Runner;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class SSH implements RunnerInterface
|
||||
{
|
||||
private $hostname;
|
||||
|
||||
public function __construct($hostname)
|
||||
{
|
||||
$this->hostname = $hostname;
|
||||
}
|
||||
|
||||
public function execute($command): string
|
||||
{
|
||||
$process = new Process([
|
||||
'ssh',
|
||||
$this->hostname,
|
||||
$command
|
||||
]);
|
||||
$process->run();
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new \Exception("Command failed with: " . $process->getErrorOutput());
|
||||
}
|
||||
return $process->getOutput();
|
||||
}
|
||||
}
|
||||
27
src/App/Service/Builder.php
Normal file
27
src/App/Service/Builder.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Runner\SSH;
|
||||
use Exception;
|
||||
|
||||
class Builder
|
||||
{
|
||||
const PACKAGE_BUILDER_SCRIPT = "prepare_package.sh";
|
||||
|
||||
/**
|
||||
* @param $host
|
||||
* @param $path
|
||||
* @return string Generated filename on remote host
|
||||
* @throws Exception
|
||||
*/
|
||||
public function buildRemotePackage($host, $path): string
|
||||
{
|
||||
$runner = new SSH($host);
|
||||
$out = $runner->execute(sprintf("%s/%s", $path, self::PACKAGE_BUILDER_SCRIPT));
|
||||
$lines = explode("\n", trim($out));
|
||||
return array_pop($lines);
|
||||
}
|
||||
}
|
||||
15
src/App/Service/BuilderFactory.php
Normal file
15
src/App/Service/BuilderFactory.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Interop\Container\ContainerInterface;
|
||||
|
||||
class BuilderFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): Builder
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
}
|
||||
65
src/App/Service/ConfigProvider.php
Normal file
65
src/App/Service/ConfigProvider.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
const CONFIG_DIR = "automatique";
|
||||
|
||||
private $taskFile = "automatique.task.yaml";
|
||||
private $envFile = "automatique.env.yaml";
|
||||
|
||||
private $loadOrder = [];
|
||||
|
||||
public function __construct(?string $taskOverride, ?string $envOverride)
|
||||
{
|
||||
if ($taskOverride) {
|
||||
$this->taskFile = $taskOverride;
|
||||
}
|
||||
if ($envOverride) {
|
||||
$this->envFile = $envOverride;
|
||||
}
|
||||
$this->loadOrder[] = ".";
|
||||
$userCfgDir = sprintf("%s/.config/%s", $_SERVER['HOME'], self::CONFIG_DIR);
|
||||
if (file_exists($userCfgDir)) {
|
||||
$this->loadOrder[] = $userCfgDir;
|
||||
}
|
||||
$globalCfgDir = sprintf("/etc/%s", self::CONFIG_DIR);
|
||||
if (file_exists($globalCfgDir)) {
|
||||
$this->loadOrder[] = $globalCfgDir;
|
||||
}
|
||||
}
|
||||
|
||||
private function findConfigFile($filename): string
|
||||
{
|
||||
foreach ($this->loadOrder as $loadDir) {
|
||||
$configFile = "${loadDir}/${filename}";
|
||||
if (file_exists($configFile)) {
|
||||
return $configFile;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Couldn't locate $filename");
|
||||
}
|
||||
|
||||
private function readConfigFile($configFile): ?iterable
|
||||
{
|
||||
$configFile = $this->findConfigFile($configFile);
|
||||
return Yaml::parseFile($configFile);
|
||||
}
|
||||
|
||||
public function getEnvironmentConfig(): ?iterable
|
||||
{
|
||||
return $this->readConfigFile($this->envFile);
|
||||
}
|
||||
|
||||
public function getTaskConfig(): ?iterable
|
||||
{
|
||||
return $this->readConfigFile($this->taskFile);
|
||||
}
|
||||
}
|
||||
25
src/App/Service/ConfigProviderFactory.php
Normal file
25
src/App/Service/ConfigProviderFactory.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
class ConfigProviderFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): ConfigProvider
|
||||
{
|
||||
$taskFile = null;
|
||||
$envFile = null;
|
||||
$args = new ArgvInput();
|
||||
if ($args->hasOption("env-file")) {
|
||||
$envFile = $args->getOption("env-file");
|
||||
}
|
||||
if ($args->hasOption("task-file")) {
|
||||
$taskFile = $args->getOption("task-file");
|
||||
}
|
||||
return new ConfigProvider($taskFile, $envFile);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user