Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created server:run nut command #5228

Merged
merged 1 commit into from
Apr 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions src/Nut/ServerRun.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php

namespace Bolt\Nut;

use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\ProcessBuilder;

/**
* Runs Bolt application using PHP built-in web server.
*
* @author Carson Full <[email protected]>
*/
class ServerRun extends BaseCommand
{
/**
* {@inheritdoc}
*/
public function configure()
{
parent::configure();
$this
->setName('server:run')
->setDescription('Runs PHP built-in web server')
->addArgument('address', InputArgument::OPTIONAL, 'Address:port', '0.0.0.0')
->addOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000')
;
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);

$address = $input->getArgument('address');
if (strpos($address, ':') === false) {
$address .= ':' . $input->getOption('port');
}

if ($this->isOtherServerProcessRunning($address)) {
$io->error(sprintf('A process is already listening on http://%s', $address));

return 1;
}

$webDir = $this->app['resources']->getPath('web');
$router = $webDir . '/index.php';

$io->success(sprintf('Server running on http://%s', $address));
$io->comment('Quit the server with CONTROL-C.');

if (($process = $this->createServerProcess($io, $address, $webDir, $router)) === null) {
return 1;
}

/** @var ProcessHelper $helper */
$helper = $this->getHelper('process');
$helper->run($output, $process, null, null, OutputInterface::VERBOSITY_VERBOSE);

if (!$process->isSuccessful()) {
$errorMessages = ['Built-in server terminated unexpectedly.'];

if ($process->isOutputDisabled()) {
$errorMessages[] = 'Run the command again with -v option for more details.';
}

$io->error($errorMessages);
}

return $process->getExitCode();
}

/**
* @param SymfonyStyle $io
* @param string $address
* @param string $webDir
* @param string $router
*
* @return null|\Symfony\Component\Process\Process
*/
protected function createServerProcess(SymfonyStyle $io, $address, $webDir, $router)
{
if (!file_exists($router)) {
$io->error(sprintf('The router script "%s" does not exist', $router));

return null;
}

$finder = new PhpExecutableFinder();
if (($binary = $finder->find()) === false) {
$io->error('Unable to find PHP binary to run server.');

return null;
}

$builder = new ProcessBuilder([$binary, '-S', $address, '-t', $webDir, $router]);
$builder->setTimeout(null);

if ($io->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE) {
$builder->disableOutput();
}

return $builder->getProcess();
}

/**
* Determines if another process is bound to the given address and port.
*
* @param string $address An address/port tuple
*
* @return bool
*/
protected function isOtherServerProcessRunning($address)
{
$lockFile = $this->getLockFile($address);

if (file_exists($lockFile)) {
return true;
}

list ($hostname, $port) = explode(':', $address);

$fp = @fsockopen($hostname, $port, $errno, $errstr, 5);

if ($fp !== false) {
fclose($fp);

return true;
}

return false;
}

/**
* Determines the name of the lock file for a particular PHP web server process.
*
* @param string $address An address/port tuple
*
* @return string The filename
*/
protected function getLockFile($address)
{
return sys_get_temp_dir() . '/' . strtr($address, '.:', '--') . '.pid';
}
}
1 change: 1 addition & 0 deletions src/Provider/NutServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function ($app) {
new Nut\UserResetPassword($app),
new Nut\UserRoleAdd($app),
new Nut\UserRoleRemove($app),
new Nut\ServerRun($app),
new Nut\SetupSync($app),
];
}
Expand Down