Skip to content

Commit

Permalink
Moved installer utilities to traits and classes. Part 2.
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSkrypnyk committed Dec 19, 2024
1 parent b5f98b3 commit 700718e
Show file tree
Hide file tree
Showing 4 changed files with 390 additions and 128 deletions.
4 changes: 3 additions & 1 deletion .vortex/installer/phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<description>Custom PHPCS standard.</description>

<!-- Coding standard. -->
<rule ref="Drupal"/>
<rule ref="Drupal">
<exclude name="Drupal.Commenting.ClassComment.Short" />
</rule>

<!-- Show sniff codes in all reports -->
<arg value="s"/>
Expand Down
224 changes: 147 additions & 77 deletions .vortex/installer/src/Command/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
use DrevOps\Installer\Converter;
use DrevOps\Installer\File;
use DrevOps\Installer\Traits\EnvTrait;
use DrevOps\Installer\Traits\FilesystemTrait;
use DrevOps\Installer\Traits\GitTrait;
use DrevOps\Installer\Traits\PrinterTrait;
use DrevOps\Installer\Traits\PromptsTrait;
use DrevOps\Installer\Traits\TuiTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;

/**
* Run command.
Expand All @@ -31,6 +34,7 @@ class InstallCommand extends Command {
use PrinterTrait;
use PromptsTrait;
use TuiTrait;
use FilesystemTrait;

/**
* Defines installer status message flags.
Expand All @@ -50,11 +54,6 @@ class InstallCommand extends Command {

final const ANSWER_NO = 'n';

/**
* Defines current working directory.
*/
protected static string $currentDir;

/**
* Defines default command name.
*
Expand All @@ -67,14 +66,43 @@ class InstallCommand extends Command {
*/
protected Config $config;

/**
* Output interface.
*/
protected OutputInterface $output;

/**
* Constructor.
*
* @param string|null $name
* File system.
* @param \Symfony\Component\Filesystem\Filesystem $fs
* Command name.
*/
public function __construct(
?string $name = NULL,
?Filesystem $fs = NULL,
) {
parent::__construct($name);
$this->fs = is_null($fs) ? new Filesystem() : $fs;
}

/**
* Configures the current command.
*/
protected function configure(): void {
$this
->setName('Vortex CLI installer')
->addArgument('path', InputArgument::OPTIONAL, 'Destination directory. Optional. Defaults to the current directory.')
->setHelp($this->getHelpText());
$this->setName('Vortex CLI installer');
$this->setDescription('Install Vortex CLI from remote or local repository.');
$this->setHelp(<<<EOF
php install destination
php install --quiet destination
EOF
);
$this->addArgument('path', InputArgument::OPTIONAL, 'Destination directory. Optional. Defaults to the current directory.');

$this->addOption('root', NULL, InputOption::VALUE_REQUIRED, 'Path to the root for file path resolution. If not specified, current directory is used.');

$this->config = new Config();
}
Expand All @@ -83,44 +111,133 @@ protected function configure(): void {
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$cwd = getcwd();
if (!$cwd) {
throw new \RuntimeException('Unable to determine current working directory.');
}
self::$currentDir = $cwd;
$this->output = $output;

static::initConfig($input);
try {
$this->checkRequirements();

if ($this->config->get('help')) {
$output->write($this->getHelpText());
$path = $input->getArgument('path');
$this->resolveOptions($input->getOptions(), $path);

return 0;
$this->doExecute();
}
catch (\Exception $exception) {
$this->output->writeln([
'<error>Processing failed with an error:</error>',
'<error>' . $exception->getMessage() . '</error>',
]);

$this->checkRequirements();
return Command::FAILURE;
}

$this->printHeader();
$this->printFooter();

$this->collectAnswers();
return Command::SUCCESS;
}

if ($this->askShouldProceed()) {
$this->download();
/**
* Instantiate configuration from CLI option and environment variables.
*
* Installer configuration is a set of internal installer script variables,
* read from the environment variables. These environment variables are not
* read directly in any operations of this installer script. Instead, these
* environment variables are accessible with $this->config->get().
*
* For simplicity of naming, internal installer config variables used in
* $this->config->get() are matching environment variables names.
*
* @param array<mixed> $options
* Array of CLI options.
* @param string|null $path
* Destination directory. Optional. Defaults to the current directory.
*/
protected function resolveOptions(array $options, ?string $path): void {
if (!empty($options['quiet'])) {
$this->config->set('quiet', TRUE);
}

$this->prepareDestination();
if (!empty($options['no-ansi'])) {
$this->config->set('ANSI', FALSE);
}
else {
// On Windows, default to no ANSI, except in ANSICON and ConEmu.
// Everywhere else, default to ANSI if stdout is a terminal.
$is_ansi = (DIRECTORY_SEPARATOR === '\\')
? (FALSE !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'))
: (function_exists('posix_isatty') && posix_isatty(1));
$this->config->set('ANSI', $is_ansi);
}

$this->replaceTokens();
// Set root directory to use it for path resolution.
$this->fsSetRootDir(!empty($options['root']) && is_scalar($options['root']) ? strval($options['root']) : NULL);

$this->copyFiles();
// Set destination directory.
if (!empty($path)) {
$path = $this->fsGetAbsolutePath($path);
if (!is_readable($path) || !is_dir($path)) {
throw new \RuntimeException(sprintf('Destination directory "%s" is not readable or does not exist.', $path));
}
}
$this->config->set('VORTEX_INSTALL_DST_DIR', $path ?: static::getenvOrDefault('VORTEX_INSTALL_DST_DIR', $this->fsGetRootDir()));

$this->processDemo();
// Load .env file from the destination directory, if it exists.
if ($this->fs->exists($this->getDstDir() . '/.env')) {
static::loadDotenv($this->getDstDir() . '/.env');
}

// Internal version of Vortex.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_VERSION', static::getenvOrDefault('VORTEX_VERSION', 'develop'));
// Flag to display install debug information.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_INSTALL_DEBUG', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEBUG', FALSE));
// Flag to proceed with installation. If FALSE - the installation will only
// print resolved values and will not proceed.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_INSTALL_PROCEED', (bool) static::getenvOrDefault('VORTEX_INSTALL_PROCEED', TRUE));
// Temporary directory to download and expand files to.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_INSTALL_TMP_DIR', static::getenvOrDefault('VORTEX_INSTALL_TMP_DIR', File::createTempdir()));
// Path to local Vortex repository. If not provided - remote will be used.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_INSTALL_LOCAL_REPO', static::getenvOrDefault('VORTEX_INSTALL_LOCAL_REPO'));
// Optional commit to download. If not provided, latest release will be
// downloaded.
// @todo Convert to option and remove from the environment variables.
$this->config->set('VORTEX_INSTALL_COMMIT', static::getenvOrDefault('VORTEX_INSTALL_COMMIT', 'HEAD'));

$this->printFooter();
// Internal flag to enforce DEMO mode. If not set, the demo mode will be
// discovered automatically.
if (!is_null(static::getenvOrDefault('VORTEX_INSTALL_DEMO'))) {
$this->config->set('VORTEX_INSTALL_DEMO', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEMO'));
}
else {
// Internal flag to skip processing of the demo mode.
$this->config->set('VORTEX_INSTALL_DEMO_SKIP', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEMO_SKIP', FALSE));
}

/**
* Execute the command.
*/
protected function doExecute(): void {
$this->printHeader();

$this->collectAnswers();

if (!$this->askShouldProceed()) {
$this->printAbort();
}

return 0;
$this->download();

$this->prepareDestination();

$this->replaceTokens();

$this->copyFiles();

$this->processDemo();

$this->printFooter();
}

protected function prepareDestination(): void {
Expand Down Expand Up @@ -466,42 +583,6 @@ protected function collectAnswers(): void {
}
}

/**
* Instantiate installer configuration from environment variables.
*
* Installer configuration is a set of internal installer script variables,
* read from the environment variables. These environment variables are not
* read directly in any operations of this installer script. Instead, these
* environment variables are accessible with get_installer_config().
*
* For simplicity of naming, internal installer config variables are matching
* environment variables names.
*/
protected function initInstallerConfig(): void {
// Internal version of Vortex.
$this->config->set('VORTEX_VERSION', static::getenvOrDefault('VORTEX_VERSION', 'develop'));
// Flag to display install debug information.
$this->config->set('VORTEX_INSTALL_DEBUG', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEBUG', FALSE));
// Flag to proceed with installation. If FALSE - the installation will only
// print resolved values and will not proceed.
$this->config->set('VORTEX_INSTALL_PROCEED', (bool) static::getenvOrDefault('VORTEX_INSTALL_PROCEED', TRUE));
// Temporary directory to download and expand files to.
$this->config->set('VORTEX_INSTALL_TMP_DIR', static::getenvOrDefault('VORTEX_INSTALL_TMP_DIR', File::createTempdir()));
// Path to local Vortex repository. If not provided - remote will be used.
$this->config->set('VORTEX_INSTALL_LOCAL_REPO', static::getenvOrDefault('VORTEX_INSTALL_LOCAL_REPO'));
// Optional commit to download. If not provided, latest release will be
// downloaded.
$this->config->set('VORTEX_INSTALL_COMMIT', static::getenvOrDefault('VORTEX_INSTALL_COMMIT', 'HEAD'));

// Internal flag to enforce DEMO mode. If not set, the demo mode will be
// discovered automatically.
if (!is_null(static::getenvOrDefault('VORTEX_INSTALL_DEMO'))) {
$this->config->set('VORTEX_INSTALL_DEMO', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEMO'));
}
// Internal flag to skip processing of the demo mode.
$this->config->set('VORTEX_INSTALL_DEMO_SKIP', (bool) static::getenvOrDefault('VORTEX_INSTALL_DEMO_SKIP', FALSE));
}

protected function getDstDir(): ?string {
return $this->config->get('VORTEX_INSTALL_DST_DIR');
}
Expand Down Expand Up @@ -545,15 +626,4 @@ protected function executeCallback(string $prefix, string $name): mixed {
return NULL;
}

/**
* Init all config.
*/
public function initConfig(InputInterface $input): void {
$this->initCliArgsAndOptions($input);

static::loadDotenv($this->getDstDir() . '/.env');

$this->initInstallerConfig();
}

}
Loading

1 comment on commit 700718e

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.