Skip to content

Commit

Permalink
Removes laminas/laminas-stdlib dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelstolt committed Sep 23, 2024
1 parent f92675d commit 115bb82
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

### Removed

- Removed laminas/laminas-stdlib dependency

## [v4.0.3] - 2024-07-10

### Added
Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
],
"require": {
"php": ">=8.1",
"laminas/laminas-stdlib": "^3.19",
"sebastian/diff": "^5.0||^4.0.3",
"sebastian/diff": "^6.0.1||^5.0||^4.0.3",
"symfony/console": "^7.1.0||^v5.4.8"
},
"autoload": {
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ parameters:
- '#is never read#'
- '#TMock#'
- '#unknown class#'
- '#set_error_handler expects#'
1 change: 0 additions & 1 deletion src/Analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Stolt\LeanPackage;

use Laminas\Stdlib\Glob;
use Stolt\LeanPackage\Exceptions\InvalidGlobPattern;
use Stolt\LeanPackage\Exceptions\InvalidGlobPatternFile;
use Stolt\LeanPackage\Exceptions\NonExistentGlobPatternFile;
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/ValidateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

return Command::FAILURE;
}
} elseif($this->isGlobPatternFileSettable($globPatternFile)) {
} elseif ($this->isGlobPatternFileSettable($globPatternFile)) {
try {
if ($this->isDefaultGlobPatternFilePresent()) {
$this->analyser->setGlobPatternFromFile($globPatternFile);
Expand Down
116 changes: 116 additions & 0 deletions src/ErrorHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php declare(strict_types=1);

namespace Stolt\LeanPackage;

use function array_pop;

use function count;
use const E_WARNING;
use ErrorException;
use function restore_error_handler;

use function set_error_handler;

/**
* ErrorHandler that can be used to catch internal PHP errors
* and convert to an ErrorException instance.
*/
abstract class ErrorHandler
{
/**
* Active stack
*
* @var list<ErrorException|null>
*/
protected static $stack = [];

/**
* Check if this error handler is active
*
* @return bool
*/
public static function started()
{
return (bool) static::getNestedLevel();
}

/**
* Get the current nested level
*
* @return int
*/
public static function getNestedLevel()
{
return \count(static::$stack);
}

/**
* Starting the error handler
*
* @param int $errorLevel
* @return void
*/
public static function start($errorLevel = E_WARNING)
{
if (! static::$stack) {
\set_error_handler([static::class, 'addError'], $errorLevel);
}

static::$stack[] = null;
}

/**
* Stopping the error handler
*
* @param bool $throw Throw the ErrorException if any
* @throws ErrorException If an error has been caught and $throw is true.
* @return null|ErrorException
*/
public static function stop($throw = false)
{
$errorException = null;

if (static::$stack) {
$errorException = \array_pop(static::$stack);

if (! static::$stack) {
\restore_error_handler();
}

if ($errorException && $throw) {
throw $errorException;
}
}

return $errorException;
}

/**
* Stop all active handler
*
* @return void
*/
public static function clean()
{
if (static::$stack) {
\restore_error_handler();
}

static::$stack = [];
}

/**
* Add an error to the stack
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return void
*/
public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
{
$stack = &static::$stack[\count(static::$stack) - 1];
$stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
}
}
224 changes: 224 additions & 0 deletions src/Glob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
<?php declare(strict_types=1);

namespace Stolt\LeanPackage;

use function array_merge;
use function array_unique;
use function defined;
use function glob;
use const GLOB_BRACE;
use const GLOB_ERR;
use const GLOB_MARK;
use const GLOB_NOCHECK;

use const GLOB_NOESCAPE;
use const GLOB_NOSORT;
use const GLOB_ONLYDIR;
use RuntimeException;
use function strlen;
use function strpos;
use function substr;

/**
* Wrapper for glob with fallback if GLOB_BRACE is not available.
*/
abstract class Glob
{
/**#@+
* Glob constants.
*/
public const GLOB_MARK = 0x01;
public const GLOB_NOSORT = 0x02;
public const GLOB_NOCHECK = 0x04;
public const GLOB_NOESCAPE = 0x08;
public const GLOB_BRACE = 0x10;
public const GLOB_ONLYDIR = 0x20;
public const GLOB_ERR = 0x40;
/**#@-*/

/**
* Find pathnames matching a pattern.
*
* @see http://docs.php.net/glob
*
* @param string $pattern
* @param int $flags
* @param bool $forceFallback
* @throws RuntimeException
* @return array
*/
public static function glob($pattern, $flags = 0, $forceFallback = false)
{
if (! \defined('GLOB_BRACE') || $forceFallback) {
return static::fallbackGlob($pattern, $flags);
}

return static::systemGlob($pattern, $flags);
}

/**
* Use the glob function provided by the system.
*
* @param string $pattern
* @param int $flags
* @throws RuntimeException
* @return array
*/
protected static function systemGlob($pattern, $flags)
{
if ($flags) {
$flagMap = [
self::GLOB_MARK => GLOB_MARK,
self::GLOB_NOSORT => GLOB_NOSORT,
self::GLOB_NOCHECK => GLOB_NOCHECK,
self::GLOB_NOESCAPE => GLOB_NOESCAPE,
self::GLOB_BRACE => \defined('GLOB_BRACE') ? GLOB_BRACE : 0,
self::GLOB_ONLYDIR => GLOB_ONLYDIR,
self::GLOB_ERR => GLOB_ERR,
];

$globFlags = 0;

foreach ($flagMap as $internalFlag => $globFlag) {
if ($flags & $internalFlag) {
$globFlags |= $globFlag;
}
}
} else {
$globFlags = 0;
}

ErrorHandler::start();
$res = \glob($pattern, $globFlags);
$err = ErrorHandler::stop();
if ($res === false) {
throw new RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err);
}
return $res;
}

/**
* Expand braces manually, then use the system glob.
*
* @param string $pattern
* @param int $flags
* @throws RuntimeException
* @return array
*/
protected static function fallbackGlob($pattern, $flags)
{
if (! self::flagsIsEqualTo($flags, self::GLOB_BRACE)) {
return static::systemGlob($pattern, $flags);
}

$flags &= ~self::GLOB_BRACE;
$length = \strlen($pattern);
$paths = [];

if ($flags & self::GLOB_NOESCAPE) {
$begin = \strpos($pattern, '{');
} else {
$begin = 0;

while (true) {
if ($begin === $length) {
$begin = false;
break;
} elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) {
$begin++;
} elseif ($pattern[$begin] === '{') {
break;
}

$begin++;
}
}

if ($begin === false) {
return static::systemGlob($pattern, $flags);
}

$next = static::nextBraceSub($pattern, $begin + 1, $flags);

if ($next === null) {
return static::systemGlob($pattern, $flags);
}

$rest = $next;

while ($pattern[$rest] !== '}') {
$rest = static::nextBraceSub($pattern, $rest + 1, $flags);

if ($rest === null) {
return static::systemGlob($pattern, $flags);
}
}

$p = $begin + 1;

while (true) {
$subPattern = \substr($pattern, 0, $begin)
. \substr($pattern, $p, $next - $p)
. \substr($pattern, $rest + 1);

$result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE);

if ($result) {
$paths = \array_merge($paths, $result);
}

if ($pattern[$next] === '}') {
break;
}

$p = $next + 1;
$next = static::nextBraceSub($pattern, $p, $flags);
}

return \array_unique($paths);
}

/**
* Find the end of the sub-pattern in a brace expression.
*
* @param string $pattern
* @param int $begin
* @param int $flags
* @return int|null
*/
protected static function nextBraceSub($pattern, $begin, $flags)
{
$length = \strlen($pattern);
$depth = 0;
$current = $begin;

while ($current < $length) {
$flagsEqualsNoEscape = self::flagsIsEqualTo($flags, self::GLOB_NOESCAPE);

if ($flagsEqualsNoEscape && $pattern[$current] === '\\') {
if (++$current === $length) {
break;
}

$current++;
} else {
if (
($pattern[$current] === '}' && $depth-- === 0)
|| ($pattern[$current] === ',' && $depth === 0)
) {
break;
} elseif ($pattern[$current++] === '{') {
$depth++;
}
}
}

return $current < $length ? $current : null;
}

/** @internal */
public static function flagsIsEqualTo(int $flags, int $otherFlags): bool
{
return (bool) ($flags & $otherFlags);
}
}
4 changes: 4 additions & 0 deletions tests/Commands/ValidateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ public function gitattributesFileWithNoExportIgnoresContentShowsExpectedContent(
#[Ticket('https://github.com/raphaelstolt/lean-package-validator/issues/13')]
public function gitattributesIsInSuggestedFileContent(): void
{
if ((new OsHelper())->isWindows()) {
$this->markTestSkipped('Skipping test on Windows systems');
}

$artifactFilenames = [
'CONDUCT.md',
'phpspec.yml.dist',
Expand Down

0 comments on commit 115bb82

Please sign in to comment.