Skip to content

Commit 89d2894

Browse files
authored
Merge pull request #1 from webteractive/feature-move-dev-commands-to-the-devstack-command
Feature move dev commands to the devstack command
2 parents 4ed9879 + 146f0ca commit 89d2894

21 files changed

Lines changed: 509 additions & 29 deletions

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"illuminate/support": "^10.3",
2121
"league/flysystem": "^3.0",
2222
"symfony/console": "^6.2",
23-
"symfony/finder": "^6.2"
23+
"symfony/finder": "^6.2",
24+
"symfony/process": "^6.2",
25+
"vlucas/phpdotenv": "^5.5"
2426
},
2527
"require-dev": {
2628
"mockery/mockery": "^1.5.1",

devstack

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,30 @@ if (file_exists($autoload = __DIR__ . '/vendor/autoload.php')) {
77
require dirname(__DIR__, 2) . '/autoload.php';
88
}
99

10-
use Symfony\Component\Console\Application;
10+
use Webteractive\Devstack\App;
11+
use Webteractive\Devstack\Commands\MySql;
12+
use Webteractive\Devstack\Commands\Redis;
13+
use Webteractive\Devstack\Commands\Shell;
1114
use Webteractive\Devstack\Commands\Config;
12-
use Webteractive\Devstack\Commands\DownloadRuntimes;
1315
use Webteractive\Devstack\Commands\InitStack;
16+
use Webteractive\Devstack\Commands\RunPHPCommand;
17+
use Webteractive\Devstack\Commands\DownloadRuntimes;
18+
use Webteractive\Devstack\Commands\RunComposerCommands;
19+
use Webteractive\Devstack\RegisterDockerComposeCommands;
20+
use Webteractive\Devstack\Commands\RunLaravelArtisanCommand;
21+
22+
$app = new App('Devstack', '1.1.5');
1423

15-
$app = new Application;
1624
$app->add(new InitStack);
1725
$app->add(new Config);
1826
$app->add(new DownloadRuntimes);
27+
$app->add(new RunLaravelArtisanCommand);
28+
$app->add(new RunPHPCommand);
29+
$app->add(new RunComposerCommands);
30+
$app->add(new Shell);
31+
$app->add(new MySql);
32+
$app->add(new Redis);
33+
34+
RegisterDockerComposeCommands::register($app);
35+
1936
$app->run();

src/App.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Webteractive\Devstack;
4+
5+
use Symfony\Component\Console\Application;
6+
7+
class App extends Application
8+
{
9+
private static $name = "MyApp";
10+
private static $logo = <<<LOGO
11+
DDDDDDDDDDDDD tttt kkkkkkkk
12+
D::::::::::::DDD ttt:::t k::::::k
13+
D:::::::::::::::DD t:::::t k::::::k
14+
DDD:::::DDDDD:::::D t:::::t k::::::k
15+
D:::::D D:::::D eeeeeeeeeeee vvvvvvv vvvvvvv ssssssssss ttttttt:::::ttttttt aaaaaaaaaaaaa cccccccccccccccc k:::::k kkkkkkk
16+
D:::::D D:::::D ee::::::::::::ee v:::::v v:::::v ss::::::::::s t:::::::::::::::::t a::::::::::::a cc:::::::::::::::c k:::::k k:::::k
17+
D:::::D D:::::D e::::::eeeee:::::eev:::::v v:::::vss:::::::::::::s t:::::::::::::::::t aaaaaaaaa:::::a c:::::::::::::::::c k:::::k k:::::k
18+
D:::::D D:::::De::::::e e:::::e v:::::v v:::::v s::::::ssss:::::stttttt:::::::tttttt a::::ac:::::::cccccc:::::c k:::::k k:::::k
19+
D:::::D D:::::De:::::::eeeee::::::e v:::::v v:::::v s:::::s ssssss t:::::t aaaaaaa:::::ac::::::c ccccccc k::::::k:::::k
20+
D:::::D D:::::De:::::::::::::::::e v:::::v v:::::v s::::::s t:::::t aa::::::::::::ac:::::c k:::::::::::k
21+
D:::::D D:::::De::::::eeeeeeeeeee v:::::v:::::v s::::::s t:::::t a::::aaaa::::::ac:::::c k:::::::::::k
22+
D:::::D D:::::D e:::::::e v:::::::::v ssssss s:::::s t:::::t tttttta::::a a:::::ac::::::c ccccccc k::::::k:::::k
23+
DDD:::::DDDDD:::::D e::::::::e v:::::::v s:::::ssss::::::s t::::::tttt:::::ta::::a a:::::ac:::::::cccccc:::::ck::::::k k:::::k
24+
D:::::::::::::::DD e::::::::eeeeeeee v:::::v s::::::::::::::s tt::::::::::::::ta:::::aaaa::::::a c:::::::::::::::::ck::::::k k:::::k
25+
D::::::::::::DDD ee:::::::::::::e v:::v s:::::::::::ss tt:::::::::::tt a::::::::::aa:::a cc:::::::::::::::ck::::::k k:::::k
26+
DDDDDDDDDDDDD eeeeeeeeeeeeee vvv sssssssssss ttttttttttt aaaaaaaaaa aaaa cccccccccccccccckkkkkkkk kkkkkkk
27+
LOGO;
28+
29+
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
30+
{
31+
$this->setName(static::$name);
32+
$this->setVersion($version);
33+
parent::__construct($name, $version);
34+
}
35+
36+
/**
37+
* @return string
38+
*/
39+
public function getHelp(): string
40+
{
41+
return static::$logo . "\n\n" . parent::getHelp();
42+
}
43+
}

src/CommandSignature.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use Illuminate\Support\Str;
66
use InvalidArgumentException;
7-
use Symfony\Component\Console\Input\InputArgument;
87
use Symfony\Component\Console\Input\InputOption;
8+
use Symfony\Component\Console\Input\InputArgument;
99

1010
class CommandSignature
1111
{

src/Commands/Base.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
namespace Webteractive\Devstack\Commands;
44

5+
use Webteractive\Devstack\CommandSignature;
56
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Question\Question;
68
use Symfony\Component\Console\Input\InputInterface;
79
use Symfony\Component\Console\Output\OutputInterface;
8-
use Symfony\Component\Console\Question\Question;
9-
use Webteractive\Devstack\CommandSignature;
1010

1111
abstract class Base extends Command
1212
{
13+
protected $fullCommandSignature;
14+
1315
protected $name;
1416

1517
protected $signature;
@@ -20,12 +22,12 @@ abstract class Base extends Command
2022

2123
protected $hidden = false;
2224

23-
protected $input;
25+
protected InputInterface $input;
2426

25-
protected $output;
27+
protected OutputInterface $output;
2628

2729
public function __construct()
28-
{
30+
{
2931
if (isset($this->signature)) {
3032
$this->setup();
3133
} else {
@@ -43,20 +45,32 @@ public function setup()
4345
{
4446
[$name, $arguments, $options] = CommandSignature::parse($this->signature);
4547

48+
49+
if ($this->shouldIgnoreValidationErrors()) {
50+
$this->ignoreValidationErrors();
51+
}
52+
4653
parent::__construct($name);
4754

4855
$this->getDefinition()->addArguments($arguments);
4956
$this->getDefinition()->addOptions($options);
5057
}
5158

59+
public function shouldIgnoreValidationErrors(): bool
60+
{
61+
return false;
62+
}
63+
5264
protected function execute(InputInterface $input, OutputInterface $output)
5365
{
5466
return $this->setIO($input, $output)
5567
->handle();
5668
}
5769

58-
public function setIO($input, $output)
70+
public function setIO(InputInterface $input, OutputInterface $output)
5971
{
72+
global $argv;
73+
$this->fullCommandSignature = array_slice($argv, 2);
6074
$this->input = $input;
6175
$this->output = $output;
6276
return $this;
@@ -115,6 +129,11 @@ public function line($message = '')
115129
return $this;
116130
}
117131

132+
public function lineBreak()
133+
{
134+
return $this->line('');
135+
}
136+
118137
public function info($message = '')
119138
{
120139
$this->output->writeln(empty($message) ? '' : "<info>{$message}</info>");

src/Commands/Config.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22

33
namespace Webteractive\Devstack\Commands;
44

5-
use Symfony\Component\Console\Attribute\AsCommand;
6-
use Symfony\Component\Console\Command\Command;
7-
use Symfony\Component\Console\Input\InputArgument;
8-
use Symfony\Component\Console\Input\InputInterface;
9-
use Symfony\Component\Console\Output\OutputInterface;
105
use Webteractive\Devstack\ShouldConfigure;
11-
use Webteractive\Devstack\WithStorage;
126

137
class Config extends Base
148
{

src/Commands/DownloadRuntimes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace Webteractive\Devstack\Commands;
44

5-
use Webteractive\Devstack\RuntimeDownloader;
65
use Webteractive\Devstack\ShouldConfigure;
6+
use Webteractive\Devstack\RuntimeDownloader;
77

88
class DownloadRuntimes extends Base
99
{

src/Commands/InitStack.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace Webteractive\Devstack\Commands;
44

5-
use Webteractive\Devstack\RuntimeDownloader;
65
use Webteractive\Devstack\File;
7-
use Webteractive\Devstack\PublicRuntimeDownloader;
86
use Webteractive\Devstack\ShouldConfigure;
7+
use Webteractive\Devstack\RuntimeDownloader;
8+
use Webteractive\Devstack\PublicRuntimeDownloader;
99

1010
class InitStack extends Base
1111
{

src/Commands/MySql.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
namespace Webteractive\Devstack\Commands;
4+
5+
use Webteractive\Devstack\Env;
6+
use Webteractive\Devstack\Process;
7+
use Webteractive\Devstack\WithSignalHandlers;
8+
9+
class MySql extends Base
10+
{
11+
use WithSignalHandlers;
12+
13+
protected $signature = 'mysql
14+
{--p|password= : The password to use.}
15+
{--u|user= : The user to use.}
16+
{--db|database= : The database to use.}
17+
{--env= : The path to the .env file. Default\'s to the current working directory.}';
18+
protected $description = 'Start a MySQL CLI session within the <comment>mysql</comment> container.';
19+
20+
public function handle(): int
21+
{
22+
$defaults = [
23+
'password' => 'password',
24+
'user' => 'user',
25+
'database' => null,
26+
];
27+
$envPath = $this->input->getOption('env') ?? getcwd();
28+
if (file_exists($envPath . '/.env')) {
29+
$env = new Env($envPath);
30+
$defaults['password'] = $env->get('DB_PASSWORD');
31+
$defaults['user'] = $env->get('DB_USERNAME');
32+
$defaults['database'] = $env->get('DB_DATABASE');
33+
$this->lineBreak();
34+
$this->line('Found an <comment>.env</comment> file in your current working directory, values will now be used as defaults.');
35+
$this->lineBreak();
36+
} else {
37+
$this->lineBreak();
38+
$this->line('Unable to find an <comment>.env</comment> file in your current working directory, now using the defaults.');
39+
$this->line('If these were changed in your <comment>docker-compose.yml</comment> file, please supply it as a command');
40+
$this->line('flag or add an <comment>.env</comment> file and add it there.');
41+
42+
$this->lineBreak();
43+
$this->line('If you want to use the .env route, create a .env file and add the variables below including the values:');
44+
$this->line('DB_USERNAME=');
45+
$this->line('DB_PASSWORD=');
46+
$this->line('DB_DATABASE=');
47+
$this->lineBreak();
48+
$this->line('If your .env is located somewhere else, you may use the <comment>--env=/path/to/your/.env</comment> flag.');
49+
$this->line('For example, <comment>devstack mysql --env=/path/to/your/.env/directory</comment>.');
50+
$this->lineBreak();
51+
$this->line('Finally for the command flag, just do <comment>devstack mysql --user=the_user --password=the_password --database=the_db</comment>.');
52+
$this->line('For more details on the <comment>devsack mysql</comment> command flags, run <comment>devstack help mysql</comment>.');
53+
$this->lineBreak();
54+
}
55+
56+
57+
$password = $this->input->getOption('password') ?? $defaults['password'];
58+
$user = $this->input->getOption('user') ?? $defaults['user'];
59+
$database = $this->input->getOption('database') ?? $defaults['database'];
60+
61+
$bashCommand = [];
62+
$bashCommand[] = "MYSQL_PWD={$password}";
63+
$bashCommand[] = "mysql -u {$user}";
64+
if ($database) {
65+
$bashCommand[] = $database;
66+
}
67+
68+
$this->handleTerminationSignals(
69+
$process = Process::prepareFromShell('docker compose exec -it mysql bash -c "' . join(' ', $bashCommand) . '"')
70+
);
71+
72+
$process->setTty(true)
73+
->setTimeout(60 * 60 * 2)
74+
->setIdleTimeout(60 * 60 * 8)
75+
->run();
76+
77+
return static::SUCCESS;
78+
}
79+
}

src/Commands/Redis.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Webteractive\Devstack\Commands;
4+
5+
use Webteractive\Devstack\Process;
6+
use Webteractive\Devstack\WithSignalHandlers;
7+
8+
class Redis extends Base
9+
{
10+
use WithSignalHandlers;
11+
12+
protected $signature = 'redis';
13+
protected $description = 'Start a Redis CLI session within the <comment>redis</comment> container.';
14+
15+
public function handle(): int
16+
{
17+
18+
$this->handleTerminationSignals(
19+
$process = Process::prepareFromShell('docker compose exec -it redis redis-cli')
20+
);
21+
22+
$process->setTty(true)
23+
->setTimeout(60 * 60 * 2)
24+
->setIdleTimeout(60 * 60 * 8)
25+
->run();
26+
27+
return static::SUCCESS;
28+
}
29+
}

0 commit comments

Comments
 (0)