Skip to content
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

[Scoper] Using different scoper.php for php 7.0 #6295

Merged
merged 5 commits into from
May 2, 2021
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/build_scoped_rector_php70.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Build Scoped Rector PHP 7.0
on:
push:
branches:
- main
- never
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temporary disable scoped 7.0

tags:
- '*'

Expand Down Expand Up @@ -44,7 +44,7 @@ jobs:
- run: sh build/downgrade-rector-php70.sh rector-build-php70

# 3. prefix classes
- run: sh build/build-rector-scoped.sh rector-build-php70 rector-prefixed-downgraded-php70
- run: sh build/build-rector-scoped-php70.sh rector-build-php70 rector-prefixed-downgraded-php70

# 4. lint the code for PHP 7.0 - this must happen here, as setup-php allows only one PHP version switch: https://github.com/shivammathur/setup-php/issues/434
-
Expand Down
59 changes: 59 additions & 0 deletions build/build-rector-scoped-php70.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash

# see https://stackoverflow.com/questions/66644233/how-to-propagate-colors-from-bash-script-to-github-action?noredirect=1#comment117811853_66644233
export TERM=xterm-color

# show errors
set -e

# script fails if trying to access to an undefined variable
set -u


# functions
note()
{
MESSAGE=$1;

printf "\n";
echo "[NOTE] $MESSAGE";
printf "\n";
}


# configure here
BUILD_DIRECTORY=$1
RESULT_DIRECTORY=$2

# ---------------------------

note "Starts"

# this will remove dependency on dev packages that are imported in phpstan.neon
rm -f "$BUILD_DIRECTORY/phpstan-for-rector.neon"

# 2. scope it
note "Running scoper to $RESULT_DIRECTORY"
wget https://github.com/humbug/php-scoper/releases/download/0.14.0/php-scoper.phar -N --no-verbose

# Work around possible PHP memory limits
php -d memory_limit=-1 php-scoper.phar add-prefix preload.php bin config src packages rules vendor composer.json --output-dir "../$RESULT_DIRECTORY" --config scoper-php70.php --force --ansi --working-dir "$BUILD_DIRECTORY"


# note "Dumping Composer Autoload"
composer dump-autoload --working-dir "$RESULT_DIRECTORY" --ansi --classmap-authoritative --no-dev

php "$BUILD_DIRECTORY/build/build-preload.php" $RESULT_DIRECTORY

rm -rf "$BUILD_DIRECTORY"


# copy metafiles needed for release
note "Copy metafiles like composer.json, .github etc to repository"
rm -f "$RESULT_DIRECTORY/composer.json"

# make bin/rector runnable without "php"
chmod 777 "$RESULT_DIRECTORY/bin/rector"
chmod 777 "$RESULT_DIRECTORY/bin/rector.php"

note "Finished"
199 changes: 199 additions & 0 deletions scoper-php70.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<?php

declare(strict_types=1);

use Nette\Utils\DateTime;
use Nette\Utils\Strings;
use Rector\Compiler\PhpScoper\StaticEasyPrefixer;
use Rector\Compiler\Unprefixer;
use Rector\Compiler\ValueObject\ScoperOption;

require_once __DIR__ . '/vendor/autoload.php';

// [BEWARE] this path is relative to the root and location of this file
$filePathsToRemoveNamespace = [
// @see https://github.com/rectorphp/rector/issues/2852#issuecomment-586315588
'vendor/symfony/deprecation-contracts/function.php',
// it would make polyfill function work only with namespace = brokes
'vendor/symfony/polyfill-ctype/bootstrap.php',
'vendor/symfony/polyfill-intl-normalizer/bootstrap.php',
'vendor/symfony/polyfill-intl-grapheme/bootstrap.php',
'vendor/symfony/polyfill-mbstring/bootstrap.php',
'vendor/symfony/polyfill-php80/bootstrap.php',
'vendor/symfony/polyfill-php74/bootstrap.php',
'vendor/symfony/polyfill-php73/bootstrap.php',
'vendor/symfony/polyfill-php72/bootstrap.php',
'vendor/symfony/polyfill-uuid/bootstrap.php',
];

// remove phpstan, because it is already prefixed in its own scope

$dateTime = DateTime::from('now');
$timestamp = $dateTime->format('Ymd');

// see https://github.com/humbug/php-scoper
return [
ScoperOption::PREFIX => 'RectorPrefix' . $timestamp,
ScoperOption::WHITELIST => StaticEasyPrefixer::getExcludedNamespacesAndClasses(),
// ScoperOption::FILES_WHITELIST => [
// // composer versions
// '../../vendor/composer/InstalledVersions.php'
// ],
ScoperOption::PATCHERS => [
// [BEWARE] $filePath is absolute!

// fixes https://github.com/rectorphp/rector-prefixed/runs/2143717534
function (string $filePath, string $prefix, string $content) use ($filePathsToRemoveNamespace): string {
// @see https://regex101.com/r/0jaVB1/1
$prefixedNamespacePattern = '#^namespace (.*?);$#m';

foreach ($filePathsToRemoveNamespace as $filePathToRemoveNamespace) {
if (Strings::endsWith($filePath, $filePathToRemoveNamespace)) {
return Strings::replace($content, $prefixedNamespacePattern, '');
}
}

return $content;
},

function (string $filePath, string $prefix, string $content): string {
if (! Strings::endsWith($filePath, 'vendor/composer/package-versions-deprecated/src/PackageVersions/Versions.php')) {
return $content;
}

// see https://regex101.com/r/v8zRMm/1
return Strings::replace(
$content, '
#' . $prefix . '\\\\Composer\\\\InstalledVersions#',
'Composer\InstalledVersions'
);
},

function (string $filePath, string $prefix, string $content): string {
if (! Strings::contains($content, $prefix . '\Composer\Plugin')) {
return $content;
}

return Strings::replace(
$content, '
#' . $prefix . '\\\\Composer\\\\Plugin#',
'Composer\Plugin'
);
},

function (string $filePath, string $prefix, string $content): string {
if (! Strings::contains($content, $prefix . '\Composer\EventDispatcher')) {
return $content;
}

return Strings::replace(
$content, '
#' . $prefix . '\\\\Composer\\\\EventDispatcher#',
'Composer\EventDispatcher'
);
},

// get version for prefixed version
function (string $filePath, string $prefix, string $content): string {
if (! Strings::endsWith($filePath, 'src/Configuration/Configuration.php')) {
return $content;
}

// @see https://regex101.com/r/gLefQk/1
return Strings::replace(
$content, '#\(\'rector\/rector\'\)#',
"('rector/rector-prefixed')"
);
},

// un-prefix composer plugin
function (string $filePath, string $prefix, string $content): string {
if (! Strings::endsWith($filePath, 'vendor/rector/rector-installer/src/Plugin.php')) {
return $content;
}

// see https://regex101.com/r/v8zRMm/1
return Strings::replace($content, '#' . $prefix . '\\\\Composer\\\\#', 'Composer\\');
},

// fixes https://github.com/rectorphp/rector/issues/6007
function (string $filePath, string $prefix, string $content): string {
if (! Strings::contains($filePath, 'vendor/')) {
return $content;
}

// @see https://regex101.com/r/lBV8IO/2
$fqcnReservedPattern = sprintf('#(\\\\)?%s\\\\(parent|self|static)#m', $prefix);
$matches = Strings::matchAll($content, $fqcnReservedPattern);

if (! $matches) {
return $content;
}

foreach ($matches as $match) {
$content = str_replace($match[0], $match[2], $content);
}

return $content;
},


function (string $filePath, string $prefix, string $content): string {
if (
! Strings::endsWith($filePath, 'packages/Testing/PHPUnit/AbstractTestCase.php')
&& ! Strings::endsWith($filePath, 'packages/Testing/PHPUnit/AbstractRectorTestCase.php')
) {
return $content;
}

// un-prefix
return Strings::replace(
$content,
'#' . $prefix . '\\\\PHPUnit\\\\Framework\\\\TestCase#',
'PHPUnit\Framework\TestCase'
);
},

// fixes https://github.com/rectorphp/rector/issues/6010 + test case prefix
function (string $filePath, string $prefix, string $content): string {
// @see https://regex101.com/r/bA1nQa/1
if (! Strings::match($filePath, '#vendor/symfony/polyfill-php\d{2}/Resources/stubs#')) {
return $content;
}

// @see https://regex101.com/r/x5Ukrx/1
$namespace = sprintf('#namespace %s;#m', $prefix);
return Strings::replace($content, $namespace);
},

// unprefix string classes, as they're string on purpose - they have to be checked in original form, not prefixed
function (string $filePath, string $prefix, string $content): string {
// skip vendor, expect rector packages
if (Strings::contains($filePath, 'vendor/') && ! Strings::contains($filePath, 'vendor/rector')) {
return $content;
}

// skip bin/rector.php for composer autoload class
if (Strings::endsWith($filePath, 'bin/rector.php')) {
return $content;
}

return Unprefixer::unprefixQuoted($content, $prefix);
},

// scoper missed PSR-4 autodiscovery in Symfony
function (string $filePath, string $prefix, string $content): string {
// scoper missed PSR-4 autodiscovery in Symfony
if (! Strings::endsWith($filePath, 'config.php') && ! Strings::endsWith($filePath, 'services.php')) {
return $content;
}

// skip "Rector\\" namespace
if (Strings::contains($content, '$services->load(\'Rector')) {
return $content;
}

return Strings::replace($content, '#services\->load\(\'#', 'services->load(\'' . $prefix . '\\');
},
],
];
24 changes: 0 additions & 24 deletions scoper.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,6 @@ function (string $filePath, string $prefix, string $content): string {
);
},

function (string $filePath, string $prefix, string $content): string {
if (! Strings::contains($content, $prefix . '\Composer\Plugin')) {
return $content;
}

return Strings::replace(
$content, '
#' . $prefix . '\\\\Composer\\\\Plugin#',
'Composer\Plugin'
);
},

function (string $filePath, string $prefix, string $content): string {
if (! Strings::contains($content, $prefix . '\Composer\EventDispatcher')) {
return $content;
}

return Strings::replace(
$content, '
#' . $prefix . '\\\\Composer\\\\EventDispatcher#',
'Composer\EventDispatcher'
);
},

// get version for prefixed version
function (string $filePath, string $prefix, string $content): string {
if (! Strings::endsWith($filePath, 'src/Configuration/Configuration.php')) {
Expand Down