22
33namespace T3Docs \GuidesExtension \Command ;
44
5- use phpDocumentor \Guides \Cli \Command \Run ;
6- use Symfony \Component \Console \Application ;
5+ use League \Tactician \CommandBus ;
6+ use Monolog \Handler \ErrorLogHandler ;
7+ use Monolog \Handler \StreamHandler ;
8+ use Monolog \Logger ;
9+ use phpDocumentor \Guides \Cli \Command \ProgressBarSubscriber ;
10+ use phpDocumentor \Guides \Cli \Command \SettingsBuilder ;
11+ use phpDocumentor \Guides \Cli \Internal \RunCommand ;
12+ use phpDocumentor \Guides \Cli \Logger \SpyProcessor ;
13+ use Psr \Log \LogLevel ;
714use Symfony \Component \Console \Command \Command ;
8- use Symfony \Component \Console \Input \ArrayInput ;
915use Symfony \Component \Console \Input \InputArgument ;
10- use Symfony \Component \Console \Input \InputDefinition ;
1116use Symfony \Component \Console \Input \InputInterface ;
1217use Symfony \Component \Console \Input \InputOption ;
18+ use Symfony \Component \Console \Output \ConsoleOutputInterface ;
1319use Symfony \Component \Console \Output \OutputInterface ;
20+ use Symfony \Component \EventDispatcher \EventDispatcher ;
1421use Symfony \Component \Finder \Finder ;
1522use Symfony \Component \Process \Process ;
1623use T3Docs \Typo3DocsTheme \Settings \Typo3DocsInputSettings ;
@@ -36,29 +43,66 @@ final class RunDecorator extends Command
3643 'README.md ' => 'md ' ,
3744 ];
3845
39- private Run $ innerCommand ;
40- public function __construct (Run $ innerCommand , private readonly Typo3DocsInputSettings $ inputSettings )
46+ public function __construct (
47+ private readonly Typo3DocsInputSettings $ inputSettings ,
48+ private readonly SettingsBuilder $ settingsBuilder ,
49+ private readonly CommandBus $ commandBus ,
50+ private readonly EventDispatcher $ eventDispatcher ,
51+ private readonly Logger $ logger ,
52+ private readonly ProgressBarSubscriber $ progressBarSubscriber ,
53+ ) {
54+ parent ::__construct ('run ' );
55+ }
56+
57+ protected function configure (): void
4158 {
42- parent ::__construct ($ innerCommand ->getName ());
43- $ this ->innerCommand = $ innerCommand ;
59+ $ this ->settingsBuilder ->configureCommand ($ this );
60+
61+ $ this ->addOption (
62+ 'log-path ' ,
63+ null ,
64+ InputOption::VALUE_REQUIRED ,
65+ 'Write rendering log to this path ' ,
66+ );
67+ $ this ->addOption (
68+ 'fail-on-log ' ,
69+ null ,
70+ InputOption::VALUE_NONE ,
71+ 'If set, returns a non-zero exit code as soon as any warnings/errors occur ' ,
72+ );
73+
74+ $ this ->addOption (
75+ 'fail-on-error ' ,
76+ null ,
77+ InputOption::VALUE_NONE ,
78+ 'If set, returns a non-zero exit code as soon as any errors occur ' ,
79+ );
4480
45- $ this ->innerCommand ->addOption (
81+ $ this ->addOption (
82+ 'progress ' ,
83+ null ,
84+ InputOption::VALUE_NEGATABLE ,
85+ 'Whether to show a progress bar ' ,
86+ true ,
87+ );
88+
89+ $ this ->addOption (
4690 'localization ' ,
4791 null ,
4892 InputArgument::OPTIONAL ,
4993 'Render a specific localization (for example "de_DE", "ru_RU", ...) ' ,
5094 );
5195
5296 // This option is evaluated in the PostProjectNodeCreated event in packages/typo3-docs-theme/src/EventListeners/AddThemeSettingsToProjectNode.php
53- $ this ->innerCommand -> addOption (
97+ $ this ->addOption (
5498 'minimal-test ' ,
5599 null ,
56100 InputOption::VALUE_NONE ,
57101 'Apply preset for minimal testing (format=singlepage) ' ,
58102 );
59-
60103 }
61104
105+
62106 protected function execute (InputInterface $ input , OutputInterface $ output ): int
63107 {
64108 $ options = [];
@@ -71,25 +115,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int
71115 }
72116
73117 $ arguments = $ input ->getArguments ();
118+ $ guessedInput = [];
74119 if ($ arguments ['input ' ] === null ) {
75120 $ guessedInput = $ this ->guessInput (self ::DEFAULT_INPUT_DIRECTORY , $ output , false );
76- } else {
77- $ guessedInput = [] ;
121+ $ input -> setArgument ( ' input ' , $ guessedInput [ ' input ' ]);
122+ $ input -> setOption ( ' input-format ' , $ guessedInput [ ' --input-format ' ] ?? null ) ;
78123 }
79124
80125 if (!isset ($ options ['--output ' ])) {
81- $ options [ ' -- output '] = getcwd () . '/ ' . self ::DEFAULT_OUTPUT_DIRECTORY ;
126+ $ input -> setOption ( ' output ', getcwd () . '/ ' . self ::DEFAULT_OUTPUT_DIRECTORY ) ;
82127 }
83128
84- $ input = new ArrayInput (
85- [
86- ...$ arguments ,
87- ...$ options ,
88- ...$ guessedInput ,
89- ],
90- $ this ->getDefinition ()
91- );
92-
93129 // Propagate all input settings to be used within events
94130 // through the Typo3DocsInputSettings singleton.
95131 $ this ->inputSettings ->setInput ($ input );
@@ -107,7 +143,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
107143 $ output ->writeln (sprintf ("<info>DEBUG</info> Using parameters: \n%s " , $ readableOutput ));
108144 }
109145
110- $ baseExecution = $ this ->innerCommand -> execute ($ input , $ output );
146+ $ baseExecution = $ this ->internalRun ($ input , $ output );
111147
112148 // When a localization is being rendered, no other sub-localizations
113149 // are allowed, the execution will end here.
@@ -260,48 +296,6 @@ public function retrieveLocalizationArgumentsFromCurrentArguments(InputInterface
260296 return $ shellCommands ;
261297 }
262298
263- public function getDescription (): string
264- {
265- return $ this ->innerCommand ->getDescription ();
266- }
267-
268- public function getHelp (): string
269- {
270- return $ this ->innerCommand ->getHelp ();
271- }
272-
273- public function setApplication (Application $ application = null ): void
274- {
275- parent ::setApplication ($ application );
276- $ this ->innerCommand ->setApplication ($ application );
277- }
278-
279- /** @return mixed[] */
280- public function getUsages (): array
281- {
282- return $ this ->innerCommand ->getUsages ();
283- }
284-
285- public function getNativeDefinition (): InputDefinition
286- {
287- return $ this ->innerCommand ->getNativeDefinition ();
288- }
289-
290- public function getSynopsis (bool $ short = false ): string
291- {
292- return $ this ->innerCommand ->getSynopsis ($ short );
293- }
294-
295- public function getDefinition (): InputDefinition
296- {
297- return $ this ->innerCommand ->getDefinition ();
298- }
299-
300- public function mergeApplicationDefinition (bool $ mergeArgs = true ): void
301- {
302- $ this ->innerCommand ->mergeApplicationDefinition ($ mergeArgs );
303- }
304-
305299 /** @return array<string, string> */
306300 private function guessInput (string $ inputBaseDirectory , OutputInterface $ output , bool $ isAbsoluteDirectory = false ): array
307301 {
@@ -363,4 +357,53 @@ private function guessInput(string $inputBaseDirectory, OutputInterface $output,
363357
364358 return [];
365359 }
360+
361+ private function internalRun (InputInterface $ input , OutputInterface $ output ): int
362+ {
363+ $ this ->settingsBuilder ->overrideWithInput ($ input );
364+ $ projectNode = $ this ->settingsBuilder ->createProjectNode ();
365+ $ settings = $ this ->settingsBuilder ->getSettings ();
366+
367+ $ logPath = $ settings ->getLogPath ();
368+ if ($ logPath === 'php://stder ' ) {
369+ $ this ->logger ->setHandlers ([new ErrorLogHandler (ErrorLogHandler::OPERATING_SYSTEM , Logger::WARNING )]);
370+ } else {
371+ $ this ->logger ->setHandlers ([new StreamHandler ($ logPath . '/warning.log ' , Logger::WARNING ), new StreamHandler ($ logPath . '/error.log ' , Logger::ERROR )]);
372+ }
373+
374+ if ($ settings ->isFailOnError ()) {
375+ $ spyProcessor = new SpyProcessor ($ settings ->getFailOnError () ?? LogLevel::WARNING );
376+ $ this ->logger ->pushProcessor ($ spyProcessor );
377+ }
378+
379+ if ($ output instanceof ConsoleOutputInterface && $ settings ->isShowProgressBar ()) {
380+ $ this ->progressBarSubscriber ->subscribe ($ output , $ this ->eventDispatcher );
381+ }
382+
383+ $ documents = $ this ->commandBus ->handle (
384+ new RunCommand ($ settings , $ projectNode , $ input ),
385+ );
386+
387+ $ outputFormats = $ settings ->getOutputFormats ();
388+ $ outputDir = $ settings ->getOutput ();
389+ if ($ output ->isQuiet () === false ) {
390+ $ lastFormat = '' ;
391+
392+ if (count ($ outputFormats ) > 1 ) {
393+ $ lastFormat = (count ($ outputFormats ) > 2 ? ', ' : '' ) . ' and ' . strtoupper ((string ) array_pop ($ outputFormats ));
394+ }
395+
396+ $ formatsText = strtoupper (implode (', ' , $ outputFormats )) . $ lastFormat ;
397+
398+ $ output ->writeln (
399+ 'Successfully placed ' . (is_countable ($ documents ) ? count ($ documents ) : 0 ) . ' rendered ' . $ formatsText . ' files into ' . $ outputDir ,
400+ );
401+ }
402+
403+ if ($ settings ->isFailOnError () && $ spyProcessor ->hasBeenCalled ()) {
404+ return Command::FAILURE ;
405+ }
406+
407+ return Command::SUCCESS ;
408+ }
366409}
0 commit comments