Skip to content
Draft
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
14 changes: 7 additions & 7 deletions .github/workflows/commit-built-file-changes.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Commits all missed changes to built files back to pull request branches.
name: Commit Built File Changes (PRs)

on:
workflow_run:
workflows:
- 'Check Built Files (PRs)'
- 'Test Default Themes & Create ZIPs'
types:
- completed
# on:
# workflow_run:
# workflows:
# - 'Check Built Files (PRs)'
# - 'Test Default Themes & Create ZIPs'
# types:
# - completed

# Cancels all previous workflow runs for pull requests that have not completed.
concurrency:
Expand Down
130 changes: 130 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,147 @@
},
"require-dev": {
"composer/ca-bundle": "1.5.8",
"james-heinrich/getid3": "1.9.23",
"paragonie/sodium_compat": "1.23.0",
"phpmailer/phpmailer": "6.11.1",
"rmccue/requests": "2.0.11",
"simplepie/simplepie": "1.9.0",
"squizlabs/php_codesniffer": "3.13.2",
"wp-coding-standards/wpcs": "~3.2.0",
"phpcompatibility/phpcompatibility-wp": "~2.1.3",
"wordpress/custom-installer-plugin": "@dev",
"yoast/phpunit-polyfills": "^1.1.0"
},
"repositories": [
{
"type": "path",
"url": "tools/composer"
}
],
"config": {
"allow-plugins": {
"wordpress/custom-installer-plugin": true,
"dealerdirect/phpcodesniffer-composer-installer": true
},
"lock": false
},
"extra": {
"installer-paths": {
"james-heinrich/getid3": {
"target": "src/wp-includes/ID3",
"source": "getid3",
"ignore": [
"extension.cache.dbm.php",
"extension.cache.mysql.php",
"extension.cache.mysqli.php",
"extension.cache.sqlite3.php",
"module.archive.7zip.php",
"module.archive.gzip.php",
"module.archive.hpk.php",
"module.archive.rar.php",
"module.archive.szip.php",
"module.archive.tar.php",
"module.archive.xz.php",
"module.archive.zip.php",
"module.audio-video.bink.php",
"module.audio-video.ivf.php",
"module.audio-video.mpeg.php",
"module.audio-video.nsv.php",
"module.audio-video.real.php",
"module.audio-video.swf.php",
"module.audio-video.ts.php",
"module.audio-video.wtv.php",
"module.audio.aa.php",
"module.audio.aac.php",
"module.audio.amr.php",
"module.audio.au.php",
"module.audio.avr.php",
"module.audio.bonk.php",
"module.audio.dsdiff.php",
"module.audio.dsf.php",
"module.audio.dss.php",
"module.audio.la.php",
"module.audio.lpac.php",
"module.audio.midi.php",
"module.audio.mod.php",
"module.audio.monkey.php",
"module.audio.mpc.php",
"module.audio.optimfrog.php",
"module.audio.rkau.php",
"module.audio.shorten.php",
"module.audio.tak.php",
"module.audio.tta.php",
"module.audio.voc.php",
"module.audio.vqf.php",
"module.audio.wavpack.php",
"module.graphic.bmp.php",
"module.graphic.efax.php",
"module.graphic.gif.php",
"module.graphic.jpg.php",
"module.graphic.pcd.php",
"module.graphic.png.php",
"module.graphic.svg.php",
"module.graphic.tiff.php",
"module.misc.cue.php",
"module.misc.exe.php",
"module.misc.iso.php",
"module.misc.msoffice.php",
"module.misc.par2.php",
"module.misc.pdf.php",
"module.misc.torrent.php",
"module.tag.nikon-nctg.php",
"module.tag.xmp.php",
"write.apetag.php",
"write.id3v1.php",
"write.id3v2.php",
"write.lyrics3.php",
"write.metaflac.php",
"write.php",
"write.real.php",
"write.vorbiscomment.php"
]
},
"paragonie/sodium_compat": {
"target": "src/wp-includes/sodium_compat",
"ignore": [
"README.md",
"composer-php52.json"
]
},
"phpmailer/phpmailer": {
"target": "src/wp-includes/PHPMailer",
"source": "src"
},
"rmccue/requests": {
"target": "src/wp-includes/Requests",
"ignore": [
".editorconfig",
"certificates",
"CHANGELOG.md",
"composer.json",
"library/Deprecated.php",
"library/README.md",
"LICENSE",
"README.md"
],
"replace": {
"library/Requests.php": "Requests.php"
}
},
"simplepie/simplepie": {
"target": "src/wp-includes/SimplePie",
"ignore": [
"CHANGELOG.md",
"composer.json",
"db.sql",
"LICENSES",
"phpstan.dist.neon",
"README.markdown",
"utils/PHPStan"
]
}
}
},
"scripts": {
"compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source",
"format": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf --report=summary,source",
Expand Down
17 changes: 17 additions & 0 deletions tools/composer/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "wordpress/custom-installer-plugin",
"description": "Custom Composer installer plugin for WordPress vendor dependencies",
"type": "composer-plugin",
"license": "GPL-2.0-or-later",
"require": {
"composer-plugin-api": "^2.0"
},
"autoload": {
"psr-4": {
"WordPress\\Composer\\": "src/"
}
},
"extra": {
"class": "WordPress\\Composer\\CustomInstallerPlugin"
}
}
12 changes: 12 additions & 0 deletions tools/composer/replacements/Requests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
/**
* Loads the old Requests class file when the autoloader
* references the original PSR-0 Requests class.
*
* @deprecated 6.2.0
* @package WordPress
* @subpackage Requests
* @since 6.2.0
*/

include_once ABSPATH . WPINC . '/class-requests.php';
199 changes: 199 additions & 0 deletions tools/composer/src/CustomInstaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<?php
/**
* Installer for handling custom installation paths.
*/

namespace WordPress\Composer;

use Composer\PartialComposer;
use Composer\IO\IOInterface;
use Composer\Installer\LibraryInstaller;
use Composer\Installer\BinaryInstaller;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Util\Filesystem;
use React\Promise\PromiseInterface;

/**
* Installer class.
*/
final class CustomInstaller extends LibraryInstaller {
/**
* Custom installer paths configuration.
*/
private array $installerPaths = array();

/**
* Initializes library installer.
*/
public function __construct(
IOInterface $io,
PartialComposer $composer,
?string $type = 'library',
?Filesystem $filesystem = null,
?BinaryInstaller $binaryInstaller = null
) {
parent::__construct( $io, $composer, $type, $filesystem, $binaryInstaller );

$this->installerPaths = $this->composer->getPackage()->getExtra()['installer-paths'];
}

/**
* Check if this installer supports the given package type.
*
* @param string $packageType The package type.
* @return bool
*/
public function supports( $packageType ) {
return true;
}

/**
* Get the installation path for a package.
*
* @param PackageInterface $package The package.
* @return string The installation path.
*/
public function getInstallPath( PackageInterface $package ) {
$packageName = $package->getName();

if ( ! isset( $this->installerPaths[ $packageName ] ) ) {
return parent::getInstallPath( $package );
}

return realpath( getcwd() ) . '/' . $this->installerPaths[ $packageName ]['target'];
}

/**
* Install a package.
*
* @param InstalledRepositoryInterface $repo The installed repository.
* @param PackageInterface $package The package to install.
* @return PromiseInterface|null
*/
public function install( InstalledRepositoryInterface $repo, PackageInterface $package ) {
$installer = parent::install( $repo, $package );

if ( $installer instanceof PromiseInterface ) {
return $installer->then( fn() => $this->modifyPaths( $package ) );
}

$this->modifyPaths( $package );
return null;
}

/**
* Update a package.
*
* @param InstalledRepositoryInterface $repo The installed repository.
* @param PackageInterface $initial The initial package.
* @param PackageInterface $target The target package.
* @return PromiseInterface|null
*/
public function update( InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target ) {
$updater = parent::update( $repo, $initial, $target );

if ( $updater instanceof PromiseInterface ) {
return $updater->then( fn() => $this->modifyPaths( $target ) );
}

$this->modifyPaths( $target );
return null;
}

/**
* Modify installation paths based on source subdirectory and ignore patterns.
*
* @param PackageInterface $package The package.
*/
private function modifyPaths( PackageInterface $package ): void {
$installPath = $this->getInstallPath( $package );

$this->applySourceSubdirectory( $package, $installPath );
$this->applyReplacements( $package, $installPath );
$this->applyIgnorePatterns( $package, $installPath );
}

/**
* Apply file replacements from custom replacement files.
*
* @param PackageInterface $package The package.
* @param string $installPath The installation path.
*/
private function applyReplacements( PackageInterface $package, string $installPath ): void {
$packageName = $package->getName();

if ( ! isset( $this->installerPaths[ $packageName ]['replace'] ) ) {
return;
}

$filesystem = new Filesystem();
$replacementsDir = realpath( getcwd() ) . '/tools/composer/replacements';

foreach ( $this->installerPaths[ $packageName ]['replace'] as $target => $source ) {
$sourcePath = $replacementsDir . '/' . $source;

if ( ! file_exists( $sourcePath ) ) {
throw new \RuntimeException( "Replacement file 'tools/composer/replacements/{$source}' does not exist for package '{$packageName}'." );
}

$filesystem->copy( $sourcePath, $installPath . '/' . $target );
}
}

/**
* Apply ignore patterns to remove unwanted files after installation.
*
* @param PackageInterface $package The package.
* @param string $installPath The installation path.
*/
private function applyIgnorePatterns( PackageInterface $package, string $installPath ): void {
$packageName = $package->getName();

if ( ! isset( $this->installerPaths[ $packageName ]['ignore'] ) ) {
return;
}

$filesystem = new Filesystem();

foreach ( $this->installerPaths[ $packageName ]['ignore'] as $pattern ) {
$matches = glob( $installPath . '/' . $pattern );

if ( empty( $matches ) ) {
throw new \RuntimeException( "Failed to glob pattern '{$pattern}' in package '{$package->getName()}'." );
}

foreach ( $matches as $path ) {
$filesystem->remove( $path );
}
}
}

/**
* Apply source subdirectory to flatten directory structure.
*
* @param PackageInterface $package The package.
* @param string $installPath The installation path.
*/
private function applySourceSubdirectory( PackageInterface $package, string $installPath ): void {
$packageName = $package->getName();

if ( ! isset( $this->installerPaths[ $packageName ]['source'] ) ) {
return;
}

$sourceSubdir = $this->installerPaths[ $packageName ]['source'];
$sourceDir = $installPath . '/' . $sourceSubdir;

if ( ! is_dir( $sourceDir ) ) {
throw new \RuntimeException( "Source directory '{$sourceSubdir}' does not exist in package '{$packageName}'." );
}

$filesystem = new Filesystem();
$tempDir = $installPath . '_temp';

$filesystem->rename( $sourceDir, $tempDir );
$filesystem->removeDirectory( $installPath );
$filesystem->rename( $tempDir, $installPath );
}
}
Loading
Loading