* initial commit

This commit is contained in:
David Danyi 2019-10-29 21:45:28 +01:00
commit 2cf81c493e
35 changed files with 3616 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
vendor/

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2013-2019 Medvedev Anton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

22
bin/automatique Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/php
<?php
require __DIR__ . '/../vendor/autoload.php';
use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
/** @var ContainerInterface $container */
$container = require __DIR__ . '/../config/container.php';
/** @var Application $application */
$application = $container->get(Application::class);
$commands = $container->get('config')['console']['commands'];
foreach ($commands as $command) {
$application->add($container->get($command));
}
$lazyCommands = $container->get('config')['console']['lazy_commands'];
$lazyLoader = new ContainerCommandLoader($container, $lazyCommands);
$application->setCommandLoader($lazyLoader);
$application->run();

72
bin/build Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env php
<?php
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require __DIR__ . '/../vendor/autoload.php';
define('ROOT', realpath(__DIR__ . '/..'));
$opt = getopt('v::');
$version = 'dev-master';
if (array_key_exists('v', $opt)) {
$version = $opt['v'];
if (!preg_match('/^\d+\.\d+\.\d+(-[\d\w\.]+)?$/i', $version)) {
die("Version number must follow semantic versioning.\n");
}
}
chdir(ROOT);
exec('composer install --no-dev');
$pharName = "automatique.phar";
$pharFile = ROOT . '/' . $pharName;
if (file_exists($pharFile)) {
unlink($pharFile);
}
$phar = new \Phar($pharFile, 0, $pharName);
$phar->setSignatureAlgorithm(\Phar::SHA1);
$phar->startBuffering();
$iterator = new RecursiveDirectoryIterator(ROOT, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveCallbackFilterIterator($iterator, function (SplFileInfo $fileInfo) {
return !in_array($fileInfo->getBasename(), ['.git', 'Tests', 'test'], true);
});
$iterator = new RecursiveIteratorIterator($iterator);
$iterator = new CallbackFilterIterator($iterator, function (SplFileInfo $fileInfo) {
return in_array($fileInfo->getExtension(), ['php', 'exe'], true);
});
foreach ($iterator as $fileInfo) {
$file = str_replace(ROOT, '', $fileInfo->getRealPath());
echo "Add file: " . $file . "\n";
$phar->addFile($fileInfo->getRealPath(), $file);
}
// Add bin/dep file
$depContent = file_get_contents(ROOT . '/bin/automatique');
$depContent = str_replace("#!/usr/bin/php\n", '', $depContent);
$depContent = str_replace("'master'", "'$version'", $depContent);
$depContent = str_replace('__FILE__', 'str_replace("phar://", "", Phar::running())', $depContent);
$phar->addFromString('bin/automatique', $depContent);
$stub = <<<STUB
#!/usr/bin/env php
<?php
Phar::mapPhar('{$pharName}');
require 'phar://{$pharName}/bin/automatique';
__HALT_COMPILER();
STUB;
$phar->setStub($stub);
$phar->compressFiles(Phar::GZ);
$phar->stopBuffering();
unset($phar);
echo "$pharName was created successfully.\n";

View File

@ -0,0 +1,48 @@
<?php
/**
* Script for clearing the configuration cache.
*
* Can also be invoked as `composer clear-config-cache`.
*
* @see https://github.com/zendframework/zend-expressive-skeleton for the canonical source repository
* @copyright Copyright (c) 2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-expressive-skeleton/blob/master/LICENSE.md New BSD License
*/
declare(strict_types=1);
chdir(__DIR__ . '/../');
require 'vendor/autoload.php';
$config = include 'config/config.php';
if (! isset($config['config_cache_path'])) {
echo "No configuration cache path found" . PHP_EOL;
exit(0);
}
if (! file_exists($config['config_cache_path'])) {
printf(
"Configured config cache file '%s' not found%s",
$config['config_cache_path'],
PHP_EOL
);
exit(0);
}
if (false === unlink($config['config_cache_path'])) {
printf(
"Error removing config cache file '%s'%s",
$config['config_cache_path'],
PHP_EOL
);
exit(1);
}
printf(
"Removed configured config cache file '%s'%s",
$config['config_cache_path'],
PHP_EOL
);
exit(0);

45
composer.json Normal file
View File

@ -0,0 +1,45 @@
{
"name": "edvidan/automatique",
"description": "Workflow auto installer",
"license": "MIT",
"homepage": "https://none",
"support": {
"issues": "https://github.com/deployphp/deployer/issues",
"source": "https://github.com/deployphp/deployer",
"docs": "https://deployer.org/docs"
},
"authors": [
{
"name": "Dávid Danyi",
"email": "david.danyi@ericsson.com"
}
],
"autoload": {
"psr-4": {
"App\\": "src/App"
}
},
"bin": [
"bin/dep"
],
"require": {
"php": "~7.2",
"doctrine/collections": "^1.6",
"phpseclib/phpseclib": "~2.0",
"symfony/console": "~4.0",
"symfony/process": "~4.0",
"symfony/yaml": "~4.0",
"zendframework/zend-component-installer": "^2.1.1",
"zendframework/zend-config-aggregator": "^1.0",
"zendframework/zend-json": "3.1.0",
"zendframework/zend-servicemanager": "^3.3",
"zendframework/zend-stdlib": "^3.1"
},
"require-dev": {
"phpunit/phpunit": "^6.4.3",
"roave/security-advisories": "dev-master"
},
"config": {
"sort-packages": true
}
}

2629
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

1
config/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
development.config.php

2
config/autoload/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
local.php
*.local.php

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
return [
// Provides application-wide services.
// We recommend using fully-qualified class names whenever possible as
// service names.
'dependencies' => [
// Use 'aliases' to alias a service name to another service. The
// key is the alias name, the value is the service to which it points.
'aliases' => [],
// Use 'invokables' for constructor-less services, or services that do
// not require arguments to the constructor. Map a service name to the
// class name.
'invokables' => [],
// Use 'factories' for services provided by callbacks/factory classes.
'factories' => [
Symfony\Component\Console\Application::class => App\ApplicationFactory::class,
],
],
];

View File

@ -0,0 +1,35 @@
<?php
/**
* Development-only configuration.
*
* Put settings you want enabled when under development mode in this file, and
* check it into your repository.
*
* Developers on your team will then automatically enable them by calling on
* `composer development-enable`.
*/
declare(strict_types=1);
use Zend\Expressive\Container;
use Zend\Expressive\Middleware\ErrorResponseGenerator;
return [
'dependencies' => [
'invokables' => [
],
'factories' => [
ErrorResponseGenerator::class => Container\WhoopsErrorResponseGeneratorFactory::class,
'Zend\Expressive\Whoops' => Container\WhoopsFactory::class,
'Zend\Expressive\WhoopsPageHandler' => Container\WhoopsPageHandlerFactory::class,
],
],
'whoops' => [
'json_exceptions' => [
'display' => true,
'show_trace' => true,
'ajax_only' => true,
],
],
];

View File

@ -0,0 +1,12 @@
<?php
/**
* Local configuration.
*
* Copy this file to `local.php` and change its settings as required.
* `local.php` is ignored by git and safe to use for local and sensitive data like usernames and passwords.
*/
declare(strict_types=1);
return [
];

39
config/config.php Normal file
View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
use Zend\ConfigAggregator\ArrayProvider;
use Zend\ConfigAggregator\ConfigAggregator;
use Zend\ConfigAggregator\PhpFileProvider;
// To enable or disable caching, set the `ConfigAggregator::ENABLE_CACHE` boolean in
// `config/autoload/local.php`.
$cacheConfig = [
'config_cache_path' => 'cache/config-cache.php',
];
$aggregator = new ConfigAggregator([
// Include cache configuration
new ArrayProvider($cacheConfig),
// Swoole config to overwrite some services (if installed)
class_exists(\Zend\Expressive\Swoole\ConfigProvider::class)
? \Zend\Expressive\Swoole\ConfigProvider::class
: function(){ return[]; },
// Default App module config
App\ConfigProvider::class,
// Load application config in a pre-defined order in such a way that local settings
// overwrite global settings. (Loaded as first to last):
// - `global.php`
// - `*.global.php`
// - `local.php`
// - `*.local.php`
new PhpFileProvider(realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php'),
// Load development config if it exists
new PhpFileProvider(realpath(__DIR__) . '/development.config.php'),
], $cacheConfig['config_cache_path']);
return $aggregator->getMergedConfig();

14
config/container.php Normal file
View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
use Zend\ServiceManager\ServiceManager;
// Load configuration
$config = require __DIR__ . '/config.php';
$dependencies = $config['dependencies'];
$dependencies['services']['config'] = $config;
// Build container
return new ServiceManager($dependencies);

View File

@ -0,0 +1,30 @@
<?php
/**
* File required to allow enablement of development mode.
*
* For use with the zf-development-mode tool.
*
* Usage:
* $ composer development-disable
* $ composer development-enable
* $ composer development-status
*
* DO NOT MODIFY THIS FILE.
*
* Provide your own development-mode settings by editing the file
* `config/autoload/development.local.php.dist`.
*
* Because this file is aggregated last, it simply ensures:
*
* - The `debug` flag is _enabled_.
* - Configuration caching is _disabled_.
*/
declare(strict_types=1);
use Zend\ConfigAggregator\ConfigAggregator;
return [
'debug' => true,
ConfigAggregator::ENABLE_CACHE => false,
];

20
phpcs.xml.dist Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<ruleset name="Expressive Skeleton coding standard">
<description>Expressive Skeleton coding standard</description>
<!-- display progress -->
<arg value="p"/>
<arg name="colors"/>
<!-- inherit rules from: -->
<rule ref="PSR2"/>
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
<properties>
<property name="ignoreBlankLines" value="false"/>
</properties>
</rule>
<!-- Paths to check -->
<file>src</file>
</ruleset>

17
phpunit.xml.dist Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="App\\Tests">
<directory>./test</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View 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');
}
}

View 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), ".");
}
}

View 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);
}
}

View 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);
}
}
}

View 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);
}
}

View 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"));
}
}

View 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);
}
}

View 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);
}
}

View 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,
],
];
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace App\Downloader;
interface DownloaderInterface {
public function download(string $remote, string $local): string;
}

View 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
View 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();
}
}

View 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
View 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();
}
}

View 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);
}
}

View 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();
}
}

View 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);
}
}

View 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);
}
}