Skip to content

Initial setup for file serve #1242

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
10 changes: 10 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM php:8.4-cli

COPY --from=ghcr.io/php/pie:bin /pie /usr/bin/pie

RUN apt update && apt install -y git

RUN docker-php-ext-configure pcntl --enable-pcntl \
&& docker-php-ext-install pcntl \
&& pie install arnaud-lb/inotify

1,171 changes: 896 additions & 275 deletions composer.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/filesystem/src/FileSystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ public function listContents(string $directory = '', bool $recursive = false): a

/** @return StorageAttributes[] */
public function find(SpecificationInterface $specification): iterable;

public function isDirectory(string $path): bool;
}
5 changes: 5 additions & 0 deletions packages/filesystem/src/FlySystemAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,9 @@ public function find(SpecificationInterface $specification): iterable
{
return $this->filesystem->find($specification);
}

public function isDirectory(string $path): bool
{
return $this->filesystem->isDirectory($path);
}
}
5 changes: 5 additions & 0 deletions packages/filesystem/src/FlysystemV1/FlysystemV1.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,9 @@
yield new \phpDocumentor\FileSystem\FlysystemV1\StorageAttributes($file);
}
}

public function isDirectory(string $path): bool
{
return $this->filesystem->directoryExists($path);

Check failure on line 81 in packages/filesystem/src/FlysystemV1/FlysystemV1.php

View workflow job for this annotation

GitHub Actions / Static analysis / Static Code Analysis (8.2)

Call to an undefined method League\Flysystem\FilesystemInterface::directoryExists().
}
}
5 changes: 5 additions & 0 deletions packages/filesystem/src/FlysystemV3/FlysystemV3.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public function has(string $path): bool
return $this->filesystem->has($path);
}

public function isDirectory(string $path): bool
{
return $this->filesystem->directoryExists($path);
}

public function readStream(string $path): mixed
{
return $this->filesystem->readStream($path);
Expand Down
5 changes: 4 additions & 1 deletion packages/guides-cli/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
"symfony/config": "^5.4 || ^6.3 || ^7.0",
"symfony/console": "^5.4 || ^6.3 || ^7.0",
"symfony/dependency-injection": "^5.4 || ^6.3 || ^7.0",
"symfony/event-dispatcher": "^5.4 || ^6.3 || ^7.0"
"symfony/event-dispatcher": "^5.4 || ^6.3 || ^7.0",
"react/http": "^v1.11",
"react/socket": "^v1.16",
"league/mime-type-detection": "^1.16"
},
"bin": [
"bin/guides"
Expand Down
14 changes: 13 additions & 1 deletion packages/guides-cli/resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
use phpDocumentor\Guides\Cli\Application;
use phpDocumentor\Guides\Cli\Command\ProgressBarSubscriber;
use phpDocumentor\Guides\Cli\Command\Run;
use phpDocumentor\Guides\Cli\Command\Serve;
use phpDocumentor\Guides\Cli\Command\WorkingDirectorySwitcher;
use phpDocumentor\Guides\Cli\Command\SettingsBuilder;

Check failure on line 11 in packages/guides-cli/resources/config/services.php

View workflow job for this annotation

GitHub Actions / Coding Standards

Use statements should be sorted alphabetically. The first wrong one is phpDocumentor\Guides\Cli\Command\SettingsBuilder.
use phpDocumentor\Guides\Cli\Internal\RunCommand;
use phpDocumentor\Guides\Cli\Internal\RunCommandHandler;
use Psr\Clock\ClockInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
Expand All @@ -26,6 +30,10 @@
->public()
->tag('phpdoc.guides.cli.command')

->set(Serve::class)
->public()
->tag('phpdoc.guides.cli.command')

->set(NativeClock::class)
->alias(ClockInterface::class, NativeClock::class)

Expand All @@ -44,5 +52,9 @@
->set(WorkingDirectorySwitcher::class)
->tag('event_listener', ['event' => ConsoleEvents::COMMAND, 'method' => '__invoke'])

->set(ProgressBarSubscriber::class);
->set(ProgressBarSubscriber::class)
->set(SettingsBuilder::class)
->set(RunCommandHandler::class)
->tag('phpdoc.guides.command', ['command' => RunCommand::class])
;

Check failure on line 59 in packages/guides-cli/resources/config/services.php

View workflow job for this annotation

GitHub Actions / Coding Standards

Space found before semicolon; expected ");" but found ")\n ;"
};
212 changes: 11 additions & 201 deletions packages/guides-cli/src/Command/Run.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

declare(strict_types=1);
Expand Down Expand Up @@ -25,6 +25,7 @@
use Monolog\Logger;
use phpDocumentor\FileSystem\Finder\Exclude;
use phpDocumentor\FileSystem\FlySystemAdapter;
use phpDocumentor\Guides\Cli\Internal\RunCommand;
use phpDocumentor\Guides\Cli\Logger\SpyProcessor;
use phpDocumentor\Guides\Compiler\CompilerContext;
use phpDocumentor\Guides\Event\PostProjectNodeCreated;
Expand Down Expand Up @@ -66,52 +67,18 @@
public function __construct(
private readonly CommandBus $commandBus,
private readonly Logger $logger,
private readonly ThemeManager $themeManager,

Check failure on line 70 in packages/guides-cli/src/Command/Run.php

View workflow job for this annotation

GitHub Actions / Static analysis / Static Code Analysis (8.2)

Property phpDocumentor\Guides\Cli\Command\Run::$themeManager is never read, only written.
private readonly SettingsManager $settingsManager,
private readonly ClockInterface $clock,
private readonly EventDispatcher $eventDispatcher,
private readonly ProgressBarSubscriber $progressBarSubscriber,
private SettingsBuilder $settingsBuilder,
) {
parent::__construct('run');

$this->addArgument(
'input',
InputArgument::OPTIONAL,
'Directory which holds the files to render',
);
$this->addOption(
'output',
null,
InputOption::VALUE_REQUIRED,
'Directory to write rendered files to',
);

$this->addOption(
'input-file',
null,
InputOption::VALUE_REQUIRED,
'If set, only the specified file is parsed, relative to the directory specified in "input"',
);

$this->addOption(
'exclude-path',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Paths to exclude, doc files in these directories will not be parsed',
);
$this->settingsBuilder ??= new SettingsBuilder($this->eventDispatcher, $this->settingsManager, $this->clock);
$this->settingsBuilder->configureCommand($this);

$this->addOption(
'input-format',
null,
InputOption::VALUE_REQUIRED,
'Format of the input can be "RST", or "Markdown"',
);
$this->addOption(
'output-format',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Format of the input can be "html" and/or "interlink"',
);
$this->addOption(
'log-path',
null,
Expand All @@ -132,13 +99,6 @@
'If set, returns a non-zero exit code as soon as any errors occur',
);

$this->addOption(
'theme',
null,
InputOption::VALUE_REQUIRED,
'The theme used for rendering',
);

$this->addOption(
'progress',
null,
Expand All @@ -159,93 +119,11 @@
$this->progressBarSubscriber->subscribe($output, $this->eventDispatcher);
}

private function getSettingsOverriddenWithInput(InputInterface $input): ProjectSettings
{
$settings = $this->settingsManager->getProjectSettings();

if ($settings->isShowProgressBar()) {
$settings->setShowProgressBar($input->getOption('progress'));
}

if ($input->getArgument('input')) {
$settings->setInput((string) $input->getArgument('input'));
}

if ($input->getOption('output')) {
$settings->setOutput((string) $input->getOption('output'));
}

if ($input->getOption('input-file')) {
$inputFile = (string) $input->getOption('input-file');
$pathInfo = pathinfo($inputFile);
$settings->setInputFile($pathInfo['filename']);
if (!empty($pathInfo['extension'])) {
$settings->setInputFormat($pathInfo['extension']);
}
}

if ($input->getOption('input-format')) {
$settings->setInputFormat((string) $input->getOption('input-format'));
}

if ($input->getOption('log-path')) {
$settings->setLogPath((string) $input->getOption('log-path'));
}

if ($input->getOption('fail-on-error')) {
$settings->setFailOnError(LogLevel::ERROR);
}

if ($input->getOption('fail-on-log')) {
$settings->setFailOnError(LogLevel::WARNING);
}

if (count($input->getOption('output-format')) > 0) {
$settings->setOutputFormats($input->getOption('output-format'));
}

if ($input->getOption('theme')) {
$settings->setTheme((string) $input->getOption('theme'));
}

if (method_exists($settings, 'setExcludes')) {
/** @var list<string> $excludePaths */
$excludePaths = (array) $input->getOption('exclude-path');
if ($excludePaths !== []) {
$settings->setExcludes(
$settings->getExcludes()->withPaths($excludePaths),
);
}
}

return $settings;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$settings = $this->getSettingsOverriddenWithInput($input);
$inputDir = $settings->getInput();
if (!is_dir($inputDir)) {
throw new RuntimeException(sprintf('Input directory "%s" was not found! ' . "\n" .
'Run "vendor/bin/guides -h" for information on how to configure this command.', $inputDir));
}

$projectNode = new ProjectNode(
$settings->getTitle() === '' ? null : $settings->getTitle(),
$settings->getVersion() === '' ? null : $settings->getVersion(),
$settings->getRelease() === '' ? null : $settings->getRelease(),
$settings->getCopyright() === '' ? null : $settings->getCopyright(),
$this->clock->now(),
);

$event = new PostProjectNodeCreated($projectNode, $settings);
$event = $this->eventDispatcher->dispatch($event);
assert($event instanceof PostProjectNodeCreated);
$projectNode = $event->getProjectNode();
$settings = $event->getSettings();

$outputDir = $settings->getOutput();
$sourceFileSystem = FlySystemAdapter::createForPath($settings->getInput());
$this->settingsBuilder->overrideWithInput($input);
$projectNode = $this->settingsBuilder->createProjectNode();
$settings = $this->settingsBuilder->getSettings();

$logPath = $settings->getLogPath();
if ($logPath === 'php://stder') {
Expand All @@ -260,57 +138,16 @@
$this->logger->pushProcessor($spyProcessor);
}

$documents = [];


if ($output instanceof ConsoleOutputInterface && $settings->isShowProgressBar()) {
$this->progressBarSubscriber->subscribe($output, $this->eventDispatcher);
}

if ($settings->getInputFile() === '') {
$documents = $this->commandBus->handle(
new ParseDirectoryCommand(
$sourceFileSystem,
'',
$settings->getInputFormat(),
$projectNode,
$this->getExclude($settings, $input),
),
);
} else {
$documents[] = $this->commandBus->handle(
new ParseFileCommand(
$sourceFileSystem,
'',
$settings->getInputFile(),
$settings->getInputFormat(),
1,
$projectNode,
true,
),
);
}

$this->themeManager->useTheme($settings->getTheme());

$documents = $this->commandBus->handle(new CompileDocumentsCommand($documents, new CompilerContext($projectNode)));

$destinationFileSystem = FlySystemAdapter::createForPath($outputDir);
$documents = $this->commandBus->handle(
new RunCommand($settings, $projectNode, $input),
);

$outputFormats = $settings->getOutputFormats();

foreach ($outputFormats as $format) {
$this->commandBus->handle(
new RenderCommand(
$format,
$documents,
$sourceFileSystem,
$destinationFileSystem,
$projectNode,
),
);
}

$outputDir = $settings->getOutput();
if ($output->isQuiet() === false) {
$lastFormat = '';

Expand All @@ -331,31 +168,4 @@

return Command::SUCCESS;
}

private function getExclude(ProjectSettings $settings, InputInterface|null $input = null): Exclude|SpecificationInterface|null
{
if (method_exists($settings, 'getExcludes')) {
return $settings->getExcludes();
}

if ($input === null) {
return null;
}

if ($input->getOption('exclude-path')) {
/** @var string[] $excludedPaths */
$excludedPaths = (array) $input->getOption('exclude-path');
$excludedSpecifications = array_map(static fn (string $path) => new NotSpecification(new InPath(new Path($path))), $excludedPaths);
$excludedSpecification = array_shift($excludedSpecifications);
assert($excludedSpecification !== null);

return array_reduce(
$excludedSpecifications,
static fn (SpecificationInterface $carry, SpecificationInterface $spec) => new OrSpecification($carry, $spec),
$excludedSpecification,
);
}

return null;
}
}
Loading
Loading