protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, $patch_url)
{
// Local patch file.
if (file_exists($patch_url)) {
$filename = realpath($patch_url);
} else {
// Generate random (but not cryptographically so) filename.
$filename = uniqid("/tmp/") . ".patch";
// Download file from remote filesystem to this location.
$hostname = parse_url($patch_url, PHP_URL_HOST);
$downloader->copy($hostname, $patch_url, $filename, FALSE);
}
// Modified from drush6:make.project.inc
$patched = FALSE;
// The order here is intentional. p1 is most likely to apply with git apply.
// p0 is next likely. p2 is extremely unlikely, but for some special cases,
// it might be useful.
$patch_levels = array('-p1', '-p0', '-p2');
foreach ($patch_levels as $patch_level) {
$checked = $this->executeCommand('cd %s && GIT_DIR=. git apply --check %s %s', $install_path, $patch_level, $filename);
if ($checked) {
// Apply the first successful style.
$patched = $this->executeCommand('cd %s && GIT_DIR=. git apply %s %s', $install_path, $patch_level, $filename);
break;
}
}
// In some rare cases, git will fail to apply a patch, fallback to using
// the 'patch' command.
if (!$patched) {
foreach ($patch_levels as $patch_level) {
// --no-backup-if-mismatch here is a hack that fixes some
// differences between how patch works on windows and unix.
if ($patched = $this->executeCommand("patch %s --no-backup-if-mismatch -d %s < %s", $patch_level, $install_path, $filename)) {
break;
}
}
}
// Clean up the temporary patch file.
if (isset($hostname)) {
unlink($filename);
}
// If the patch *still* isn't applied, then give up and throw an Exception.
// Otherwise, let the user know it worked.
if (!$patched) {
throw new \Exception("Cannot apply patch {$patch_url}");
}
}