/** * 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('TYPO3\\FLOW3\\Log\\SystemLoggerInterface'); $systemLogger->log('Running sub process loop.', LOG_DEBUG); echo "\nREADY\n"; try { while (TRUE) { $commandLine = trim(fgets(STDIN)); $systemLogger->log(sprintf('Received command "%s".', $commandLine), LOG_INFO); if ($commandLine === "QUIT\n") { break; } $request = $objectManager->get('TYPO3\\FLOW3\\Cli\\RequestBuilder')->build($commandLine); $response = new \TYPO3\FLOW3\Cli\Response(); if ($this->bootstrap->isCompiletimeCommand($request->getCommand()->getCommandIdentifier())) { echo "This command must be executed during compiletime.\n"; } else { $objectManager->get('TYPO3\\FLOW3\\Mvc\\Dispatcher')->dispatch($request, $response); $response->send(); $this->emitDispatchedCommandLineSlaveRequest(); } echo "\nREADY\n"; } $systemLogger->log('Exiting sub process loop.', LOG_DEBUG); $this->bootstrap->shutdown('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 = array(); foreach ($this->getAvailableCommands() as $availableCommand) { list($packageKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier()); if (!isset($commandsByCommandName[$commandName])) { $commandsByCommandName[$commandName] = array(); } if (!isset($commandsByCommandName[$commandName][$controllerName])) { $commandsByCommandName[$commandName][$controllerName] = array(); } $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 (\TYPO3\FLOW3\Mvc\Exception\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\FLOW3\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 FLOW3'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') . '/.flow3_' . md5(FLOW3_PATH_ROOT); readline_read_history($historyPathAndFilename); readline_completion_function(array($this, 'autocomplete')); echo "FLOW3 Interactive Shell\n\n"; while (true) { $commandLine = readline('FLOW3 > '); if ($commandLine == '') { echo "\n"; break; } readline_add_history($commandLine); readline_write_history($historyPathAndFilename); $request = $this->requestBuilder->build($commandLine); $response = new \TYPO3\FLOW3\Cli\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"; }