Skip to content

Commit

Permalink
Merge branch 'v5.5.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
williamdes committed Apr 14, 2023
2 parents 7ab4c80 + bc26369 commit 2ca5517
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 8 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"symfony/yaml": "~3.4|~4.3|^5|^6",
"symfony/process": "~3.4|~4.3|^5|^6",
"phpdocumentor/reflection-docblock": "~5.3",
"phpdocumentor/type-resolver": "1.6.*",
"wdes/php-i18n-l10n": "^4.0",
"code-lts/cli-tools": "^1.4.0",
"erusev/parsedown": "^1.7"
Expand Down
5 changes: 5 additions & 0 deletions scripts/make-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,13 @@ echo "PHP version required: ${PHP_VERSION_REQUIRED}"

echo "Lock composer php version"
COMPOSER_FILE=$(cat composer.json)
# Example: 5db49ae740e4d1fd8eb79a9de52c9aefc7906f1f
GIT_COMMIT_HASH="$(git rev-parse --verify HEAD)"
COMPOSER_AUTOLOADER_VERSION="$(echo "$VERSION" | tr '.' '_' | tr '-' '_')"

${COMPOSER_BIN} config platform.php "$PHP_VERSION_REQUIRED"
echo "Setting composer autoload suffix to: ${COMPOSER_AUTOLOADER_VERSION}__${GIT_COMMIT_HASH}"
${COMPOSER_BIN} config autoloader-suffix "${COMPOSER_AUTOLOADER_VERSION}__${GIT_COMMIT_HASH}"

backupVendorFolder

Expand Down
36 changes: 31 additions & 5 deletions scripts/phar-generator-script.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

// To be able to fetch the version in this script afterwards
require_once __DIR__ . '/../src/Doctum.php';
// Load phar utils (https://github.com/Seldaek/phar-utils)
require_once __DIR__ . '/phar-utils-timestamps.php';

use Phar;
use RecursiveDirectoryIterator;
Expand Down Expand Up @@ -40,6 +42,14 @@
exit(1);
}

exec('git show -s --format=%ci HEAD', $commandOutput);

$gitCommitDate = $commandOutput[0] ?? '';
if (empty($gitCommitDate)) {
echo 'Unable to fetch the git commit';
exit(1);
}

$pharAlias = 'doctum-' . $version . '.phar';

$phar = new Phar(
Expand All @@ -50,14 +60,12 @@

$shebang = '#!/usr/bin/env php';

$date = date('c');

// See: https://github.com/zendtech/ZendOptimizerPlus/issues/115#issuecomment-25612769
// See: https://stackoverflow.com/a/13896692/5155484
$stub = <<<STUB
<?php
/**
* Doctum phar, generated by Doctum the $date
* Doctum phar, generated by Doctum on $gitCommitDate
* @see https://github.com/code-lts/doctum#readme
* @version $version
* @license MIT
Expand Down Expand Up @@ -258,14 +266,14 @@ public static function getExcludedFolders(): array
'vcs.browser' => 'https://github.com/code-lts/doctum',
'vcs.ref' => $gitCommit,
'version' => $version,
'build-date' => $date,
'build-date' => $gitCommitDate,
'license' => 'MIT',
'vendor' => 'Doctum',
'name' => 'Doctum',
]
);

$files = array_map(
$files = array_map(
static function (string $fileRelativePath) {
return [
'name' => $fileRelativePath,
Expand All @@ -274,13 +282,31 @@ static function (string $fileRelativePath) {
},
PharFilterIterator::getAcceptedFiles()
);
$oldPharCount = $phar->count();
unset($phar);

$pharUtils = new \Seld\PharUtils\Timestamps($buildRoot . '/doctum.phar');
$pharUtils->updateTimestamps($gitCommitDate);
$pharUtils->save($buildRoot . '/doctum.phar', Phar::SHA256);

$phar = new Phar(
$buildRoot . '/doctum.phar',
FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_FILENAME,
$pharAlias
);

if ($oldPharCount !== $phar->count()) {
echo 'File count mismatch, phar is corrupted ?';
exit(1);
}

$manifest = [
'files' => $files,
'excludedFiles' => PharFilterIterator::getExcludedFiles(),
'excludedFolders' => PharFilterIterator::getExcludedFolders(),
'phar' => [
'sha256' => $phar->getSignature()['hash'],
'fileSha256' => hash_file('sha256', $buildRoot . '/doctum.phar'),
'numberOfFiles' => $phar->count(),
],
];
Expand Down
204 changes: 204 additions & 0 deletions scripts/phar-utils-timestamps.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
<?php

declare(strict_types = 1);

/*
* This file is part of PHAR Utils.
*
* (c) Jordi Boggiano <[email protected]>
*
* @source https://github.com/Seldaek/phar-utils/commit/8dbab3e508113310354194c83719ca343b4ad9f4
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Seld\PharUtils;

class Timestamps
{
/**
* @var string
*/
private $contents;

/**
* @param string $file path to the phar file to use
*/
public function __construct(string $file)
{
$this->contents = file_get_contents($file);
}

/**
* Updates each file's unix timestamps in the PHAR
*
* The PHAR signature can then be produced in a reproducible manner.
*
* @param int|\DateTimeInterface|string $timestamp Date string or DateTime or unix timestamp to use
*/
public function updateTimestamps($timestamp = null)
{
if ($timestamp instanceof \DateTime || $timestamp instanceof \DateTimeInterface) {
$timestamp = $timestamp->getTimestamp();
} elseif (is_string($timestamp)) {
$timestamp = strtotime($timestamp);
} elseif (!is_int($timestamp)) {
$timestamp = strtotime('1984-12-24T00:00:00Z');
}

// detect manifest offset / end of stub
if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) {
throw new \RuntimeException('Could not detect the stub\'s end in the phar');
}

// set starting position and skip past manifest length
$pos = $match[0][1] + strlen($match[0][0]);
$stubEnd = $pos + $this->readUint($pos, 4);
$pos += 4;

$numFiles = $this->readUint($pos, 4);
$pos += 4;

// skip API version (YOLO)
$pos += 2;

// skip PHAR flags
$pos += 4;

$aliasLength = $this->readUint($pos, 4);
$pos += 4 + $aliasLength;

$metadataLength = $this->readUint($pos, 4);
$pos += 4 + $metadataLength;

while ($pos < $stubEnd) {
$filenameLength = $this->readUint($pos, 4);
$pos += 4 + $filenameLength;

// skip filesize
$pos += 4;

// update timestamp to a fixed value
$timeStampBytes = pack('L', $timestamp);
$this->contents[$pos + 0] = $timeStampBytes[0];
$this->contents[$pos + 1] = $timeStampBytes[1];
$this->contents[$pos + 2] = $timeStampBytes[2];
$this->contents[$pos + 3] = $timeStampBytes[3];

// skip timestamp, compressed file size, crc32 checksum and file flags
$pos += 4 * 4;

$metadataLength = $this->readUint($pos, 4);
$pos += 4 + $metadataLength;

$numFiles--;
}

if ($numFiles !== 0) {
throw new \LogicException('All files were not processed, something must have gone wrong');
}
}

/**
* Saves the updated phar file, optionally with an updated signature.
*
* @param string $path
* @param int $signatureAlgo One of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512
* @return bool
*/
public function save(string $path, int $signatureAlgo)
{
$pos = $this->determineSignatureBegin();

$algos = [
\Phar::MD5 => 'md5',
\Phar::SHA1 => 'sha1',
\Phar::SHA256 => 'sha256',
\Phar::SHA512 => 'sha512',
];

if (!isset($algos[$signatureAlgo])) {
throw new \UnexpectedValueException('Invalid hash algorithm given: ' . $signatureAlgo . ' expected one of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512');
}
$algo = $algos[$signatureAlgo];

// re-sign phar
// signature
$signature = hash($algo, substr($this->contents, 0, $pos), true)
// sig type
. pack('L', $signatureAlgo)
// ohai Greg & Marcus
. 'GBMB';

$this->contents = substr($this->contents, 0, $pos) . $signature;

return file_put_contents($path, $this->contents);
}

private function readUint($pos, $bytes)
{
$res = unpack('V', substr($this->contents, $pos, $bytes));

return $res[1];
}

/**
* Determine the beginning of the signature.
*
* @return int
*/
private function determineSignatureBegin()
{
// detect signature position
if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) {
throw new \RuntimeException('Could not detect the stub\'s end in the phar');
}

// set starting position and skip past manifest length
$pos = $match[0][1] + strlen($match[0][0]);
$manifestEnd = $pos + 4 + $this->readUint($pos, 4);

$pos += 4;
$numFiles = $this->readUint($pos, 4);

$pos += 4;

// skip API version (YOLO)
$pos += 2;

// skip PHAR flags
$pos += 4;

$aliasLength = $this->readUint($pos, 4);
$pos += 4 + $aliasLength;

$metadataLength = $this->readUint($pos, 4);
$pos += 4 + $metadataLength;

$compressedSizes = 0;
while (($numFiles > 0) && ($pos < $manifestEnd - 24)) {
$filenameLength = $this->readUint($pos, 4);
$pos += 4 + $filenameLength;

// skip filesize and timestamp
$pos += 2 * 4;

$compressedSizes += $this->readUint($pos, 4);
// skip compressed file size, crc32 checksum and file flags
$pos += 3 * 4;

$metadataLength = $this->readUint($pos, 4);
$pos += 4 + $metadataLength;

$numFiles--;
}

if ($numFiles !== 0) {
throw new \LogicException('All files were not processed, something must have gone wrong');
}

return $manifestEnd + $compressedSizes;
}

}
2 changes: 1 addition & 1 deletion scripts/update-release.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash

##
# @license http://unlicense.org/UNLICENSE The UNLICENSE
Expand Down
11 changes: 9 additions & 2 deletions src/Parser/NodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
use Doctum\Parser\Node\DocBlockNode;
use PhpParser\Node\Stmt\PropertyProperty;
use PhpParser\Node\UnionType;
use PhpParser\Node\IntersectionType;

class NodeVisitor extends NodeVisitorAbstract
{
Expand Down Expand Up @@ -187,12 +188,12 @@ protected function addFunction(FunctionNode $node, ?string $namespace = null)
}

/**
* @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|NullableType|UnionType|null $type Type declaration
* @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|NullableType|UnionType|IntersectionType|null $type Type declaration
*/
protected function typeToString($type): ?string
{
$typeString = null;
if ($type !== null && ! ($type instanceof NullableType || $type instanceof UnionType)) {
if ($type !== null && ! ($type instanceof NullableType || $type instanceof UnionType || $type instanceof IntersectionType)) {
$typeString = $type->__toString();
} elseif ($type instanceof NullableType) {
$typeString = $type->type->__toString();
Expand All @@ -202,6 +203,12 @@ protected function typeToString($type): ?string
$typeString[] = $type->__toString();
}
$typeString = implode('|', $typeString);
} elseif ($type instanceof IntersectionType) {
$typeString = [];
foreach ($type->types as $type) {
$typeString[] = $type->__toString();
}
$typeString = implode('&', $typeString);
}

if ($typeString === null) {
Expand Down
Loading

0 comments on commit 2ca5517

Please sign in to comment.