From c254e29cca754c5e877ab8dd1e275221f767d6d6 Mon Sep 17 00:00:00 2001 From: Richard Dern Date: Mon, 6 May 2024 21:20:43 +0200 Subject: [PATCH] Refactoring --- app/Console/Commands/Bundle/Render.php | 236 +++++++++++++++++++++---- 1 file changed, 200 insertions(+), 36 deletions(-) diff --git a/app/Console/Commands/Bundle/Render.php b/app/Console/Commands/Bundle/Render.php index 4768daa..e12d862 100644 --- a/app/Console/Commands/Bundle/Render.php +++ b/app/Console/Commands/Bundle/Render.php @@ -4,6 +4,7 @@ use App\Classes\Bundle; use Illuminate\Console\Command; +use Illuminate\Contracts\Filesystem\Filesystem; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; @@ -13,13 +14,6 @@ class Render extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'bundle:render { --a|assets : Rebuild assets }'; - /** * The console command description. * @@ -27,49 +21,219 @@ class Render extends Command */ protected $description = 'Render bundles'; + protected Filesystem $sourceDisk; + + protected Filesystem $targetDisk; + + public function __construct() + { + $this->signature = 'bundle:render + { --a|assets : Rebuild assets - implies -c } + { --c|clear-cache : Clear cache before rendering } + { --d|dry-run : Show what would be done but do nothing } + { --no-deploy : Do not deploy, do not ask to deploy } + { --r|recursive : Also render sub-bundles } + { --source-disk= : Use specified content disk - Defaults to ' . env('CONTENT_DISK') . ' } + { --target-disk= : Use specified rendering disk - Defaults to ' . env('DIST_DISK') . ' } + { path? : Path to a specific bundle to render - Default to / } + '; + + parent::__construct(); + } + /** * Execute the console command. */ public function handle() { - if ($this->option('assets')) { - $this->output->write('Building assets... '); - Process::run('npm run build')->throw(); - $this->info('OK'); + $this->showDisclaimer() + ->selectDisk() + ->renderAssets() + ->clearCache() + ->render() + ->deploy(); + } - $this->call('cache:clear'); + /** + * Show a "disclaimer" for running dry-mode + */ + private function showDisclaimer(): self + { + if (!$this->option('dry-run')) { + return $this; } - $path = '/'; - $bundles = Bundle::findBundles(Storage::disk(env('CONTENT_DISK')), $path, true); - $progress = progress(label: 'Rendering... ', steps: count($bundles)); - $progress->start(); + $this->newLine(); + $this->warn('Running dry-mode: no modification will be done'); + $this->newLine(); - foreach ($bundles as $bundle) { - $result = $bundle->render(); + return $this; + } - foreach ($result as $path => $content) { - if (!Str::contains($path, '.')) { - $path = Str::finish($path, '/') . 'index.html'; - } + /** + * Select the disk we will be working on + */ + private function selectDisk(): self + { + $sourceDisk = $this->option('source-disk') ?? env('CONTENT_DISK'); + $targetDisk = $this->option('target-disk') ?? env('DIST_DISK'); - Storage::disk(env('DIST_DISK'))->put($path, $content); + $this->sourceDisk = Storage::disk($sourceDisk); + $this->targetDisk = Storage::disk($targetDisk); + + $this->comment( + sprintf( + 'Using `%s` as source disk and `%s` as target disk for generated content', + $sourceDisk, + $targetDisk + ) + ); + + return $this; + } + + /** + * Build assets, and clear cache afterwise + */ + private function renderAssets(): self + { + // Do not re-generate assets if we didn't explicitely asked for it + if (!$this->option('assets')) { + return $this; + } + + $this->output->write('Building assets... '); + + if (!$this->option('dry-run')) { + Process::run('npm run build')->throw(); + } + + $this->info('OK'); + + return $this; + } + + /** + * Clear application cache + */ + private function clearCache(): self + { + // Do not clear cache if we didn't explicitely asked for it + if (!$this->option('clear-cache') && !$this->option('assets')) { + return $this; + } + + // For now, we need to clear the cache, otherwise rendered HTML will + // still reference old assets + $this->output->write('Clearing cache... '); + + if (!$this->option('dry-run')) { + $this->call('cache:clear', ['--quiet']); + } + + $this->info('OK'); + + return $this; + } + + /** + * Collect a list of bundles to render + */ + private function getBundles() + { + $path = $this->argument('path') ?? '/'; + $comment = sprintf('Rendering %s', $path); + + if ($this->option('recursive')) { + $comment .= ' and all sub-bundles'; + } + + $this->comment($comment); + $this->output->write('Collecting bundles... '); + + if ($this->option('recursive')) { + $bundles = Bundle::findBundles($this->sourceDisk, $path, true); + } else { + $bundles = [new Bundle($path, $this->sourceDisk)]; + } + + $this->info('OK'); + + return $bundles; + } + + /** + * Perform rendering + */ + private function render(): self + { + $bundles = $this->getBundles(); + + progress( + label: 'Rendering... ', + steps: $bundles, + callback: fn (Bundle $bundle, $progress) => $this->handleBundle($bundle, $progress) + ); + + return $this; + } + + /** + * Handle specific bundle + */ + private function handleBundle(Bundle $bundle, $progress) + { + $progress->label(sprintf('Rendering %s ...', $bundle->getPath())); + + if ($this->option('dry-run')) { + return; + } + + $progress->hint('Rendering the bundle'); + + $result = $bundle->render(); + + foreach ($result as $path => $content) { + if (!Str::contains($path, '.')) { + $path = Str::finish($path, '/') . 'index.html'; } - $progress->advance(); - } + $progress->hint(sprintf('Storing %s', $path)); - $progress->finish(); - - if (confirm('Ready to deploy?')) { - $this->output->write('Deploying... '); - $source = Str::finish(Storage::disk(env('DIST_DISK'))->path('/'), '/'); - $target = env('DEPLOY_TARGET'); - - $command = sprintf('rsync -az -L --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --chown=caddy:caddy --delete "%s" "%s"', $source, $target); - - Process::run($command)->throw(); - $this->info('OK'); + $this->targetDisk->put($path, $content); } } + + /** + * Deploy to remote server + */ + private function deploy() + { + // Do not even ask if --no-deploy was used + if ($this->option('no-deploy')) { + return; + } + + // Ask for confirmation + if (!confirm('Ready to deploy?')) { + $this->comment('OK, not deploying!'); + + return; + } + + $source = Str::finish($this->targetDisk->path('/'), '/'); + $target = env('DEPLOY_TARGET'); + $command = __(env('DEPLOY_COMMAND'), [ + 'source' => $source, + 'target' => $target, + ]); + + $this->output->write(sprintf('Deploying using `%s` ... ', $command)); + + if (!$this->option('dry-run')) { + Process::run($command)->throw(); + } + + $this->info('OK'); + } }