signature = 'bundle:render { --a|assets : Rebuild assets - implies -c } { --clean-target : Remove all files and directories before rendering (excluding assets and storage) } { --c|clear-cache : Clear cache before rendering } { --deploy : Deploy without asking } { --describe : Ask for missing descriptions } { --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') . ' } { --validate : Perform validations before rendering } { path? : Path to a specific bundle to render - Default to / } '; parent::__construct(); } /** * Execute the console command. */ public function handle() { $this->showDisclaimer() ->selectDisk(true, true) ->cleanTarget() ->renderAssets() ->clearCache() ->validate() ->renderFeed() ->selectBundles() ->render() ->deploy(); } /** * Show a "disclaimer" for running dry-mode */ private function showDisclaimer(): self { if (!$this->option('dry-run')) { return $this; } $this->newLine(); $this->warn('Running dry-mode: no modification will be done'); $this->newLine(); return $this; } /** * Remove previously rendered files before rendering new files */ private function cleanTarget(): self { if (!$this->option('clean-target')) { return $this; } $this->output->write('Cleaning target... '); $list = $this->targetDisk->listContents($this->argument('path') ?? '/')->toArray(); if (!$this->option('dry-run')) { foreach ($list as $attrs) { if ($attrs->isFile()) { $this->targetDisk->delete($attrs->path()); } else { $this->targetDisk->deleteDirectory($attrs->path()); } } } $this->info('OK'); 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->callSilently('cache:clear'); $this->callSilently('view:clear'); } $this->info('OK'); return $this; } /** * Validate bundles before rendering */ private function validate(): self { if (!$this->option('validate')) { return $this; } $options = [ '--recursive' => $this->option('recursive'), '--source-disk' => $this->option('source-disk'), 'path' => $this->argument('path') ?? '/', ]; if (!$this->option('dry-run')) { $result = $this->call('bundle:validate', $options); } if (!empty($result)) { if (confirm('Validation errors have occurred. Cancel process?')) { exit(1); } } return $this; } /** * Render feed */ private function renderFeed(): self { if ($this->option('dry-run')) { return $this; } $result = Bundle::renderFeed($this->sourceDisk); foreach ($result as $path => $content) { $this->output->write(sprintf('Rendering %s as feed... ', $path)); if ($this->targetDisk->exists($path)) { $fileChecksum = $this->targetDisk->checksum($path); $contentChecksum = md5($content); if ($fileChecksum === $contentChecksum) { $this->info('Not changed'); continue; } } $this->targetDisk->put($path, $content); //TODO: Find the right way to check for feed's validity... Cache::forever('feed_is_valid', true); $this->info('OK'); } return $this; } /** * Perform rendering */ private function render(): self { $bundles = $this->bundles; 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; } $result = $bundle->render(); foreach ($result as $path => $content) { if (!Str::contains($path, '.')) { $path = Str::finish($path, '/') . 'index.html'; } if ($this->targetDisk->exists($path)) { $fileChecksum = $this->targetDisk->checksum($path); $contentChecksum = md5($content); if ($fileChecksum === $contentChecksum) { continue; } } $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; } if (!$this->option('deploy')) { // 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'); } }