Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
use PhpCsFixer\Utils;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
final class Cache implements CacheInterface
{
private SignatureInterface $signature;
/**
* @var array<string, string>
*/
private array $hashes = [];
public function __construct(SignatureInterface $signature)
{
$this->signature = $signature;
}
public function getSignature(): SignatureInterface
{
return $this->signature;
}
public function has(string $file): bool
{
return \array_key_exists($file, $this->hashes);
}
public function get(string $file): ?string
{
if (!$this->has($file)) {
return null;
}
return $this->hashes[$file];
}
public function set(string $file, string $hash): void
{
$this->hashes[$file] = $hash;
}
public function clear(string $file): void
{
unset($this->hashes[$file]);
}
public function toJson(): string
{
$json = json_encode([
'php' => $this->getSignature()->getPhpVersion(),
'version' => $this->getSignature()->getFixerVersion(),
'indent' => $this->getSignature()->getIndent(),
'lineEnding' => $this->getSignature()->getLineEnding(),
'rules' => $this->getSignature()->getRules(),
'hashes' => $this->hashes,
]);
if (\JSON_ERROR_NONE !== json_last_error() || false === $json) {
throw new \UnexpectedValueException(\sprintf(
'Cannot encode cache signature to JSON, error: "%s". If you have non-UTF8 chars in your signature, like in license for `header_comment`, consider enabling `ext-mbstring` or install `symfony/polyfill-mbstring`.',
json_last_error_msg()
));
}
return $json;
}
/**
* @throws \InvalidArgumentException
*/
public static function fromJson(string $json): self
{
$data = json_decode($json, true);
if (null === $data && \JSON_ERROR_NONE !== json_last_error()) {
throw new \InvalidArgumentException(\sprintf(
'Value needs to be a valid JSON string, got "%s", error: "%s".',
$json,
json_last_error_msg()
));
}
$requiredKeys = [
'php',
'version',
'indent',
'lineEnding',
'rules',
'hashes',
];
$missingKeys = array_diff_key(array_flip($requiredKeys), $data);
if (\count($missingKeys) > 0) {
throw new \InvalidArgumentException(\sprintf(
'JSON data is missing keys %s',
Utils::naturalLanguageJoin(array_keys($missingKeys))
));
}
$signature = new Signature(
$data['php'],
$data['version'],
$data['indent'],
$data['lineEnding'],
$data['rules']
);
$cache = new self($signature);
// before v3.11.1 the hashes were crc32 encoded and saved as integers
// @TODO: remove the to string cast/array_map in v4.0
$cache->hashes = array_map(static fn ($v): string => \is_int($v) ? (string) $v : $v, $data['hashes']);
return $cache;
}
/**
* @internal
*/
public function backfillHashes(self $oldCache): bool
{
if (!$this->getSignature()->equals($oldCache->getSignature())) {
return false;
}
$this->hashes = array_merge($oldCache->hashes, $this->hashes);
return true;
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface CacheInterface
{
public function getSignature(): SignatureInterface;
public function has(string $file): bool;
public function get(string $file): ?string;
public function set(string $file, string $hash): void;
public function clear(string $file): void;
public function toJson(): string;
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
interface CacheManagerInterface
{
public function needFixing(string $file, string $fileContent): bool;
public function setFile(string $file, string $fileContent): void;
public function setFileHash(string $file, string $hash): void;
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @readonly
*
* @internal
*/
final class Directory implements DirectoryInterface
{
private string $directoryName;
public function __construct(string $directoryName)
{
$this->directoryName = $directoryName;
}
public function getRelativePathTo(string $file): string
{
$file = $this->normalizePath($file);
if (
'' === $this->directoryName
|| 0 !== stripos($file, $this->directoryName.\DIRECTORY_SEPARATOR)
) {
return $file;
}
return substr($file, \strlen($this->directoryName) + 1);
}
private function normalizePath(string $path): string
{
return str_replace(['\\', '/'], \DIRECTORY_SEPARATOR, $path);
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
interface DirectoryInterface
{
public function getRelativePathTo(string $file): string;
}

View File

@@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
use PhpCsFixer\Hasher;
/**
* Class supports caching information about state of fixing files.
*
* Cache is supported only for phar version and version installed via composer.
*
* File will be processed by PHP CS Fixer only if any of the following conditions is fulfilled:
* - cache is corrupt
* - fixer version changed
* - rules changed
* - file is new
* - file changed
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class FileCacheManager implements CacheManagerInterface
{
public const WRITE_FREQUENCY = 10;
private FileHandlerInterface $handler;
private SignatureInterface $signature;
private bool $isDryRun;
private DirectoryInterface $cacheDirectory;
private int $writeCounter = 0;
private bool $signatureWasUpdated = false;
private CacheInterface $cache;
public function __construct(
FileHandlerInterface $handler,
SignatureInterface $signature,
bool $isDryRun = false,
?DirectoryInterface $cacheDirectory = null
) {
$this->handler = $handler;
$this->signature = $signature;
$this->isDryRun = $isDryRun;
$this->cacheDirectory = $cacheDirectory ?? new Directory('');
$this->readCache();
}
public function __destruct()
{
if (true === $this->signatureWasUpdated || 0 !== $this->writeCounter) {
$this->writeCache();
}
}
/**
* This class is not intended to be serialized,
* and cannot be deserialized (see __wakeup method).
*/
public function __sleep(): array
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
/**
* Disable the deserialization of the class to prevent attacker executing
* code by leveraging the __destruct method.
*
* @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
*/
public function __wakeup(): void
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
public function needFixing(string $file, string $fileContent): bool
{
$file = $this->cacheDirectory->getRelativePathTo($file);
return !$this->cache->has($file) || $this->cache->get($file) !== $this->calcHash($fileContent);
}
public function setFile(string $file, string $fileContent): void
{
$this->setFileHash($file, $this->calcHash($fileContent));
}
public function setFileHash(string $file, string $hash): void
{
$file = $this->cacheDirectory->getRelativePathTo($file);
if ($this->isDryRun && $this->cache->has($file) && $this->cache->get($file) !== $hash) {
$this->cache->clear($file);
} else {
$this->cache->set($file, $hash);
}
if (self::WRITE_FREQUENCY === ++$this->writeCounter) {
$this->writeCounter = 0;
$this->writeCache();
}
}
private function readCache(): void
{
$cache = $this->handler->read();
if (null === $cache || !$this->signature->equals($cache->getSignature())) {
$cache = new Cache($this->signature);
$this->signatureWasUpdated = true;
}
$this->cache = $cache;
}
private function writeCache(): void
{
$this->handler->write($this->cache);
}
private function calcHash(string $content): string
{
return Hasher::calculate($content);
}
}

View File

@@ -0,0 +1,184 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
use Symfony\Component\Filesystem\Exception\IOException;
/**
* @author Andreas Möller <am@localheinz.com>
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class FileHandler implements FileHandlerInterface
{
private \SplFileInfo $fileInfo;
private int $fileMTime = 0;
public function __construct(string $file)
{
$this->fileInfo = new \SplFileInfo($file);
}
public function getFile(): string
{
return $this->fileInfo->getPathname();
}
public function read(): ?CacheInterface
{
if (!$this->fileInfo->isFile() || !$this->fileInfo->isReadable()) {
return null;
}
$fileObject = $this->fileInfo->openFile('r');
$cache = $this->readFromHandle($fileObject);
$this->fileMTime = $this->getFileCurrentMTime();
unset($fileObject); // explicitly close file handler
return $cache;
}
public function write(CacheInterface $cache): void
{
$this->ensureFileIsWriteable();
$fileObject = $this->fileInfo->openFile('r+');
if (method_exists($cache, 'backfillHashes') && $this->fileMTime < $this->getFileCurrentMTime()) {
$resultOfFlock = $fileObject->flock(\LOCK_EX);
if (false === $resultOfFlock) {
// Lock failed, OK - we continue without the lock.
// noop
}
$oldCache = $this->readFromHandle($fileObject);
$fileObject->rewind();
if (null !== $oldCache) {
$cache->backfillHashes($oldCache);
}
}
$resultOfTruncate = $fileObject->ftruncate(0);
if (false === $resultOfTruncate) {
// Truncate failed. OK - we do not save the cache.
return;
}
$resultOfWrite = $fileObject->fwrite($cache->toJson());
if (false === $resultOfWrite) {
// Write failed. OK - we did not save the cache.
return;
}
$resultOfFlush = $fileObject->fflush();
if (false === $resultOfFlush) {
// Flush failed. OK - part of cache can be missing, in case this was last chunk in this pid.
// noop
}
$this->fileMTime = time(); // we could take the fresh `mtime` of file that we just modified with `$this->getFileCurrentMTime()`, but `time()` should be good enough here and reduce IO operation
}
private function getFileCurrentMTime(): int
{
clearstatcache(true, $this->fileInfo->getPathname());
$mtime = $this->fileInfo->getMTime();
if (false === $mtime) {
// cannot check mtime? OK - let's pretend file is old.
$mtime = 0;
}
return $mtime;
}
private function readFromHandle(\SplFileObject $fileObject): ?CacheInterface
{
try {
$size = $fileObject->getSize();
if (false === $size || 0 === $size) {
return null;
}
$content = $fileObject->fread($size);
if (false === $content) {
return null;
}
return Cache::fromJson($content);
} catch (\InvalidArgumentException $exception) {
return null;
}
}
private function ensureFileIsWriteable(): void
{
if ($this->fileInfo->isFile() && $this->fileInfo->isWritable()) {
// all good
return;
}
if ($this->fileInfo->isDir()) {
throw new IOException(
\sprintf('Cannot write cache file "%s" as the location exists as directory.', $this->fileInfo->getRealPath()),
0,
null,
$this->fileInfo->getPathname()
);
}
if ($this->fileInfo->isFile() && !$this->fileInfo->isWritable()) {
throw new IOException(
\sprintf('Cannot write to file "%s" as it is not writable.', $this->fileInfo->getRealPath()),
0,
null,
$this->fileInfo->getPathname()
);
}
$this->createFile($this->fileInfo->getPathname());
}
private function createFile(string $file): void
{
$dir = \dirname($file);
// Ensure path is created, but ignore if already exists. FYI: ignore EA suggestion in IDE,
// `mkdir()` returns `false` for existing paths, so we can't mix it with `is_dir()` in one condition.
if (!@is_dir($dir)) {
@mkdir($dir, 0777, true);
}
if (!@is_dir($dir)) {
throw new IOException(
\sprintf('Directory of cache file "%s" does not exists and couldn\'t be created.', $file),
0,
null,
$file
);
}
@touch($file);
@chmod($file, 0666);
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface FileHandlerInterface
{
public function getFile(): string;
public function read(): ?CacheInterface;
public function write(CacheInterface $cache): void;
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class NullCacheManager implements CacheManagerInterface
{
public function needFixing(string $file, string $fileContent): bool
{
return true;
}
public function setFile(string $file, string $fileContent): void {}
public function setFileHash(string $file, string $hash): void {}
}

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @readonly
*
* @internal
*/
final class Signature implements SignatureInterface
{
private string $phpVersion;
private string $fixerVersion;
private string $indent;
private string $lineEnding;
/**
* @var array<string, array<string, mixed>|bool>
*/
private array $rules;
/**
* @param array<string, array<string, mixed>|bool> $rules
*/
public function __construct(string $phpVersion, string $fixerVersion, string $indent, string $lineEnding, array $rules)
{
$this->phpVersion = $phpVersion;
$this->fixerVersion = $fixerVersion;
$this->indent = $indent;
$this->lineEnding = $lineEnding;
$this->rules = self::makeJsonEncodable($rules);
}
public function getPhpVersion(): string
{
return $this->phpVersion;
}
public function getFixerVersion(): string
{
return $this->fixerVersion;
}
public function getIndent(): string
{
return $this->indent;
}
public function getLineEnding(): string
{
return $this->lineEnding;
}
public function getRules(): array
{
return $this->rules;
}
public function equals(SignatureInterface $signature): bool
{
return $this->phpVersion === $signature->getPhpVersion()
&& $this->fixerVersion === $signature->getFixerVersion()
&& $this->indent === $signature->getIndent()
&& $this->lineEnding === $signature->getLineEnding()
&& $this->rules === $signature->getRules();
}
/**
* @param array<string, array<string, mixed>|bool> $data
*
* @return array<string, array<string, mixed>|bool>
*/
private static function makeJsonEncodable(array $data): array
{
array_walk_recursive($data, static function (&$item): void {
if (\is_string($item) && false === mb_detect_encoding($item, 'utf-8', true)) {
$item = base64_encode($item);
}
});
return $data;
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface SignatureInterface
{
public function getPhpVersion(): string;
public function getFixerVersion(): string;
public function getIndent(): string;
public function getLineEnding(): string;
/**
* @return array<string, array<string, mixed>|bool>
*/
public function getRules(): array;
public function equals(self $signature): bool;
}