/** * Creates an event loop which takes orders from the parent process and executes * them in runtime mode. * * @return void */ public function handleRequest() { $sequence = $this->bootstrap->buildRuntimeSequence(); $sequence->invoke($this->bootstrap); $objectManager = $this->bootstrap->getObjectManager(); $systemLogger = $objectManager->get(SystemLoggerInterface::class); $systemLogger->log('Running sub process loop.', LOG_DEBUG); echo "\nREADY\n"; try { while (true) { $commandLine = trim(fgets(STDIN)); $trimmedCommandLine = trim($commandLine); $systemLogger->log(sprintf('Received command "%s".', $trimmedCommandLine), LOG_INFO); if ($commandLine === "QUIT\n") { break; } /** @var Request $request */ $request = $objectManager->get(RequestBuilder::class)->build($trimmedCommandLine); $response = new Response(); if ($this->bootstrap->isCompiletimeCommand($request->getCommand()->getCommandIdentifier())) { echo "This command must be executed during compiletime.\n"; } else { $objectManager->get(Dispatcher::class)->dispatch($request, $response); $response->send(); $this->emitDispatchedCommandLineSlaveRequest(); } echo "\nREADY\n"; } $systemLogger->log('Exiting sub process loop.', LOG_DEBUG); $this->bootstrap->shutdown(Bootstrap::RUNLEVEL_RUNTIME); exit($response->getExitCode()); } catch (\Exception $exception) { $this->handleException($exception); } }
/** * Returns an array that contains all available command identifiers and their shortest non-ambiguous alias * * @return array in the format array('full.command:identifier1' => 'alias1', 'full.command:identifier2' => 'alias2') */ protected function getShortCommandIdentifiers() { if ($this->shortCommandIdentifiers === null) { $commandsByCommandName = []; /** @var Command $availableCommand */ foreach ($this->getAvailableCommands() as $availableCommand) { list($packageKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier()); if (!isset($commandsByCommandName[$commandName])) { $commandsByCommandName[$commandName] = []; } if (!isset($commandsByCommandName[$commandName][$controllerName])) { $commandsByCommandName[$commandName][$controllerName] = []; } $commandsByCommandName[$commandName][$controllerName][] = $packageKey; } foreach ($this->getAvailableCommands() as $availableCommand) { list($packageKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier()); if (count($commandsByCommandName[$commandName][$controllerName]) > 1 || $this->bootstrap->isCompiletimeCommand($availableCommand->getCommandIdentifier())) { $packageKeyParts = array_reverse(explode('.', $packageKey)); for ($i = 1; $i <= count($packageKeyParts); $i++) { $shortCommandIdentifier = implode('.', array_slice($packageKeyParts, 0, $i)) . ':' . $controllerName . ':' . $commandName; try { $this->getCommandByIdentifier($shortCommandIdentifier); $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = $shortCommandIdentifier; break; } catch (CommandException $exception) { } } } else { $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s', $controllerName, $commandName); } } } return $this->shortCommandIdentifiers; }
/** * @test * @dataProvider commandIdentifiersAndCompiletimeControllerInfo */ public function isCompileTimeCommandControllerChecksIfTheGivenCommandIdentifierRefersToACompileTimeController($compiletimeCommandControllerIdentifiers, $givenCommandIdentifier, $expectedResult) { $bootstrap = new Bootstrap('Testing'); foreach ($compiletimeCommandControllerIdentifiers as $compiletimeCommandControllerIdentifier) { $bootstrap->registerCompiletimeCommand($compiletimeCommandControllerIdentifier); } $this->assertSame($expectedResult, $bootstrap->isCompiletimeCommand($givenCommandIdentifier)); }
/** * Checks if compile time command was not recognized as such, then runlevel was * booted but it turned out that in fact the command is a compile time command. * * This happens if the user doesn't specify the full command identifier. * * @param string $runlevel * @return void * @throws \TYPO3\Flow\Mvc\Exception\InvalidCommandIdentifierException */ public function exitIfCompiletimeCommandWasNotCalledCorrectly($runlevel) { if ($runlevel === 'Runtime') { $command = $this->request->getCommand(); if ($this->bootstrap->isCompiletimeCommand($command->getCommandIdentifier())) { $this->response->appendContent(sprintf("<b>Unrecognized Command</b>\n\n" . "Sorry, but he command \"%s\" must be specified by its full command\n" . "identifier because it is a compile time command which cannot be resolved\n" . "from an abbreviated command identifier.\n\n", $command->getCommandIdentifier())); $this->response->send(); $this->shutdown($runlevel); exit(1); } } }
/** * Run the interactive Shell * * The shell command runs Flow's interactive shell. This shell allows for * entering commands like through the regular command line interface but * additionally supports autocompletion and a user-based command history. * * @return void */ public function shellCommand() { if (!function_exists('readline_read_history')) { $this->outputLine('Interactive Shell is not available on this system!'); $this->quit(1); } $subProcess = false; $pipes = array(); $historyPathAndFilename = getenv('HOME') . '/.flow_' . md5(FLOW_PATH_ROOT); readline_read_history($historyPathAndFilename); readline_completion_function(array($this, 'autocomplete')); echo "Flow Interactive Shell\n\n"; while (true) { $commandLine = readline('Flow > '); if ($commandLine == '') { echo "\n"; break; } readline_add_history($commandLine); readline_write_history($historyPathAndFilename); $request = $this->requestBuilder->build($commandLine); $response = new Response(); $command = $request->getCommand(); if ($request === false || $command->getCommandIdentifier() === false) { echo "Bad command\n"; continue; } if ($this->bootstrap->isCompiletimeCommand($command->getCommandIdentifier())) { $this->dispatcher->dispatch($request, $response); $response->send(); if (is_resource($subProcess)) { $this->quitSubProcess($subProcess, $pipes); } } else { if (is_resource($subProcess)) { $subProcessStatus = proc_get_status($subProcess); if ($subProcessStatus['running'] === false) { proc_close($subProcess); } } if (!is_resource($subProcess)) { list($subProcess, $pipes) = $this->launchSubProcess(); if ($subProcess === false || !is_array($pipes)) { echo "Failed launching the shell sub process for executing the runtime command.\n"; continue; } $this->echoSubProcessResponse($pipes); } fwrite($pipes[0], $commandLine . "\n"); fflush($pipes[0]); $this->echoSubProcessResponse($pipes); if ($command->isFlushingCaches()) { $this->quitSubProcess($subProcess, $pipes); } } } if (is_resource($subProcess)) { $this->quitSubProcess($subProcess, $pipes); } echo "Bye!\n"; }