Skip to content

Commit 3cae214

Browse files
authored
Use dependency injection (#99)
1 parent 6d214fd commit 3cae214

84 files changed

Lines changed: 2481 additions & 964 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# In all environments, the following files are loaded if they exist,
2+
# the latter taking precedence over the former:
3+
#
4+
# * .env contains default values for the environment variables needed by the app
5+
# * .env.local uncommitted file with local overrides
6+
# * .env.$APP_ENV committed environment-specific defaults
7+
# * .env.$APP_ENV.local uncommitted environment-specific overrides
8+
#
9+
# Real environment variables win over .env files.
10+
#
11+
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
12+
#
13+
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
14+
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
15+
APP_ENV=prod
16+
APP_DEBUG=0

.gitignore

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
1-
drupal
1+
###> symfony/framework-bundle ###
2+
/.env.local
3+
/.env.local.php
4+
/.env.*.local
5+
/var/
26
/vendor/
7+
###< symfony/framework-bundle ###
8+
9+
drupal
310
.idea
4-
.phpcs-cache
511
build
612
.DS_STORE
713
tests/fixtures/.acquia/acquia-cli.json
814
tests/fixtures/.acquia/cloud_api.conf
915
*.phar
16+
17+
###> squizlabs/php_codesniffer ###
18+
/.phpcs-cache
19+
/phpcs.xml
20+
###< squizlabs/php_codesniffer ###
21+
22+
###> phpunit/phpunit ###
23+
/phpunit.xml
24+
.phpunit.result.cache
25+
###< phpunit/phpunit ###
26+
1027
cx-api-spec

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ jobs:
3939
- stage: "Build packages for CLI"
4040
if: tag IS present
4141
install: composer install --no-dev --optimize-autoloader && composer box-install
42+
# Warm the symfony cache so it gets bundled with phar.
43+
before_script: ./bin/acli
4244
script: composer box-compile
4345
deploy:
4446
provider: releases

bin/acli

Lines changed: 70 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -3,170 +3,91 @@
33

44
/**
55
* @file
6+
* Acquia CLI command line front file.
7+
*
8+
* This is largely based on the default bin/console command that ships with a
9+
* Symfony app. However, it's been modified to not rely on the Framework Bundle,
10+
* which spares us from unnecessary dependencies such as the routing layer.
11+
*
12+
* ORCA does something similar.
13+
*
14+
* @see https://github.com/TravisCarden/stackoverflow-a-50356503
615
*/
716

8-
use Acquia\Cli\AcquiaCliApplication;
9-
use Acquia\Cli\Command\Api\ApiListCommand;
10-
use Acquia\Cli\Command\AuthCommand;
11-
use Acquia\Cli\Command\Ide\IdeCreateCommand;
12-
use Acquia\Cli\Command\Ide\IdeDeleteCommand;
13-
use Acquia\Cli\Command\Ide\IdeListCommand;
14-
use Acquia\Cli\Command\Ide\IdeOpenCommand;
15-
use Acquia\Cli\Command\Ide\Wizard\IdeWizardCreateSshKeyCommand;
16-
use Acquia\Cli\Command\Ide\Wizard\IdeWizardDeleteSshKeyCommand;
17-
use Acquia\Cli\Command\LinkCommand;
18-
use Acquia\Cli\Command\LogTailCommand;
19-
use Acquia\Cli\Command\NewCommand;
20-
use Acquia\Cli\Command\RefreshCommand;
21-
use Acquia\Cli\Command\Remote\AliasesDownloadCommand;
22-
use Acquia\Cli\Command\Remote\AliasListCommand;
23-
use Acquia\Cli\Command\Remote\DrushCommand;
24-
use Acquia\Cli\Command\Remote\SshCommand;
25-
use Acquia\Cli\Command\Ssh\SshKeyCreateCommand;
26-
use Acquia\Cli\Command\Ssh\SshKeyCreateUploadCommand;
27-
use Acquia\Cli\Command\Ssh\SshKeyDeleteCommand;
28-
use Acquia\Cli\Command\Ssh\SshKeyListCommand;
29-
use Acquia\Cli\Command\Ssh\SshKeyUploadCommand;
30-
use Acquia\Cli\Command\TelemetryCommand;
31-
use Acquia\Cli\Command\UnlinkCommand;
32-
use Acquia\Cli\Command\UpdateCommand;
33-
use Acquia\Cli\Helpers\ClientService;
34-
use Acquia\Cli\Helpers\LocalMachineHelper;
35-
use Acquia\Cli\Helpers\TelemetryHelper;
36-
use Symfony\Component\Console\Helper\QuestionHelper;
37-
use AcquiaLogstream\LogstreamManager;
17+
namespace Acquia\Cli;
18+
19+
use Acquia\Cli\Command\Api\ApiCommandHelper;
20+
use Acquia\Cli\Exception\AcquiaCliException;
21+
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
22+
use Symfony\Component\Console\Application;
23+
use Symfony\Component\Console\ConsoleEvents;
24+
use Symfony\Component\Console\Event\ConsoleErrorEvent;
3825
use Symfony\Component\Console\Input\ArgvInput;
39-
use Symfony\Component\Console\Logger\ConsoleLogger;
40-
use Symfony\Component\Console\Output\ConsoleOutput;
41-
use Symfony\Component\DependencyInjection\Reference;
42-
use Webmozart\KeyValueStore\JsonFileStore;
43-
use Webmozart\PathUtil\Path;
44-
use Zumba\Amplitude\Amplitude;
26+
use Symfony\Component\Dotenv\Dotenv;
27+
use Symfony\Component\ErrorHandler\Debug;
28+
use Symfony\Component\EventDispatcher\EventDispatcher;
29+
use Symfony\Component\Filesystem\Filesystem;
4530

46-
$pharPath = Phar::running(TRUE);
47-
if ($pharPath) {
48-
require_once "$pharPath/vendor/autoload.php";
31+
if (!in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
32+
echo 'Warning: The console should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
4933
}
50-
else {
51-
require_once __DIR__ . '/../vendor/autoload.php';
52-
}
53-
54-
// Create the input and output objects for Acquia CLI to run against.
55-
$input = new ArgvInput($_SERVER['argv']);
56-
$output = new ConsoleOutput();
57-
$logger = new ConsoleLogger($output);
58-
$container = new Symfony\Component\DependencyInjection\ContainerBuilder();
59-
$container->setParameter('repo_root', find_repo_root());
60-
$container->setParameter('data_dir', LocalMachineHelper::getHomeDir() . '/.acquia');
61-
AcquiaCliApplication::configureContainer($container, $input, $output, $logger);
6234

63-
/**
64-
* Running Acquia CLI.
65-
*/
66-
$application = new AcquiaCliApplication($container, $logger, $input, $output, '@package_version@');
67-
$application->addCommands([
68-
new AliasesDownloadCommand(),
69-
new AliasListCommand(),
70-
new AuthCommand(),
71-
new ApiListCommand(),
72-
new DrushCommand(),
73-
new IdeCreateCommand(),
74-
new IdeDeleteCommand(),
75-
new IdeListCommand(),
76-
new IdeOpenCommand(),
77-
new IdeWizardCreateSshKeyCommand(),
78-
new IdeWizardDeleteSshKeyCommand(),
79-
new LinkCommand(),
80-
new LogTailCommand(),
81-
new NewCommand(),
82-
new RefreshCommand(),
83-
new SshCommand(),
84-
new SshKeyCreateCommand(),
85-
new SshKeyDeleteCommand(),
86-
new SshKeyListCommand(),
87-
new SshKeyUploadCommand(),
88-
new SshKeyCreateUploadCommand(),
89-
new TelemetryCommand(),
90-
new UnlinkCommand(),
91-
new UpdateCommand(),
92-
]);
35+
set_time_limit(0);
9336

94-
$status_code = $application->run($input, $output);
95-
exit($status_code);
37+
require dirname(__DIR__).'/vendor/autoload.php';
9638

97-
/**
98-
* Finds the root directory for the repository.
99-
*
100-
* @return null|string
101-
* Root.
102-
*/
103-
function find_repo_root() {
104-
$possible_repo_roots = [
105-
getcwd(),
106-
];
107-
// Check for PWD - some local environments will not have this key.
108-
if (isset($_SERVER['PWD']) && !in_array($_SERVER['PWD'], $possible_repo_roots, TRUE)) {
109-
array_unshift($possible_repo_roots, $_SERVER['PWD']);
110-
}
111-
foreach ($possible_repo_roots as $possible_repo_root) {
112-
if ($repo_root = find_directory_containing_files($possible_repo_root, ['docroot/index.php'])) {
113-
return realpath($repo_root);
114-
}
115-
}
39+
$input = new ArgvInput();
40+
if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) {
41+
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
42+
}
11643

117-
return NULL;
44+
if ($input->hasParameterOption('--no-debug', true)) {
45+
putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
11846
}
11947

120-
/**
121-
* Traverses file system upwards in search of a given file.
122-
*
123-
* Begins searching for $file in $working_directory and climbs up directories
124-
* $max_height times, repeating search.
125-
*
126-
* @param string $working_directory
127-
* Working directory.
128-
* @param array $files
129-
* Files.
130-
* @param int $max_height
131-
* Max Height.
132-
*
133-
* @return bool|string
134-
* FALSE if file was not found. Otherwise, the directory path containing the
135-
* file.
136-
*/
137-
function find_directory_containing_files($working_directory, array $files, $max_height = 10) {
138-
// Find the root directory of the git repository containing BLT.
139-
// We traverse the file tree upwards $max_height times until we find
140-
// vendor/bin/blt.
141-
$file_path = $working_directory;
142-
for ($i = 0; $i <= $max_height; $i++) {
143-
if (files_exist($file_path, $files)) {
144-
return $file_path;
145-
}
48+
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
49+
50+
if ($_SERVER['APP_DEBUG']) {
51+
umask(0000);
14652

147-
$file_path = dirname($file_path) . '';
53+
if (class_exists(Debug::class)) {
54+
Debug::enable();
14855
}
56+
}
14957

150-
return FALSE;
58+
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
59+
60+
// Handle a cache:clear pseudo command. This isn't implemented as a true console
61+
// command because a stale or corrupted cache would render it unusable--
62+
// precisely when it is needed.
63+
if (in_array($input->getFirstArgument(), ['cache:clear', 'cc'])) {
64+
$filesystem = new Filesystem();
65+
$cache_dir = $kernel->getCacheDir();
66+
$filesystem->remove($cache_dir);
67+
$filesystem->mkdir($cache_dir);
68+
$filesystem->touch("{$cache_dir}/.gitkeep");
69+
exit;
15170
}
15271

153-
/**
154-
* Determines if an array of files exist in a particular directory.
155-
*
156-
* @param string $dir
157-
* Dir.
158-
* @param array $files
159-
* Files.
160-
*
161-
* @return bool
162-
* Exists.
163-
*/
164-
function files_exist($dir, array $files) {
165-
foreach ($files as $file) {
166-
if (file_exists(Path::join($dir, $file))) {
167-
return TRUE;
168-
}
72+
$kernel->boot();
73+
$container = $kernel->getContainer();
74+
/** @var Application $application */
75+
$application = $container->get(Application::class);
76+
$application->setName('Acquia CLI');
77+
$application->setVersion('@package_version@');
78+
/** @var \Acquia\Cli\Command\Api\ApiCommandHelper $helper */
79+
$helper = $container->get(ApiCommandHelper::class);
80+
$application->addCommands($helper->getApiCommands());
81+
// Clean up exceptions thrown during commands.
82+
$dispatcher = new EventDispatcher();
83+
$dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleErrorEvent $event) {
84+
$exitCode = $event->getExitCode();
85+
$error = $event->getError();
86+
// Make OAuth server errors more human-friendly.
87+
if ($error instanceof IdentityProviderException && $error->getMessage() === 'invalid_client') {
88+
$event->setError(new AcquiaCliException('Your Cloud API credentials are invalid. Run acli auth:login to reset them.', [], $exitCode));
16989
}
90+
});
91+
$application->setDispatcher($dispatcher);
17092

171-
return FALSE;
172-
}
93+
$application->run();

box.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
{
22
"files": ["assets/acquia-spec.yaml"],
3+
"files-bin":[
4+
".env.local.php"
5+
],
6+
"directories":[
7+
"config",
8+
"var"
9+
],
310
"output": "build/acli.phar",
4-
"git-version": "package_version"
11+
"git-version": "package_version",
12+
"exclude-composer-files": false,
13+
"force-autodiscovery": true,
14+
"check-requirements": false
515
}

box.json.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## Box configuration
2+
3+
box.json is largely based on the template provided here: https://github.com/humbug/box/blob/master/fixtures/build/dir012/box.json.dist
4+
5+
This particular configuration is necessary to support Symfony Console. Specifically:
6+
- Must include composer files, since Symfony uses these to determine the root directory
7+
- Must force autodisovery and disable requirements checks, for good (but unknown) reasons
8+
- Must force include of config and var directories
9+
10+
See also: https://github.com/humbug/box/blob/master/doc/symfony.md

composer.json

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@
1919
"padraic/phar-updater": "^1.0",
2020
"psr/log": "^1.1",
2121
"react/event-loop": "^1.1",
22-
"symfony/cache": "^5.0",
23-
"symfony/console": "^5.0",
24-
"symfony/dependency-injection": "^5.0",
25-
"symfony/event-dispatcher": "^5.0",
22+
"symfony/cache": "^5.1",
23+
"symfony/config": "^5.1",
24+
"symfony/console": "^5.1",
25+
"symfony/dependency-injection": "^5.1",
26+
"symfony/dotenv": "^5.1",
27+
"symfony/event-dispatcher": "^5.1",
28+
"symfony/expression-language": "^5.1",
2629
"symfony/filesystem": "^5.1@dev",
27-
"symfony/finder": "^5.0",
28-
"symfony/process": "^5.0",
29-
"symfony/validator": "^5.0",
30+
"symfony/finder": "^5.1",
31+
"symfony/flex": "^1.7",
32+
"symfony/http-kernel": "^5.1",
33+
"symfony/process": "^5.1",
34+
"symfony/validator": "^5.1",
3035
"symfony/yaml": "^5.1@dev",
3136
"typhonius/acquia-logstream": "dev-master",
3237
"typhonius/acquia-php-sdk-v2": "^2.0.8",

0 commit comments

Comments
 (0)