Update website

This commit is contained in:
Guilhem Lavaux 2024-11-19 08:02:04 +01:00
parent 4413528994
commit 1d90fbf296
6865 changed files with 1091082 additions and 0 deletions

View file

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\Builder;
use Symfony\Component\Filesystem\Filesystem;
use function basename;
use function dirname;
use function is_dir;
final class Copier
{
/** @var Filesystem */
private $filesystem;
/** @var string[][] */
private $toCopy = [];
/** @var string[] */
private $toMkdir = [];
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
public function doCopy(string $sourceDirectory, string $targetDirectory): void
{
foreach ($this->toCopy as $copy) {
[$source, $destination] = $copy;
if ($source[0] !== '/') {
$source = $sourceDirectory . '/' . $source;
}
$destination = $targetDirectory . '/' . $destination;
if (is_dir($source) && is_dir($destination)) {
$destination = dirname($destination);
}
if (is_dir($source)) {
$this->filesystem->mirror($source, $destination);
} else {
$this->filesystem->copy($source, $destination);
}
}
$this->toCopy = [];
}
public function doMkdir(string $targetDirectory): void
{
foreach ($this->toMkdir as $mkdir) {
$dir = $targetDirectory . '/' . $mkdir;
if (is_dir($dir)) {
continue;
}
$this->filesystem->mkdir($dir, 0755);
}
$this->toMkdir = [];
}
public function copy(string $source, ?string $destination = null): void
{
if ($destination === null) {
$destination = basename($source);
}
$this->toCopy[] = [$source, $destination];
}
public function mkdir(string $directory): void
{
$this->toMkdir[] = $directory;
}
}

View file

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\Builder;
use Doctrine\RST\Meta\Metas;
use Doctrine\RST\Nodes\DocumentNode;
use InvalidArgumentException;
use Symfony\Component\Filesystem\Filesystem;
use function dirname;
use function is_dir;
use function sprintf;
class Documents
{
/** @var Filesystem */
private $filesystem;
/** @var Metas */
private $metas;
/** @var DocumentNode[] */
private $documents = [];
public function __construct(
Filesystem $filesystem,
Metas $metas
) {
$this->filesystem = $filesystem;
$this->metas = $metas;
}
/** @return DocumentNode[] */
public function getAll(): array
{
return $this->documents;
}
public function hasDocument(string $file): bool
{
return isset($this->documents[$file]);
}
public function addDocument(string $file, DocumentNode $document): void
{
$this->documents[$file] = $document;
}
public function render(string $targetDirectory): void
{
foreach ($this->documents as $file => $document) {
$target = $this->getTargetOf($targetDirectory, $file);
$directory = dirname($target);
if (! is_dir($directory)) {
$this->filesystem->mkdir($directory, 0755);
}
$this->filesystem->dumpFile($target, $document->renderDocument());
}
}
private function getTargetOf(string $targetDirectory, string $file): string
{
$metaEntry = $this->metas->get($file);
if ($metaEntry === null) {
throw new InvalidArgumentException(sprintf('Could not find target file for %s', $file));
}
return $targetDirectory . '/' . $metaEntry->getUrl();
}
}

View file

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\Builder;
use InvalidArgumentException;
use function array_filter;
use function array_key_exists;
use function array_keys;
use function sprintf;
final class ParseQueue
{
/**
* An array where each key is the filename and the value is a
* boolean indicating if the file needs to be parsed or not.
*
* @var bool[]
*/
private $fileStatuses = [];
public function addFile(string $filename, bool $parseNeeded): void
{
if (isset($this->fileStatuses[$filename])) {
throw new InvalidArgumentException(sprintf('File "%s" is already in the parse queue', $filename));
}
$this->fileStatuses[$filename] = $parseNeeded;
}
public function isFileKnownToParseQueue(string $filename): bool
{
return array_key_exists($filename, $this->fileStatuses);
}
public function doesFileRequireParsing(string $filename): bool
{
if (! $this->isFileKnownToParseQueue($filename)) {
throw new InvalidArgumentException(sprintf('File "%s" is not known to the parse queue', $filename));
}
return $this->fileStatuses[$filename];
}
/** @return string[] */
public function getAllFilesThatRequireParsing(): array
{
return array_keys(array_filter($this->fileStatuses, static function (bool $parseNeeded): bool {
return $parseNeeded;
}));
}
}

View file

@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\Builder;
use Doctrine\RST\ErrorManager;
use Doctrine\RST\Kernel;
use Doctrine\RST\Meta\Metas;
use Doctrine\RST\Nodes\DocumentNode;
use Doctrine\RST\Parser;
use function filemtime;
use function fwrite;
use function getenv;
use function sprintf;
use const PHP_SAPI;
use const STDERR;
final class ParseQueueProcessor
{
/** @var Kernel */
private $kernel;
/** @var ErrorManager */
private $errorManager;
/** @var Metas */
private $metas;
/** @var Documents */
private $documents;
/** @var string */
private $directory;
/** @var string */
private $targetDirectory;
/** @var string */
private $fileExtension;
public function __construct(
Kernel $kernel,
ErrorManager $errorManager,
Metas $metas,
Documents $documents,
string $directory,
string $targetDirectory,
string $fileExtension
) {
$this->kernel = $kernel;
$this->errorManager = $errorManager;
$this->metas = $metas;
$this->documents = $documents;
$this->directory = $directory;
$this->targetDirectory = $targetDirectory;
$this->fileExtension = $fileExtension;
}
public function process(ParseQueue $parseQueue): void
{
foreach ($parseQueue->getAllFilesThatRequireParsing() as $file) {
$this->processFile($file);
}
}
private function processFile(string $file): void
{
if (getenv('SHELL_VERBOSITY') >= 1 && PHP_SAPI === 'cli') {
fwrite(STDERR, sprintf("Processing file: %s\n", $file));
}
$fileAbsolutePath = $this->buildFileAbsolutePath($file);
$parser = $this->createFileParser($file);
$environment = $parser->getEnvironment();
$document = $parser->parseFile($fileAbsolutePath);
$this->documents->addDocument($file, $document);
$this->kernel->postParse($document);
$this->metas->set(
$file,
$this->buildDocumentUrl($document),
(string) $document->getTitle(),
$document->getTitles(),
$document->getTocs(),
(int) filemtime($fileAbsolutePath),
$environment->getDependencies(),
$environment->getLinks()
);
}
private function createFileParser(string $file): Parser
{
$parser = new Parser($this->kernel);
$environment = $parser->getEnvironment();
$environment->setMetas($this->metas);
$environment->setCurrentFileName($file);
$environment->setCurrentDirectory($this->directory);
$environment->setTargetDirectory($this->targetDirectory);
$environment->setErrorManager($this->errorManager);
return $parser;
}
private function buildFileAbsolutePath(string $file): string
{
return $this->directory . '/' . $file . '.rst';
}
private function buildDocumentUrl(DocumentNode $document): string
{
return $document->getEnvironment()->getUrl() . '.' . $this->fileExtension;
}
}

View file

@ -0,0 +1,147 @@
<?php
declare(strict_types=1);
namespace Doctrine\RST\Builder;
use Doctrine\RST\Meta\Metas;
use InvalidArgumentException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use function sprintf;
use function strlen;
use function substr;
final class Scanner
{
/** @var string */
private $fileExtension;
/** @var string */
private $directory;
/** @var Metas */
private $metas;
/** @var Finder */
private $finder;
/** @var SplFileInfo[] */
private $fileInfos = [];
public function __construct(string $fileExtension, string $directory, Metas $metas, ?Finder $finder = null)
{
$this->fileExtension = $fileExtension;
$this->directory = $directory;
$this->metas = $metas;
$this->finder = $finder ?? new Finder();
$this->finder->in($this->directory)
->files()
->name('*.' . $this->fileExtension);
}
/**
* Scans a directory recursively looking for all files to parse.
*
* This takes into account the presence of cached & fresh MetaEntry
* objects, and avoids adding files to the parse queue that have
* not changed and whose direct dependencies have not changed.
*/
public function scan(): ParseQueue
{
// completely populate the splFileInfos property
$this->fileInfos = [];
foreach ($this->finder as $fileInfo) {
$relativeFilename = $fileInfo->getRelativePathname();
// strip off the extension
$documentPath = substr($relativeFilename, 0, -(strlen($this->fileExtension) + 1));
$this->fileInfos[$documentPath] = $fileInfo;
}
$parseQueue = new ParseQueue();
foreach ($this->fileInfos as $filename => $fileInfo) {
$parseQueue->addFile(
$filename,
$this->doesFileRequireParsing($filename, $parseQueue)
);
}
return $parseQueue;
}
private function doesFileRequireParsing(string $filename, ParseQueue $parseQueue): bool
{
if (! isset($this->fileInfos[$filename])) {
throw new InvalidArgumentException(sprintf('No file info found for "%s" - file does not exist.', $filename));
}
$file = $this->fileInfos[$filename];
$documentFilename = $this->getFilenameFromFile($file);
$entry = $this->metas->get($documentFilename);
if ($this->hasFileBeenUpdated($filename)) {
// File is new or changed and thus need to be parsed
return true;
}
// Look to the file's dependencies to know if you need to parse it or not
$dependencies = $entry !== null ? $entry->getDepends() : [];
if ($entry !== null && $entry->getParent() !== null) {
$dependencies[] = $entry->getParent();
}
foreach ($dependencies as $dependency) {
/*
* The dependency check is NOT recursive on purpose.
* If fileA has a link to fileB that uses its "headline",
* for example, then fileA is "dependent" on fileB. If
* fileB changes, it means that its MetaEntry needs to
* be updated. And because fileA gets the headline from
* the MetaEntry, it means that fileA must also be re-parsed.
* However, if fileB depends on fileC and file C only is
* updated, fileB *does* need to be re-parsed, but fileA
* does not, because the MetaEntry for fileB IS still
* "fresh" - fileB did not actually change, so any metadata
* about headlines, etc, is still fresh. Therefore, fileA
* does not need to be parsed.
*/
// dependency no longer exists? We should re-parse this file
if (! isset($this->fileInfos[$dependency])) {
return true;
}
// finally, we need to recursively ask if this file needs parsing
if ($this->hasFileBeenUpdated($dependency)) {
return true;
}
}
// Meta is fresh and no dependencies need parsing
return false;
}
private function hasFileBeenUpdated(string $filename): bool
{
$file = $this->fileInfos[$filename];
$documentFilename = $this->getFilenameFromFile($file);
$entry = $this->metas->get($documentFilename);
// File is new or changed
return $entry === null || $entry->getMtime() < $file->getMTime();
}
/**
* Converts foo/bar.rst to foo/bar (the document filename)
*/
private function getFilenameFromFile(SplFileInfo $file): string
{
return substr($file->getRelativePathname(), 0, -(strlen($this->fileExtension) + 1));
}
}