diff -u b/core/lib/Drupal/Core/Command/QuickStartCommand.php b/core/lib/Drupal/Core/Command/QuickStartCommand.php --- b/core/lib/Drupal/Core/Command/QuickStartCommand.php +++ b/core/lib/Drupal/Core/Command/QuickStartCommand.php @@ -31,7 +31,6 @@ ->addOption('host', NULL, InputOption::VALUE_OPTIONAL, 'Provide a host for the server to run on. Defaults to 127.0.0.1.', '127.0.0.1') ->addOption('port', NULL, InputOption::VALUE_OPTIONAL, 'Provide a port for the server to run on. Will be determined automatically if none supplied.') ->addOption('suppress-login', 's', InputOption::VALUE_NONE, 'Disable opening a login URL in a browser.') - ->addOption('show-server-output', NULL, InputOption::VALUE_NONE, 'Show output from the PHP development server.') ->addUsage('demo_umami --langcode fr'); parent::configure(); @@ -63,9 +62,6 @@ if ($input->getOption('suppress-login')) { $arguments['--suppress-login'] = TRUE; } - if ($input->getOption('show-server-output')) { - $arguments['--show-server-output'] = TRUE; - } $serverInput = new ArrayInput($arguments); $returnCode = $command->run($serverInput, $output); } diff -u b/core/lib/Drupal/Core/Command/ServerCommand.php b/core/lib/Drupal/Core/Command/ServerCommand.php --- b/core/lib/Drupal/Core/Command/ServerCommand.php +++ b/core/lib/Drupal/Core/Command/ServerCommand.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessUtils; /** * Runs the PHP webserver for a Drupal site for local testing/development. @@ -46,8 +47,7 @@ $this->setDescription('Starts up a webserver for a site.') ->addOption('host', NULL, InputOption::VALUE_OPTIONAL, 'Provide a host for the server to run on. Defaults to 127.0.0.1.', '127.0.0.1') ->addOption('port', NULL, InputOption::VALUE_OPTIONAL, 'Provide a port for the server to run on. Will be determined automatically if none supplied.') - ->addOption('suppress-login', 's', InputOption::VALUE_NONE, 'Disable opening a login URL in a browser.') - ->addOption('show-server-output', NULL, InputOption::VALUE_NONE, 'Show output from the PHP development server.'); + ->addOption('suppress-login', 's', InputOption::VALUE_NONE, 'Disable opening a login URL in a browser.'); } /** @@ -130,29 +130,40 @@ * * @param string $url * The URL to browser to. - * - * @return int - * The exit code of opening up a browser. + * @param \Symfony\Component\Console\Style\SymfonyStyle $io + * The IO. + * @param int $wait + * Time in seconds to wait for before opening the browser. */ - protected function openBrowser($url, SymfonyStyle $io) { + protected function openBrowser($url, SymfonyStyle $io, $wait = 0) { $url = escapeshellarg($url); $is_windows = defined('PHP_WINDOWS_VERSION_BUILD'); if ($is_windows) { - $process = new Process('start "web" explorer "' . $url . '"'); - return $process->run(); + $cmd = 'start "web" explorer "' . $url . '"'; } $is_linux = (new Process('which xdg-open'))->run(); $is_osx = (new Process('which open'))->run(); if ($is_linux === 0) { - return (new Process('xdg-open ' . $url))->run(); + $cmd = 'xdg-open ' . $url; } elseif ($is_osx === 0) { - return (new Process('open ' . $url))->run(); + $cmd = 'open ' . $url; } - $io->getErrorStyle() - ->error('No suitable browser opening command found, open yourself: ' . $url); + + if (empty($cmd)) { + $io->getErrorStyle() + ->error('No suitable browser opening command found, open yourself: ' . $url); + return; + } + + if ($wait) { + $cmd = 'sleep ' . $wait . ' && ' . $cmd; + } + + (new Process($cmd))->start(); + return; } /** @@ -170,12 +181,19 @@ /** * Starts up a webserver with a running Drupal. * + * @param strng $host + * The hostname of the webserver. + * @param int $port + * The port to start the webserver on. * @param \Drupal\Core\DrupalKernelInterface $kernel * The Drupal kernel. * @param \Symfony\Component\Console\Input\InputInterface $input * The input. * @param \Symfony\Component\Console\Style\SymfonyStyle $io * The IO. + * + * @return int + * The exit status of the PHP in-built webserver command. */ protected function start($host, $port, DrupalKernelInterface $kernel, InputInterface $input, SymfonyStyle $io) { $finder = new PhpExecutableFinder(); @@ -184,44 +202,34 @@ throw new \RuntimeException('Unable to find the PHP binary.'); } - $process = new Process([ - $binary, - '-S', - $host . ':' . $port, - '.ht.router.php', - ], $kernel->getAppRoot(), [], NULL, NULL); - - // If TTY is available and the --show-server-output is used, run the command - // using it so that the full colored output from PHP's in-built webserver is - // displayed. - if (DIRECTORY_SEPARATOR !== '\\' && $input->getOption('show-server-output')) { - $process->setTty(TRUE); - $process->start(); - } - else { - $io->writeln("Starting webserver on http://$host:$port"); - $io->writeln('Press Ctrl-C to quit.'); - $output = NULL; - if ($input->getOption('show-server-output')) { - $output = function ($type, $buffer) { - echo $buffer; - }; - } - $process->start($output); - } - + $io->writeln("Drupal development server started: "); $one_time_login = "http://$host:$port{$this->getOneTimeLoginUrl()}/login"; - if ($input->getOption('suppress-login')) { - $io->writeln('One time login url: ' . $one_time_login); - } - else { - // Should we redirect to the front page? - if ($this->openBrowser("$one_time_login?destination=" . urlencode("/"), $io) === 1) { + $io->writeln("One time login url: <$one_time_login>"); + $io->writeln('Press Ctrl-C to quit.'); + + if (!$input->getOption('suppress-login')) { + // @todo Fix redirect to the front page. + if ($this->openBrowser("$one_time_login?destination=" . urlencode("/"), $io, 2) === 1) { $io->error('Error while opening up a one time login URL'); } } - // Hang until the process is killed. - $process->wait(); + + $command = sprintf('%s -S %s:%s %s', + ProcessUtils::escapeArgument($binary), + $host, + $port, + '.ht.router.php' + ); + + // Write a blank line so that server output and the useful information are + // visually separated. + $io->writeln(''); + $cwd = getcwd(); + chdir($kernel->getAppRoot()); + // To support Windows we can't open the server in another process. + passthru($command, $status); + chdir($cwd); + return $status; } /** diff -u b/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php b/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php --- b/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php +++ b/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php @@ -53,6 +53,9 @@ $this->php = $php_executable_finder->find(); $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))); chdir($this->root); + if (!is_writable("{$this->root}/sites/simpletest")) { + $this->markTestSkipped('This test requires a writable sites/simpletest directory'); + } // Get a lock and a valid site path. $this->testDb = new TestDatabase(); }