From c8aa2ad8b02709342000d5ad287c3c4a84f90e9b Mon Sep 17 00:00:00 2001 From: uri Date: Sun, 3 May 2026 14:02:16 -0500 Subject: [PATCH] fix: better updated wp-adapter-copy --- bin/wp-adapter-copy | 229 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 184 insertions(+), 45 deletions(-) diff --git a/bin/wp-adapter-copy b/bin/wp-adapter-copy index 021b7e4..25f09f8 100755 --- a/bin/wp-adapter-copy +++ b/bin/wp-adapter-copy @@ -1,6 +1,5 @@ #!/usr/bin/env php $exclude Top-level names to skip. + * @return array{files: int, dirs: int, bytes: int} + */ +function copyDirectory(string $source, string $target, array $exclude): array +{ + if (!is_dir($target) && !mkdir($target, 0755, true) && !is_dir($target)) { + abort("Could not create directory: {$target}"); + } + + $stats = ['files' => 0, 'dirs' => 0, 'bytes' => 0]; + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST, + ); + + foreach ($iterator as $item) { + $relative = substr($item->getPathname(), strlen($source) + 1); + $topLevel = explode(DIRECTORY_SEPARATOR, $relative)[0]; + + if (in_array($topLevel, $exclude, true)) { + continue; + } + + $dest = $target . DIRECTORY_SEPARATOR . $relative; + + if ($item->isDir()) { + if (!is_dir($dest) && !mkdir($dest, 0755, true) && !is_dir($dest)) { + abort("Could not create directory: {$dest}"); + } + $stats['dirs']++; + } else { + if (!copy($item->getPathname(), $dest)) { + abort("Could not copy file: {$item->getPathname()}"); + } + $stats['files']++; + $stats['bytes'] += $item->getSize(); + } + } + + return $stats; +} + +function formatBytes(int $bytes): string +{ + if ($bytes < 1024) { return "{$bytes} B"; } + if ($bytes < 1_048_576) { return round($bytes / 1024, 1) . ' KB'; } + return round($bytes / 1_048_576, 2) . ' MB'; +} + +// ── Disable colour when not in a TTY or when --no-color is passed ───────────── + +if (!stream_isatty(STDOUT) || in_array('--no-color', $argv ?? [], true)) { + Ansi::disable(); +} + +// ── Configuration ───────────────────────────────────────────────────────────── + $packageRoot = dirname(__DIR__); $pluginRoot = getcwd(); $target = $pluginRoot . '/lib/wp-adapter'; @@ -36,61 +163,73 @@ $exclude = [ 'docs', ]; -echo "wp-adapter-copy\n"; -echo " Source: {$packageRoot}\n"; -echo " Target: {$target}\n\n"; - -// Copy psr/log ^1.1 source (PHP 7.4-safe) into psr-log/. -// psr/log v1.1.x keeps its files under Psr/Log/ (no src/ subdirectory). +// psr/log v1.1.x ships its files under Psr/Log/ (no src/ subdirectory). $psrLogSource = $pluginRoot . '/vendor/psr/log/Psr/Log'; -$psrLogTarget = $target . '/psr-log'; if (!is_dir($psrLogSource)) { - // Fallback: look relative to the package's own vendor entry. - // Works for normal (non-symlinked) Composer installs where - // dirname($packageRoot, 2) resolves to the consuming plugin's vendor/. + // Fallback for non-symlinked Composer installs. $psrLogSource = dirname($packageRoot, 2) . '/psr/log/Psr/Log'; } -copyDirectory($packageRoot, $target, $exclude); +$psrLogTarget = $target . '/psr-log'; -if (is_dir($psrLogSource)) { - copyDirectory($psrLogSource, $psrLogTarget, []); - echo " Copied psr/log source -> psr-log/\n"; -} else { - echo " WARNING: psr/log source not found at {$psrLogSource}\n"; - echo " Run composer install before wp-adapter-copy.\n"; -} +// ── Header ──────────────────────────────────────────────────────────────────── -echo "\nDone. lib/wp-adapter/ is ready.\n"; +blank(); +line(Ansi::bold(Ansi::cyan(' wp-adapter-copy '))); +line(Ansi::muted(' ─────────────────────────────────────────')); +info('source', $packageRoot); +info('target', $target); +blank(); -function copyDirectory(string $source, string $target, array $exclude): void -{ - if (!is_dir($target)) { - mkdir($target, 0755, true); - } +// ── Sanity checks ───────────────────────────────────────────────────────────── - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), - RecursiveIteratorIterator::SELF_FIRST - ); +if (!is_dir($packageRoot)) { + abort("Package root not found: {$packageRoot}"); +} - foreach ($iterator as $item) { - $relative = substr($item->getPathname(), strlen($source) + 1); - $topLevel = explode(DIRECTORY_SEPARATOR, $relative)[0]; +// ── Main copy ───────────────────────────────────────────────────────────────── - if (in_array($topLevel, $exclude, true)) { - continue; - } +$start = microtime(true); - $dest = $target . DIRECTORY_SEPARATOR . $relative; +step(Ansi::cyan('→'), 'Copying wp-adapter source …'); +$mainStats = copyDirectory($packageRoot, $target, $exclude); +step( + Ansi::ok('✔'), + Ansi::green('wp-adapter copied'), + sprintf('%d files, %d dirs, %s', $mainStats['files'], $mainStats['dirs'], formatBytes($mainStats['bytes'])), +); - if ($item->isDir()) { - if (!is_dir($dest)) { - mkdir($dest, 0755, true); - } - } else { - copy($item->getPathname(), $dest); - } - } +blank(); + +// ── psr/log copy ────────────────────────────────────────────────────────────── + +if (is_dir($psrLogSource)) { + step(Ansi::cyan('→'), 'Copying psr/log source …'); + $psrStats = copyDirectory($psrLogSource, $psrLogTarget, []); + step( + Ansi::ok('✔'), + Ansi::green('psr/log copied'), + sprintf('%d files, %s → psr-log/', $psrStats['files'], formatBytes($psrStats['bytes'])), + ); +} else { + warn( + 'psr/log source not found.', + 'Run composer install before wp-adapter-copy.', + ); } + +// ── Footer ──────────────────────────────────────────────────────────────────── + +$elapsed = round((microtime(true) - $start) * 1000); + +blank(); +line(Ansi::muted(' ─────────────────────────────────────────')); +line( + sprintf( + ' %s %s', + Ansi::ok('✔ Done'), + Ansi::muted("lib/wp-adapter/ is ready ({$elapsed}ms)"), + ), +); +blank();