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(sys_get_temp_dir() . '/') . ".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. p4 is useful for Magento 2 patches
        $patch_levels = $this->getConfig('patch-levels');
        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>' . $comment . '</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;
            }
        }

        // 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");
        }
    }