|
4 | 4 |
|
5 | 5 | namespace Leaf\Console; |
6 | 6 |
|
7 | | -use Symfony\Component\Console\Command\Command; |
8 | | -use Symfony\Component\Console\Input\InputArgument; |
9 | | -use Symfony\Component\Console\Input\InputOption; |
10 | | -use Symfony\Component\Console\Input\InputInterface; |
11 | | -use Symfony\Component\Console\Output\OutputInterface; |
12 | | -use Symfony\Component\Console\Question\ConfirmationQuestion; |
13 | | -use Symfony\Component\Process\Process; |
| 7 | +use Leaf\Sprout\Command; |
14 | 8 |
|
15 | 9 | class ServeCommand extends Command |
16 | 10 | { |
17 | | - protected static $defaultName = 'serve'; |
| 11 | + protected $signature = 'serve |
| 12 | + {filename? : The PHP script to run} |
| 13 | + {--p|port=5500 : Port to run app on} |
| 14 | + {--nc|no-concurrent : Run PHP server without Vite server}'; |
18 | 15 |
|
19 | | - protected function configure() |
20 | | - { |
21 | | - $this |
22 | | - ->setHelp('Start the leaf app server') |
23 | | - ->setDescription('Run your Leaf app') |
24 | | - ->addArgument('filename', InputArgument::OPTIONAL, 'The PHP script to run') |
25 | | - ->addOption('port', 'p', InputOption::VALUE_OPTIONAL, 'Port to run app on') |
26 | | - ->addOption('watch', 'w', InputOption::VALUE_NONE, 'Run your leaf app with hot reloading [experimental]') |
27 | | - // ->addOption('path', 't', InputOption::VALUE_OPTIONAL, 'Path to your app', getcwd() . '/public') |
28 | | - // ->addOption('host', 's', InputOption::VALUE_OPTIONAL, 'Your application host', 'localhost') |
29 | | - ->addOption('no-concurrent', 'nc', InputOption::VALUE_OPTIONAL, 'Run PHP server without Vite server', false); |
30 | | - } |
| 16 | + protected $description = 'Run a server to serve your Leaf app'; |
31 | 17 |
|
32 | | - protected function execute(InputInterface $input, OutputInterface $output): int |
| 18 | + protected function handle(): int |
33 | 19 | { |
34 | 20 | if ($this->isMVCApp()) { |
35 | | - return (int) Utils\Core::run("php leaf serve --ansi", $output); |
36 | | - } |
37 | | - |
38 | | - $vendorPath = getcwd() . '/vendor'; |
39 | | - $composerJsonPath = getcwd() . '/composer.json'; |
40 | | - |
41 | | - if (!is_dir($vendorPath) && file_exists($composerJsonPath)) { |
42 | | - $output->writeln('<info>Installing dependencies...</info>'); |
43 | | - $leaf = Utils\Core::findLeaf(); |
44 | | - $installProcess = Process::fromShellCommandline("$leaf install"); |
45 | | - |
46 | | - $installProcess->run(function ($type, $line) use ($output) { |
47 | | - $output->write($line); |
48 | | - }); |
49 | | - |
50 | | - if (!$installProcess->isSuccessful()) { |
51 | | - $output->writeln('<error>Failed to install dependencies</error>'); |
52 | | - } |
| 21 | + return (int) sprout()->run("php leaf serve --ansi"); |
53 | 22 | } |
54 | 23 |
|
55 | | - if ($input->getArgument('filename')) { |
56 | | - $input->setOption('watch', true); |
| 24 | + if (!sprout()->composer()->json()) { |
| 25 | + $this->writeln('<error>No composer.json found in the current directory.</error>'); |
| 26 | + return 1; |
57 | 27 | } |
58 | 28 |
|
59 | | - if ($input->getOption('watch')) { |
60 | | - $leafWatcherInstalled = Utils\Core::commandExists('leaf-watcher'); |
61 | | - $node = Utils\Core::findNodeJS(); |
62 | | - $npm = Utils\Core::findNpm(); |
63 | | - $watcher = Utils\Core::findWatcher(); |
64 | | - $leaf = Utils\Core::findLeaf(); |
| 29 | + if (!sprout()->composer()->hasDependencies()) { |
| 30 | + $this->writeln('<info>Installing dependencies...</info>'); |
65 | 31 |
|
66 | | - if (!$node || !$npm) { |
67 | | - $output->writeln('<error>Can\'t find NodeJS on the system. Watching will be disabled.</error>'); |
68 | | - |
69 | | - return $this->startServer($input, $output); |
| 32 | + if (!sprout()->composer()->install()->isSuccessful()) { |
| 33 | + $this->writeln('<error>❌ Failed to install dependencies.</error>'); |
| 34 | + return 1; |
70 | 35 | } |
71 | | - |
72 | | - if (!$leafWatcherInstalled) { |
73 | | - $installWatcher = $this->askToInstallWatcher($input, $output); |
74 | | - |
75 | | - if (!$installWatcher && !file_exists($watcher)) { |
76 | | - $output->writeln('<error>Watcher install cancelled. Watching will be disabled.</error>'); |
77 | | - |
78 | | - return $this->startServer($input, $output); |
79 | | - } |
80 | | - |
81 | | - $output->writeln('<info>Installing leaf watcher...</info>'); |
82 | | - $installProcess = Process::fromShellCommandline("$npm install -g @leafphp/watcher"); |
83 | | - |
84 | | - $installProcess->run(function ($type, $line) use ($output) { |
85 | | - $output->write($line); |
86 | | - }); |
87 | | - |
88 | | - if (!$installProcess->isSuccessful()) { |
89 | | - $output->writeln('<error>Failed to install leaf watcher. Watching will be disabled.</error>'); |
90 | | - |
91 | | - return $this->startServer($input, $output); |
92 | | - } |
93 | | - } |
94 | | - |
95 | | - $port = $input->getOption('port') ? (int) $input->getOption('port') : 5500; |
96 | | - $process = Process::fromShellCommandline("$watcher --exec $leaf serve --port $port", null, null, null, null); |
97 | | - |
98 | | - if ($input->getArgument('filename')) { |
99 | | - $filename = $input->getArgument('filename'); |
100 | | - $process = Process::fromShellCommandline("$watcher --exec " . PHP_BINARY . " $filename", null, null, null, null); |
101 | | - } |
102 | | - |
103 | | - return $process->run(function ($type, $line) use ($output) { |
104 | | - $output->write($line); |
105 | | - }); |
106 | | - } |
107 | | - |
108 | | - return $this->startServer($input, $output); |
109 | | - } |
110 | | - |
111 | | - protected function askToInstallWatcher($input, $output) |
112 | | - { |
113 | | - $helper = $this->getHelper('question'); |
114 | | - $question = new ConfirmationQuestion('<info>* Leaf Watcher is required to enable monitoring. Install package?</info> ', true); |
115 | | - |
116 | | - return $helper->ask($input, $output, $question); |
117 | | - } |
118 | | - |
119 | | - protected function startServer(InputInterface $input, OutputInterface $output): int |
120 | | - { |
121 | | - $useConcurrent = true; |
122 | | - |
123 | | - $noConcurrent = $input->getOption('no-concurrent'); |
124 | | - $port = (int) ($input->getOption('port') ?? 5500); |
125 | | - |
126 | | - if ($noConcurrent || !file_exists(getcwd() . '/vite.config.js')) { |
127 | | - $useConcurrent = false; |
128 | 36 | } |
129 | 37 |
|
130 | | - $serveCommand = !$useConcurrent ? "php -S localhost:$port" : "npx concurrently -c \"#3eaf7c,#bd34fe\" \"php -S localhost:$port\" \"npm run dev\" --names=server,vite --colors"; |
131 | | - |
| 38 | + $port = $this->option('port'); |
132 | 39 | $isDockerProject = file_exists(getcwd() . '/docker-compose.yml'); |
133 | | - $process = Process::fromShellCommandline( |
134 | | - $isDockerProject ? 'docker compose up' : $serveCommand, |
135 | | - null, |
136 | | - null, |
137 | | - null, |
138 | | - null |
139 | | - ); |
140 | | - |
141 | | - $output->writeln( |
142 | | - $isDockerProject ? |
143 | | - '<info>Serving Leaf application using Docker Compose...</info>' : |
144 | | - "<info>Starting Leaf development server on <href=http://localhost:$port>http://localhost:$port</></info>" |
145 | | - ); |
| 40 | + $useConcurrent = !$this->option('no-concurrent') && file_exists(getcwd() . '/vite.config.js'); |
| 41 | + $serveCommand = !$useConcurrent ? "php -S localhost:$port" : "npx concurrently -c \"#3eaf7c,#bd34fe\" \"php -S localhost:$port\" \"npm run dev\" --names=server,vite --colors"; |
146 | 42 |
|
147 | | - return $process->run(function ($type, $line) use ($output, $process) { |
148 | | - if (is_string($line) && !strpos($line, 'Failed')) { |
149 | | - $output->write($line); |
150 | | - } else { |
151 | | - $output->write("<error>$line</error>"); |
152 | | - } |
153 | | - }); |
| 43 | + return sprout()->process( |
| 44 | + $isDockerProject ? 'docker compose up' : $serveCommand |
| 45 | + )->run(); |
154 | 46 | } |
155 | 47 |
|
156 | 48 | protected function isMVCApp() |
|
0 commit comments