Skip to content

Commit 458c082

Browse files
committed
Add dev build tool for PHP manual across different manuals
1 parent 8185e5c commit 458c082

21 files changed

Lines changed: 1229 additions & 1 deletion

‎.docker/Dockerfile‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM php:8.4-cli
2+
3+
ARG UID=1000
4+
ARG GID=1000
5+
6+
RUN apt-get update && \
7+
apt-get install -y git default-jre-headless
8+
9+
WORKDIR /var/www
10+
11+
ADD https://api.github.com/repos/php/phd/git/refs/heads/master version-phd.json
12+
ADD https://api.github.com/repos/php/docbook-cs/git/refs/heads/main version-docbook-cs.json
13+
14+
RUN echo 'memory_limit = 512M' >> /usr/local/etc/php/conf.d/local.ini
15+
16+
RUN chown $UID:$GID /var/www
17+
18+
USER $UID:$GID
19+
20+
RUN git clone --depth 1 https://github.com/php/phd.git && \
21+
git clone --depth 1 https://github.com/php/docbook-cs.git

‎.gitignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Files generated by the configure script
22
.manual.xml
3+
.manual.*.xml
34
.revcheck.json
45
version.xml
56
sources.xml
@@ -9,3 +10,6 @@ fileModHistory.php
910

1011
# A plece for all temporary or generated files (idempotent build)
1112
temp/
13+
14+
# Docker dev build stamp
15+
.docker/built

‎dev.php‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
/**
5+
* Dev build tool for the PHP manual, usable for every language
6+
* Run "php dev.php help" for usage
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
spl_autoload_register(static function (string $class): void {
12+
if (str_starts_with($class, 'PhpDoc\\Dev\\')) {
13+
require __DIR__ . '/scripts/dev/' . str_replace('\\', '/', substr($class, 11)) . '.php';
14+
}
15+
});
16+
17+
exit((new PhpDoc\Dev\Application(__DIR__))->run(array_slice($argv, 1)));

‎docbookcs.dev.xml‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Fallback docbook-cs configuration for translations that do not ship their
4+
own docbookcs.xml. @LANG@ is replaced with the target language.
5+
-->
6+
<docbookcs xmlns="https://php.github.io/docbook-cs/config"
7+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
8+
xsi:schemaLocation="https://php.github.io/docbook-cs/config
9+
https://php.github.io/docbook-cs/config.xsd">
10+
11+
<project>
12+
<directory alias="doc-@LANG@">@LANG@</directory>
13+
<directory>doc-base</directory>
14+
</project>
15+
16+
<sniffs>
17+
<sniff class="DocbookCS\Sniff\SimparaSniff" />
18+
<sniff class="DocbookCS\Sniff\ExceptionNameSniff" />
19+
<sniff class="DocbookCS\Sniff\AttributeOrderSniff" />
20+
<sniff class="DocbookCS\Sniff\MixedIndentationSniff" />
21+
<sniff class="DocbookCS\Sniff\TrailingWhitespaceSniff" />
22+
</sniffs>
23+
24+
<paths>
25+
<path>.</path>
26+
</paths>
27+
28+
<entities>
29+
<file>extensions.ent</file>
30+
<file>language-defs.ent</file>
31+
<file>language-snippets.ent</file>
32+
<directory>entities/</directory>
33+
<directory>../doc-base/entities/</directory>
34+
<file>../doc-base/temp/manual.ent</file>
35+
<file>../doc-base/temp/entities.ent</file>
36+
<file>../doc-base/temp/file-entities.ent</file>
37+
<directory>../doc-base/temp/file-entities</directory>
38+
</entities>
39+
40+
<exclude>
41+
<pattern>output/*</pattern>
42+
</exclude>
43+
44+
</docbookcs>

‎docs/local-setup.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,4 @@ revert the changes with commands below and open an issue on
133133
git config --unset core.autocrlf
134134
git reset
135135
git status
136-
```
136+
```

‎scripts/dev/Application.php‎

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDoc\Dev;
6+
7+
use PhpDoc\Dev\Command\BuildCommand;
8+
use PhpDoc\Dev\Command\ConfigureCommand;
9+
use PhpDoc\Dev\Command\HelpCommand;
10+
use PhpDoc\Dev\Command\LintCommand;
11+
use PhpDoc\Dev\Command\PullCommand;
12+
use PhpDoc\Dev\Command\RenderCommand;
13+
use PhpDoc\Dev\Command\ServeCommand;
14+
use PhpDoc\Dev\Command\ShellCommand;
15+
use PhpDoc\Dev\Environment\DockerEnvironment;
16+
use PhpDoc\Dev\Environment\LocalEnvironment;
17+
18+
final class Application
19+
{
20+
public function __construct(private readonly string $basedir)
21+
{
22+
}
23+
24+
/**
25+
* @param list<string> $args Command line arguments, without argv[0].
26+
*/
27+
public function run(array $args): int
28+
{
29+
$options = new Options();
30+
$command = $this->parse($args, $options);
31+
32+
if ($command === null) {
33+
return 1;
34+
}
35+
36+
if ($command === 'help') {
37+
return (new HelpCommand())->execute($options);
38+
}
39+
40+
$subcommand = null;
41+
42+
if ($command === 'docker') {
43+
$subcommand = array_shift($options->args);
44+
45+
if (!in_array($subcommand, ['build', 'shell'], true)) {
46+
fwrite(STDERR, "Usage: php dev.php docker <build|shell> (see: php dev.php help)\n");
47+
return 1;
48+
}
49+
50+
$options->docker = true;
51+
}
52+
53+
if ($command === 'render') {
54+
$subcommand = array_shift($options->args);
55+
56+
if (!in_array($subcommand, ['xhtml', 'php'], true)) {
57+
fwrite(STDERR, "Usage: php dev.php render <xhtml|php> (see: php dev.php help)\n");
58+
return 1;
59+
}
60+
61+
$options->format = $subcommand;
62+
}
63+
64+
if ($command === 'cs') {
65+
$subcommand = array_shift($options->args);
66+
67+
if (!in_array($subcommand, ['lint', 'fix'], true)) {
68+
fwrite(STDERR, "Usage: php dev.php cs <lint|fix> (see: php dev.php help)\n");
69+
return 1;
70+
}
71+
}
72+
73+
$runner = new ProcessRunner();
74+
$dockerAvailable = $runner->runQuiet(['docker', 'version', '--format', '{{.Server.Version}}']) === 0;
75+
76+
if ($options->docker === true && !$dockerAvailable) {
77+
fwrite(STDERR, "error: Docker requested but the docker command is not available.\n");
78+
return 1;
79+
}
80+
81+
$workspace = new Workspace($this->basedir, $runner, $options->assumeYes);
82+
$environment = ($options->docker ?? $dockerAvailable)
83+
? new DockerEnvironment($workspace, $runner)
84+
: new LocalEnvironment($workspace, $runner);
85+
86+
$configure = new ConfigureCommand($workspace, $environment);
87+
88+
switch ($command) {
89+
case 'pull':
90+
return (new PullCommand($workspace, $environment))->execute($options);
91+
case 'configure':
92+
return $configure->execute($options);
93+
case 'render':
94+
return (new RenderCommand($workspace, $environment, $configure))->execute($options);
95+
case 'cs':
96+
return (new LintCommand($workspace, $environment, $configure, fix: $subcommand === 'fix'))
97+
->execute($options);
98+
case 'serve':
99+
return (new ServeCommand($workspace, $environment))->execute($options);
100+
case 'docker':
101+
return $subcommand === 'build'
102+
? (new BuildCommand($environment))->execute($options)
103+
: (new ShellCommand($environment))->execute($options);
104+
}
105+
106+
fwrite(STDERR, "Unknown command: $command (see: php dev.php help)\n");
107+
108+
return 1;
109+
}
110+
111+
/** @param list<string> $args */
112+
private function parse(array $args, Options $options): ?string
113+
{
114+
$command = null;
115+
116+
foreach ($args as $arg) {
117+
if (preg_match('/^--lang=(.+)$/', $arg, $m)) {
118+
$options->lang = $m[1];
119+
continue;
120+
}
121+
122+
if (preg_match('/^--port=(\d+)$/', $arg, $m)) {
123+
$options->port = (int) $m[1];
124+
continue;
125+
}
126+
127+
if ($arg === '--docker') {
128+
$options->docker = true;
129+
continue;
130+
}
131+
132+
if ($arg === '--no-docker') {
133+
$options->docker = false;
134+
continue;
135+
}
136+
137+
if ($arg === '--yes' || $arg === '-y') {
138+
$options->assumeYes = true;
139+
continue;
140+
}
141+
142+
if ($command === null) {
143+
if ($arg[0] !== '-') {
144+
$command = $arg;
145+
continue;
146+
}
147+
148+
if ($arg === '-h' || $arg === '--help') {
149+
$command = 'help';
150+
continue;
151+
}
152+
153+
$fileName = $_SERVER['SCRIPT_FILENAME'];
154+
fwrite(STDERR, "Unknown option: $arg (see: php $fileName help)\n");
155+
return null;
156+
}
157+
158+
$options->args[] = $arg;
159+
}
160+
161+
return $command ?? 'help';
162+
}
163+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDoc\Dev\Command;
6+
7+
use PhpDoc\Dev\Environment\Environment;
8+
use PhpDoc\Dev\Options;
9+
10+
final class BuildCommand implements Command
11+
{
12+
public function __construct(private readonly Environment $environment)
13+
{
14+
}
15+
16+
public function execute(Options $options): int
17+
{
18+
return $this->environment->buildImage();
19+
}
20+
}

‎scripts/dev/Command/Command.php‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDoc\Dev\Command;
6+
7+
use PhpDoc\Dev\Options;
8+
9+
interface Command
10+
{
11+
public function execute(Options $options): int;
12+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDoc\Dev\Command;
6+
7+
use PhpDoc\Dev\Environment\Environment;
8+
use PhpDoc\Dev\Options;
9+
use PhpDoc\Dev\Workspace;
10+
11+
final class ConfigureCommand implements Command
12+
{
13+
public function __construct(
14+
private readonly Workspace $workspace,
15+
private readonly Environment $environment,
16+
) {
17+
}
18+
19+
public function execute(Options $options): int
20+
{
21+
$lang = $options->lang;
22+
23+
if (!$this->workspace->ensureLangRepos($lang, $this->environment->canMapDirectoryNames())) {
24+
return 1;
25+
}
26+
27+
$this->workspace->pullSideRepos($lang);
28+
29+
$args = array_merge([
30+
($this->workspace->isBaseLang($lang) ? '--with-base-lang=' : '--with-lang=') . $lang,
31+
'--enable-xml-details',
32+
'--disable-libxml-check',
33+
'--redirect-stderr-to-stdout',
34+
], $options->args);
35+
36+
return $this->environment->configure($lang, $args);
37+
}
38+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDoc\Dev\Command;
6+
7+
use PhpDoc\Dev\Options;
8+
9+
final class HelpCommand implements Command
10+
{
11+
public function execute(Options $options): int
12+
{
13+
echo <<<HELP
14+
Dev build tool for the PHP manual, for every language, with or without
15+
Docker. Missing sibling repositories (en, the translation, and without
16+
Docker also phd/docbook-cs) are cloned automatically on first use.
17+
18+
Usage:
19+
php dev.php <command> [options] [extra arguments]
20+
21+
Commands:
22+
pull Clone missing sibling repositories and update existing ones
23+
configure Assemble and validate the manual, without rendering
24+
render xhtml configure + render the chunked XHTML manual to <lang>/output
25+
render php configure + render the web (PHP) version to <lang>/output
26+
cs lint Run docbook-cs; extra arguments are passed through (paths, --wide)
27+
cs fix Same as cs lint, with --fix: rewrite violations that have fixers
28+
serve Serve <lang>/output over HTTP
29+
docker build Build the Docker image
30+
docker shell Interactive shell inside the container
31+
32+
Options:
33+
--lang=XX Language to operate on (default: en)
34+
--port=NNNN Port for serve (default: 8080)
35+
--docker Force Docker mode (default: used when available)
36+
--no-docker Force local mode
37+
--yes, -y Clone missing repositories without asking for confirmation
38+
39+
Any other argument after the command is passed through: to configure.php
40+
for configure/render (e.g. --with-partial=book.datetime), and to
41+
docbook-cs for cs lint/cs fix (e.g. reference/datetime --wide).
42+
43+
HELP;
44+
45+
return 0;
46+
}
47+
}

0 commit comments

Comments
 (0)