Last active
July 16, 2026 08:57
-
-
Save adamzero1/9be573ed6d1366f7198ede715a135035 to your computer and use it in GitHub Desktop.
Add composer patches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env php | |
| <?php | |
| declare(strict_types=1); | |
| /** | |
| * Merge patch declarations into composer.json extra.patches. | |
| * | |
| * Usage: | |
| * php add_composer_patches.php payload.json [composer.json] | |
| * cat payload.json | php add_composer_patches.php [composer.json] | |
| */ | |
| function fail(string $message, int $code = 1): void | |
| { | |
| fwrite(STDERR, $message . PHP_EOL); | |
| exit($code); | |
| } | |
| function getPayloadJson(array $argv): string | |
| { | |
| if (isset($argv[1]) && $argv[1] !== '') { | |
| if (!is_file($argv[1])) { | |
| fail("Payload file not found: {$argv[1]}"); | |
| } | |
| $contents = file_get_contents($argv[1]); | |
| if ($contents === false) { | |
| fail("Unable to read payload file: {$argv[1]}"); | |
| } | |
| return $contents; | |
| } | |
| $stdin = stream_get_contents(STDIN); | |
| if ($stdin === false || trim($stdin) === '') { | |
| fail('No payload provided. Pass a JSON file path or pipe JSON via stdin.'); | |
| } | |
| return $stdin; | |
| } | |
| function loadJsonFile(string $path): array | |
| { | |
| if (!is_file($path)) { | |
| fail("composer.json not found: {$path}"); | |
| } | |
| $contents = file_get_contents($path); | |
| if ($contents === false) { | |
| fail("Unable to read file: {$path}"); | |
| } | |
| try { | |
| $decoded = json_decode($contents, true, 512, JSON_THROW_ON_ERROR); | |
| } catch (JsonException $e) { | |
| fail("Invalid JSON in {$path}: {$e->getMessage()}"); | |
| } | |
| if (!is_array($decoded)) { | |
| fail("Unexpected JSON structure in {$path}"); | |
| } | |
| return $decoded; | |
| } | |
| function decodePayload(string $json): array | |
| { | |
| try { | |
| $decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR); | |
| } catch (JsonException $e) { | |
| fail('Invalid payload JSON: ' . $e->getMessage()); | |
| } | |
| if (!is_array($decoded) || !isset($decoded['patches']) || !is_array($decoded['patches'])) { | |
| fail('Payload must contain a top-level "patches" object.'); | |
| } | |
| return $decoded['patches']; | |
| } | |
| function normalizePackagePatches(mixed $value): array | |
| { | |
| return is_array($value) ? $value : []; | |
| } | |
| function declarationExists(array $existingDeclarations, string $label, string $path): bool | |
| { | |
| if (array_key_exists($label, $existingDeclarations)) { | |
| return true; | |
| } | |
| return in_array($path, $existingDeclarations, true); | |
| } | |
| $payloadJson = getPayloadJson($argv); | |
| $composerPath = $argv[2] ?? 'composer.json'; | |
| $payloadPatches = decodePayload($payloadJson); | |
| $composer = loadJsonFile($composerPath); | |
| if (!isset($composer['extra']) || !is_array($composer['extra'])) { | |
| $composer['extra'] = []; | |
| } | |
| if (!isset($composer['extra']['patches']) || !is_array($composer['extra']['patches'])) { | |
| $composer['extra']['patches'] = []; | |
| } | |
| foreach ($payloadPatches as $packageName => $declarations) { | |
| if (!is_array($declarations)) { | |
| continue; | |
| } | |
| $existingDeclarations = normalizePackagePatches($composer['extra']['patches'][$packageName] ?? []); | |
| foreach ($declarations as $label => $patchPath) { | |
| if (!is_string($label) || !is_string($patchPath)) { | |
| continue; | |
| } | |
| if (declarationExists($existingDeclarations, $label, $patchPath)) { | |
| echo "declaration already present: {$packageName} :: {$label}" . PHP_EOL; | |
| continue; | |
| } | |
| $existingDeclarations[$label] = $patchPath; | |
| echo "adding declaration: {$packageName} :: {$label}" . PHP_EOL; | |
| } | |
| $composer['extra']['patches'][$packageName] = $existingDeclarations; | |
| } | |
| $encoded = json_encode( | |
| $composer, | |
| JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | |
| ); | |
| if ($encoded === false) { | |
| fail('Failed to encode updated composer.json'); | |
| } | |
| $encoded .= PHP_EOL; | |
| if (file_put_contents($composerPath, $encoded) === false) { | |
| fail("Unable to write file: {$composerPath}"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment