diff --git a/src/Patches.php b/src/Patches.php index 31f5225c..dc5d5e23 100644 --- a/src/Patches.php +++ b/src/Patches.php @@ -525,34 +525,65 @@ protected function arrayMergeRecursiveDistinct(array $array1, array $array2) { * TRUE if patch was applied, FALSE otherwise. */ protected function applyPatchWithGit($install_path, $patch_levels, $filename) { - // Do not use git apply unless the install path is itself a git repo + // "git apply" works only if the install path is itself a git repo + // @see https://github.com/cweagans/composer-patches/issues/148 // @see https://stackoverflow.com/a/27283285 - if (!is_dir($install_path . '/.git')) { - return FALSE; - } + $filesToUnlink = []; + try { + if (!is_dir($install_path . '/.git')) { + // Simulate "git init" to fix the "git apply" limitation. + // @see https://github.com/cweagans/composer-patches/issues/294 + if (file_exists($install_path . '/.git') || !mkdir($install_path . '/.git')) { + return false; + } + $filesToUnlink[] = $install_path . '/.git'; - $patched = FALSE; - foreach ($patch_levels as $patch_level) { - if ($this->io->isVerbose()) { - $comment = 'Testing ability to patch with git apply.'; - $comment .= ' This command may produce errors that can be safely ignored.'; - $this->io->write('' . $comment . ''); - } - $checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename); - $output = $this->executor->getErrorOutput(); - if (substr($output, 0, 7) == 'Skipped') { - // Git will indicate success but silently skip patches in some scenarios. - // - // @see https://github.com/cweagans/composer-patches/pull/165 - $checked = FALSE; + if (!mkdir($install_path . '/.git/objects')) { + return false; + } + $filesToUnlink[] = $install_path . '/.git/objects'; + + if (!mkdir($install_path . '/.git/refs')) { + return false; + } + $filesToUnlink[] = $install_path . '/.git/refs'; + + if (!file_put_contents($install_path . '/.git/HEAD', "ref: refs/heads/master\n")) { + return false; + } + $filesToUnlink[] = $install_path . '/.git/HEAD'; } - if ($checked) { - // Apply the first successful style. - $patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename); - break; + + $patched = FALSE; + foreach ($patch_levels as $patch_level) { + if ($this->io->isVerbose()) { + $comment = 'Testing ability to patch with git apply.'; + $comment .= ' This command may produce errors that can be safely ignored.'; + $this->io->write('' . $comment . ''); + } + $checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename); + $output = $this->executor->getErrorOutput(); + if (substr($output, 0, 7) == 'Skipped') { + // Git will indicate success but silently skip patches in some scenarios. + // @see https://github.com/cweagans/composer-patches/pull/165 + $checked = FALSE; + } + if ($checked) { + // Apply the first successful style. + $patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename); + break; + } } + return $patched; + } finally { + foreach (array_reverse($filesToUnlink) as $f) { + if (is_dir($f)) { + rmdir($f); + } else { + unlink($f); + } + } } - return $patched; } }