1# quilt.py -- Quilt patch handling 2# Copyright (C) 2011 Canonical Ltd. 3# Copyright (C) 2019 Jelmer Verooij <jelmer@jelmer.uk> 4# 5# Breezy is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# Breezy is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Breezy; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18# 19 20"""Quilt patch handling.""" 21 22import shutil 23import tempfile 24 25from ...i18n import gettext 26from ...mutabletree import MutableTree 27from ...revisiontree import RevisionTree 28from ... import ( 29 errors, 30 merge as _mod_merge, 31 trace, 32 ) 33 34from .quilt import ( 35 QuiltPatches, 36) 37 38 39class NoUnapplyingMerger(_mod_merge.Merge3Merger): 40 41 _no_quilt_unapplying = True 42 43 44def tree_unapply_patches(orig_tree, orig_branch=None, force=False): 45 """Return a tree with patches unapplied. 46 47 :param orig_tree: Tree from which to unapply quilt patches 48 :param orig_branch: Related branch (optional) 49 :return: Tuple with tree and temp path. 50 The tree is a tree with unapplied patches; either a checkout of 51 tree or tree itself if there were no patches 52 """ 53 if orig_branch is None: 54 orig_branch = orig_tree.branch 55 quilt = QuiltPatches.find(orig_tree) 56 if quilt is None: 57 return orig_tree, None 58 applied_patches = quilt.applied() 59 if not applied_patches: 60 # No quilt patches 61 return orig_tree, None 62 63 target_dir = tempfile.mkdtemp() 64 try: 65 if isinstance(orig_tree, MutableTree): 66 tree = orig_branch.create_checkout( 67 target_dir, lightweight=True, 68 revision_id=orig_tree.last_revision(), 69 accelerator_tree=orig_tree) 70 merger = _mod_merge.Merger.from_uncommitted(tree, orig_tree) 71 merger.merge_type = NoUnapplyingMerger 72 merger.do_merge() 73 elif isinstance(orig_tree, RevisionTree): 74 tree = orig_branch.create_checkout( 75 target_dir, lightweight=True, 76 accelerator_tree=orig_tree, revision_id=orig_tree.get_revision_id()) 77 else: 78 trace.mutter("Not sure how to create copy of %r", orig_tree) 79 shutil.rmtree(target_dir) 80 return orig_tree, None 81 trace.mutter("Applying quilt patches for %r in %s", orig_tree, target_dir) 82 quilt = QuiltPatches.find(tree) 83 if quilt is not None: 84 quilt.pop_all(force=force) 85 return tree, target_dir 86 except BaseException: 87 shutil.rmtree(target_dir) 88 raise 89 90 91def post_process_quilt_patches(tree, old_patches, policy): 92 """(Un)apply patches after a merge. 93 94 :param tree: Working tree to work in 95 :param old_patches: List of patches applied before the operation (usually a merge) 96 """ 97 quilt = QuiltPatches.find(tree) 98 if quilt is None: 99 return 100 new_patches = quilt.series() 101 applied_patches = quilt.applied() 102 if policy == "applied": 103 to_apply = [] 104 for p in new_patches: 105 if p in old_patches: 106 continue 107 if p not in applied_patches: 108 to_apply.append(p) 109 if to_apply == []: 110 return 111 trace.note(gettext("Applying %d quilt patches."), len(to_apply)) 112 for p in to_apply: 113 quilt.push(p) 114 elif policy == "unapplied": 115 to_unapply = [] 116 for p in new_patches: 117 if p in old_patches: 118 continue 119 if p in applied_patches: 120 to_unapply.append(p) 121 if to_unapply == []: 122 return 123 trace.note(gettext("Unapplying %d quilt patches."), len(to_unapply)) 124 for p in to_unapply: 125 quilt.pop(p) 126 127 128def start_commit_quilt_patches(tree, policy): 129 quilt = QuiltPatches.find(tree) 130 if quilt is None: 131 return 132 applied_patches = quilt.applied() 133 unapplied_patches = quilt.unapplied() 134 if policy is None: 135 # No policy set - just warn about having both applied and unapplied 136 # patches. 137 if applied_patches and unapplied_patches: 138 trace.warning( 139 gettext("Committing with %d patches applied and %d patches unapplied."), 140 len(applied_patches), len(unapplied_patches)) 141 elif policy == "applied": 142 quilt.push_all() 143 elif policy == "unapplied": 144 quilt.pop_all() 145