Skip to content

Commit 6f689d6

Browse files
committed
[WebServerBundle] changed the way we keep track of the web server
1 parent 585d445 commit 6f689d6

File tree

6 files changed

+156
-107
lines changed

6 files changed

+156
-107
lines changed

src/Symfony/Bundle/WebServerBundle/Command/ServerRunCommand.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\WebServerBundle\Command;
1313

1414
use Symfony\Bundle\WebServerBundle\WebServer;
15+
use Symfony\Bundle\WebServerBundle\WebServerConfig;
1516
use Symfony\Component\Console\Input\InputArgument;
1617
use Symfony\Component\Console\Input\InputOption;
1718
use Symfony\Component\Console\Input\InputInterface;
@@ -34,8 +35,8 @@ protected function configure()
3435
$this
3536
->setDefinition(array(
3637
new InputArgument('addressport', InputArgument::OPTIONAL, 'The address to listen to (can be address:port, address, or port)', '127.0.0.1:8000'),
37-
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
38-
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script', dirname(__DIR__).'/Resources/router.php'),
38+
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root'),
39+
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
3940
))
4041
->setName('server:run')
4142
->setDescription('Runs a local web server')
@@ -84,8 +85,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
8485
$io->error('Running this server in production environment is NOT recommended!');
8586
}
8687

87-
$router = $input->getOption('router');
88-
8988
$callback = null;
9089
$disableOutput = false;
9190
if ($output->isQuiet()) {
@@ -100,13 +99,13 @@ protected function execute(InputInterface $input, OutputInterface $output)
10099
}
101100

102101
try {
103-
$server = new WebServer($input->getArgument('addressport'));
104-
$server->setConfig($documentRoot, $env);
102+
$server = new WebServer();
103+
$config = new WebServerConfig($documentRoot, $env, $input->getArgument('addressport'), $input->getOption('router'));
105104

106-
$io->success(sprintf('Server listening on http://%s', $server->getAddress()));
105+
$io->success(sprintf('Server listening on http://%s', $config->getAddress()));
107106
$io->comment('Quit the server with CONTROL-C.');
108107

109-
$exitCode = $server->run($router, $disableOutput, $callback);
108+
$exitCode = $server->run($config, $disableOutput, $callback);
110109
} catch (\Exception $e) {
111110
$io->error($e->getMessage());
112111

src/Symfony/Bundle/WebServerBundle/Command/ServerStartCommand.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\WebServerBundle\Command;
1313

1414
use Symfony\Bundle\WebServerBundle\WebServer;
15+
use Symfony\Bundle\WebServerBundle\WebServerConfig;
1516
use Symfony\Component\Console\Input\InputArgument;
1617
use Symfony\Component\Console\Input\InputInterface;
1718
use Symfony\Component\Console\Input\InputOption;
@@ -34,8 +35,9 @@ protected function configure()
3435
->setName('server:start')
3536
->setDefinition(array(
3637
new InputArgument('addressport', InputArgument::OPTIONAL, 'The address to listen to (can be address:port, address, or port)', '127.0.0.1:8000'),
37-
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
38+
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root'),
3839
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
40+
new InputOption('pidfile', null, InputOption::VALUE_REQUIRED, 'PID file'),
3941
))
4042
->setDescription('Starts a local web server in the background')
4143
->setHelp(<<<'EOF'
@@ -96,14 +98,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
9698
$io->error('Running this server in production environment is NOT recommended!');
9799
}
98100

99-
$router = $input->getOption('router');
100-
101101
try {
102-
$server = new WebServer($input->getArgument('addressport'));
103-
$server->setConfig($documentRoot, $env);
102+
$server = new WebServer();
103+
$config = new WebServerConfig($documentRoot, $env, $input->getArgument('addressport'), $input->getOption('router'));
104104

105-
if (WebServer::STARTED === $server->start($router)) {
106-
$io->success(sprintf('Server listening on http://%s', $server->getAddress()));
105+
if (WebServer::STARTED === $server->start($config, $input->getOption('pidfile'))) {
106+
$io->success(sprintf('Server listening on http://%s', $config->getAddress()));
107107
}
108108
} catch (\Exception $e) {
109109
$io->error($e->getMessage());

src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ protected function configure()
3434
$this
3535
->setName('server:status')
3636
->setDefinition(array(
37-
new InputArgument('addressport', InputArgument::OPTIONAL, 'The address to listen to (can be address:port, address, or port)', '127.0.0.1:8000'),
37+
new InputOption('pidfile', null, InputOption::VALUE_REQUIRED, 'PID file'),
3838
))
3939
->setDescription('Outputs the status of the local web server for the given address')
4040
;
@@ -46,11 +46,11 @@ protected function configure()
4646
protected function execute(InputInterface $input, OutputInterface $output)
4747
{
4848
$io = new SymfonyStyle($input, $output);
49-
$server = new WebServer($input->getArgument('addressport'));
50-
if ($server->isRunning()) {
51-
$io->success(sprintf('Web server still listening on http://%s', $server->getAddress()));
49+
$server = new WebServer();
50+
if ($server->isRunning($input->getOption('pidfile'))) {
51+
$io->success('Web server still listening.');
5252
} else {
53-
$io->warning(sprintf('No web server is listening on http://%s', $server->getAddress()));
53+
$io->warning('No web server is listening.');
5454
}
5555
}
5656
}

src/Symfony/Bundle/WebServerBundle/Command/ServerStopCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ protected function configure()
3333
$this
3434
->setName('server:stop')
3535
->setDefinition(array(
36-
new InputArgument('addressport', InputArgument::OPTIONAL, 'The address to listen to (can be address:port, address, or port)', '127.0.0.1:8000'),
36+
new InputOption('pidfile', null, InputOption::VALUE_REQUIRED, 'PID file'),
3737
))
3838
->setDescription('Stops the local web server that was started with the server:start command')
3939
->setHelp(<<<'EOF'
@@ -57,9 +57,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
5757
$io = new SymfonyStyle($input, $output);
5858

5959
try {
60-
$server = new WebServer($input->getArgument('addressport'));
61-
$server->stop();
62-
$io->success(sprintf('Stopped the web server listening on http://%s', $server->getAddress()));
60+
$server = new WebServer();
61+
$server->stop($input->getOption('pidfile'));
62+
$io->success('Stopped the web server.');
6363
} catch (\Exception $e) {
6464
$io->error($e->getMessage());
6565

src/Symfony/Bundle/WebServerBundle/WebServer.php

Lines changed: 31 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -26,53 +26,13 @@ class WebServer
2626
const STARTED = 0;
2727
const STOPPED = 1;
2828

29-
private $hostname;
30-
private $port;
31-
private $documentRoot;
32-
private $env;
33-
34-
public function __construct($address = '127.0.0.1:8000')
35-
{
36-
if (false !== $pos = strrpos($address, ':')) {
37-
$this->hostname = substr($address, 0, $pos);
38-
$this->port = substr($address, $pos + 1);
39-
} elseif (ctype_digit($address)) {
40-
$this->hostname = '127.0.0.1';
41-
$this->port = $address;
42-
} else {
43-
$this->hostname = $address;
44-
$this->port = 80;
45-
}
46-
}
47-
48-
public function getAddress()
49-
{
50-
return $this->hostname.':'.$this->port;
51-
}
52-
53-
public function setConfig($documentRoot, $env)
54-
{
55-
if (!is_dir($documentRoot)) {
56-
throw new \InvalidArgumentException(sprintf('The document root directory "%s" does not exist.', $documentRoot));
57-
}
58-
59-
if (null === $file = $this->guessFrontController($documentRoot, $env)) {
60-
throw new \InvalidArgumentException(sprintf('Unable to guess the front controller under "%s".', $documentRoot));
61-
}
62-
63-
putenv('APP_FRONT_CONTROLLER='.$file);
64-
65-
$this->documentRoot = $documentRoot;
66-
$this->env = $env;
67-
}
68-
69-
public function run($router = null, $disableOutput = true, callable $callback = null)
29+
public function run(WebServerConfig $config, $disableOutput = true, callable $callback = null)
7030
{
7131
if ($this->isRunning()) {
72-
throw new \RuntimeException(sprintf('A process is already listening on http://%s.', $this->getAddress()));
32+
throw new \RuntimeException(sprintf('A process is already listening on http://%s.', $config->getAddress()));
7333
}
7434

75-
$process = $this->createServerProcess($router);
35+
$process = $this->createServerProcess($config);
7636
if ($disableOutput) {
7737
$process->disableOutput();
7838
$callback = null;
@@ -96,10 +56,10 @@ public function run($router = null, $disableOutput = true, callable $callback =
9656
}
9757
}
9858

99-
public function start($router = null)
59+
public function start(WebServerConfig $config, $pidFile = null)
10060
{
10161
if ($this->isRunning()) {
102-
throw new \RuntimeException(sprintf('A process is already listening on http://%s.', $this->getAddress()));
62+
throw new \RuntimeException(sprintf('A process is already listening on http://%s.', $config->getAddress()));
10363
}
10464

10565
$pid = pcntl_fork();
@@ -116,20 +76,20 @@ public function start($router = null)
11676
throw new \RuntimeException('Unable to set the child process as session leader.');
11777
}
11878

119-
$process = $this->createServerProcess($router);
79+
$process = $this->createServerProcess($config);
12080
$process->disableOutput();
12181
$process->start();
12282

12383
if (!$process->isRunning()) {
12484
throw new \RuntimeException('Unable to start the server process.');
12585
}
12686

127-
$lockFile = $this->getLockFile();
128-
touch($lockFile);
87+
$pidFile = $pidFile ?: $this->getDefaultPidFile();
88+
file_put_contents($pidFile, $config->getAddress());
12989

13090
// stop the web server when the lock file is removed
13191
while ($process->isRunning()) {
132-
if (!file_exists($lockFile)) {
92+
if (!file_exists($pidFile)) {
13393
$process->stop();
13494
}
13595

@@ -139,69 +99,57 @@ public function start($router = null)
13999
return self::STOPPED;
140100
}
141101

142-
public function stop()
102+
public function stop($pidFile = null)
143103
{
144-
if (!file_exists($lockFile = $this->getLockFile())) {
145-
throw new \RuntimeException(sprintf('No web server is listening on http://%s.', $this->getAddress()));
104+
$pidFile = $pidFile ?: $this->getDefaultPidFile();
105+
if (!file_exists($pidFile)) {
106+
throw new \RuntimeException('No web server is listening.');
146107
}
147108

148-
unlink($lockFile);
109+
unlink($pidFile);
149110
}
150111

151-
public function isRunning()
112+
public function isRunning($pidFile = null)
152113
{
153-
if (false !== $fp = @fsockopen($this->hostname, $this->port, $errno, $errstr, 1)) {
114+
$pidFile = $pidFile ?: $this->getDefaultPidFile();
115+
if (!file_exists($pidFile)) {
116+
return false;
117+
}
118+
119+
$address = file_get_contents($pidFile);
120+
$pos = strrpos($address, ':');
121+
$hostname = substr($address, 0, $pos);
122+
$port = substr($address, $pos + 1);
123+
if (false !== $fp = @fsockopen($hostname, $port, $errno, $errstr, 1)) {
154124
fclose($fp);
155125

156126
return true;
157127
}
158128

159-
if (file_exists($lockFile = $this->getLockFile())) {
160-
unlink($lockFile);
161-
}
129+
unlink($pidFile);
162130

163131
return false;
164132
}
165133

166134
/**
167135
* @return Process The process
168136
*/
169-
private function createServerProcess($router = null)
137+
private function createServerProcess(WebServerConfig $config)
170138
{
171139
$finder = new PhpExecutableFinder();
172140
if (false === $binary = $finder->find()) {
173141
throw new \RuntimeException('Unable to find the PHP binary.');
174142
}
175143

176-
$builder = new ProcessBuilder(array($binary, '-S', $this->getAddress(), $router));
177-
$builder->setWorkingDirectory($this->documentRoot);
144+
$builder = new ProcessBuilder(array($binary, '-S', $config->getAddress(), $config->getRouter()));
145+
$builder->setWorkingDirectory($config->getDocumentRoot());
178146
$builder->setTimeout(null);
179147

180148
return $builder->getProcess();
181149
}
182150

183-
/**
184-
* Determines the name of the lock file for a particular PHP web server process.
185-
*
186-
* @return string The filename
187-
*/
188-
private function getLockFile()
189-
{
190-
return sys_get_temp_dir().'/'.strtr($this->getAddress(), '.:', '--').'.pid';
191-
}
192-
193-
private function guessFrontController($documentRoot, $env)
151+
private function getDefaultPidFile()
194152
{
195-
foreach (array('app', 'index') as $prefix) {
196-
$file = sprintf('%s_%s.php', $prefix, $env);
197-
if (file_exists($documentRoot.'/'.$file)) {
198-
return $file;
199-
}
200-
201-
$file = sprintf('%s.php', $prefix);
202-
if (file_exists($documentRoot.'/'.$file)) {
203-
return $file;
204-
}
205-
}
153+
return getcwd().'/.web-server-pid';
206154
}
207155
}

0 commit comments

Comments
 (0)