From cf00c44cc3b6bd2b41fcf31a4283fceb312c8f90 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 22 Dec 2011 13:48:17 -0800 Subject: [PATCH] Decompose TYPE_MULTICOPY changes into a MOVE_HERE plus one or more COPY_HERE Summary: See T419 for some philosophical musing on this. The "ideal" way to represent these changes is two or more COPY_HERE plus a DELETE, but we can't build the DELETE patch yet. Just turn one of the COPY_HERE changes into a MOVE_HERE. While less idealistic, I think this should always work. Test Plan: This seemed to cleanly apply TenXer D265. TenXer guys, can you confirm that this makes it actually patch correctly? Reviewers: jonathanhester, bizrad6, kdeggelman, jungejason, btrahan Reviewed By: jungejason CC: aran, jonathanhester, jungejason, epriestley Maniphest Tasks: T419 Differential Revision: https://secure.phabricator.com/D1270 --- src/parser/bundle/ArcanistBundle.php | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/parser/bundle/ArcanistBundle.php b/src/parser/bundle/ArcanistBundle.php index c9f7b3f6..21db9bf1 100644 --- a/src/parser/bundle/ArcanistBundle.php +++ b/src/parser/bundle/ArcanistBundle.php @@ -207,6 +207,50 @@ class ArcanistBundle { public function toGitPatch() { $result = array(); $changes = $this->getChanges(); + + foreach (array_keys($changes) as $multicopy_key) { + $multicopy_change = $changes[$multicopy_key]; + + $type = $multicopy_change->getType(); + if ($type != ArcanistDiffChangeType::TYPE_MULTICOPY) { + continue; + } + + // Decompose MULTICOPY into one MOVE_HERE and several COPY_HERE because + // we need more information than we have in order to build a delete patch + // and represent it as a bunch of COPY_HERE plus a delete. For details, + // see T419. + + // Basically, MULTICOPY means there are 2 or more corresponding COPY_HERE + // changes, so find one of them arbitrariy and turn it into a MOVE_HERE. + + // TODO: We might be able to do this more cleanly after T230 is resolved. + + $decompose_okay = false; + foreach ($changes as $change_key => $change) { + if ($change->getType() != ArcanistDiffChangeType::TYPE_COPY_HERE) { + continue; + } + if ($change->getOldPath() != $multicopy_change->getCurrentPath()) { + continue; + } + $decompose_okay = true; + $change = clone $change; + $change->setType(ArcanistDiffChangeType::TYPE_MOVE_HERE); + $changes[$change_key] = $change; + + // The multicopy is now fully represented by MOVE_HERE plus one or more + // COPY_HERE, so throw it away. + unset($changes[$multicopy_key]); + break; + } + + if (!$decompose_okay) { + throw new Exception( + "Failed to decompose multicopy changeset in order to generate diff."); + } + } + foreach ($changes as $change) { $type = $change->getType(); $file_type = $change->getFileType();