/**
  * 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";
 }