~abentley/bzrtools/bzrtools.dev

749.1.6 by Aaron Bentley
Add --store option for zap.
1
# Copyright (C) 2006-2007, 2010-2011 Aaron Bentley <aaron@aaronbentley.com>
787 by Aaron Bentley
Fix zap command for 2.6/7
2
# Copyright (C) 2013 Aaron Bentley <aaron@aaronbentley.com>
749.1.6 by Aaron Bentley
Add --store option for zap.
3
# Copyright (C) 2007 Charlie Shepherd <masterdriverz@gentoo.org>
4
# Copyright (C) 2011 Canonical Ltd.
5
#
6
#    This program is free software; you can redistribute it and/or modify
7
#    it under the terms of the GNU General Public License as published by
8
#    the Free Software Foundation; either version 2 of the License, or
9
#    (at your option) any later version.
10
#
11
#    This program is distributed in the hope that it will be useful,
12
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
#    GNU General Public License for more details.
15
#
16
#    You should have received a copy of the GNU General Public License
17
#    along with this program; if not, write to the Free Software
18
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
345 by Aaron Bentley
Added zap command
20
from shutil import rmtree
21
554 by Aaron Bentley
Adjust to use NULL_REVISION in API
22
from bzrlib import (
23
    bzrdir,
24
    revision as _mod_revision,
25
    )
401 by Aaron Bentley
Add check whether branch has unique revisions
26
from bzrlib.branch import Branch
758 by Aaron Bentley
Allow zap --branch --store if no uncommitted changes.
27
from bzrlib.errors import BzrCommandError, NoWorkingTree, NotBranchError
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
28
from bzrlib import registry
345 by Aaron Bentley
Added zap command
29
from bzrlib.workingtree import WorkingTree
30
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
31
from errors import (NotCheckout, UncommittedCheckout, ParentMissingRevisions,
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
32
                    NoParent)
787 by Aaron Bentley
Fix zap command for 2.6/7
33
from bzrlib.plugins.bzrtools.bzrtools import read_locked
345 by Aaron Bentley
Added zap command
34
35
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
36
class AllowChanged(object):
37
38
    @classmethod
39
    def check_changed(klass, wt, remove_branch):
40
        pass
41
42
43
class CheckChanged(object):
44
45
    @classmethod
46
    def check_changed(klass, wt, remove_branch):
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
47
        delta = wt.changes_from(wt.basis_tree(), want_unchanged=False)
48
        if delta.has_changed():
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
49
            klass.handle_changed(wt, remove_branch)
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
50
51
52
class HaltOnChange(CheckChanged):
53
54
    @staticmethod
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
55
    def handle_changed(wt, remove_branch):
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
56
        raise UncommittedCheckout()
57
58
59
class StoreChanges(CheckChanged):
60
61
    @staticmethod
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
62
    def handle_changed(wt, remove_branch):
749.1.6 by Aaron Bentley
Add --store option for zap.
63
        from bzrlib.plugins.pipeline.pipeline import PipeManager
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
64
        if remove_branch:
758 by Aaron Bentley
Allow zap --branch --store if no uncommitted changes.
65
            raise BzrCommandError('Cannot store changes in deleted branch.')
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
66
        PipeManager.from_checkout(wt).store_uncommitted()
67
68
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
69
change_policy_registry = registry.Registry()
70
71
72
change_policy_registry.register('force', AllowChanged,
73
                                'Delete tree even if contents are modified.')
74
75
76
change_policy_registry.register('store', StoreChanges,
77
                                'Store changes in branch.  (Requires'
78
                                ' bzr-pipeline.)')
79
80
749.1.10 by Aaron Bentley
Cleaner default handling.
81
change_policy_registry.register('check', HaltOnChange,
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
82
                                'Stop if tree contents are modified.')
83
84
749.1.10 by Aaron Bentley
Cleaner default handling.
85
change_policy_registry.default_key = 'check'
86
87
787 by Aaron Bentley
Fix zap command for 2.6/7
88
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
89
def zap(path, remove_branch=False, policy=HaltOnChange):
345 by Aaron Bentley
Added zap command
90
    try:
544.1.1 by Aaron Bentley
Zap doesn't recommend upgrading trees it's about to delete
91
        wt = bzrdir.BzrDir.open(path).open_workingtree(path,
92
                                                       recommend_upgrade=False)
345 by Aaron Bentley
Added zap command
93
    except (NoWorkingTree, NotBranchError):
94
        raise NotCheckout(path)
95
    tree_base = wt.bzrdir.transport.base
355.1.1 by Aaron Bentley
Provided --branch option to for zapping branches
96
    branch = wt.branch
97
    branch_base = branch.bzrdir.transport.base
345 by Aaron Bentley
Added zap command
98
    if tree_base == branch_base:
99
        raise NotCheckout(path)
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
100
    policy.check_changed(wt, remove_branch)
401 by Aaron Bentley
Add check whether branch has unique revisions
101
    if remove_branch:
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
102
        parent_loc = branch.get_parent()
103
        if parent_loc is None:
104
            raise NoParent()
787 by Aaron Bentley
Fix zap command for 2.6/7
105
        with read_locked(Branch.open(parent_loc)) as parent:
106
            last_revision = _mod_revision.ensure_null(parent.last_revision())
107
            if last_revision != _mod_revision.NULL_REVISION:
108
                graph = parent.repository.get_graph()
109
                heads = graph.heads([last_revision, branch.last_revision()])
110
                if branch.last_revision() in heads:
111
                    raise ParentMissingRevisions(branch.get_parent())
345 by Aaron Bentley
Added zap command
112
    rmtree(path)
355.1.1 by Aaron Bentley
Provided --branch option to for zapping branches
113
    if remove_branch:
114
        t = branch.bzrdir.transport
115
        while t.base != branch_base:
116
            t = t.clone('..')
117
        t = t.clone('..')
118
        t.delete_tree('')
345 by Aaron Bentley
Added zap command
119
120
121
def test_suite():
122
    import os
123
    from unittest import makeSuite
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
124
787 by Aaron Bentley
Fix zap command for 2.6/7
125
    from bzrlib.tests import TestCaseWithTransport
345 by Aaron Bentley
Added zap command
126
749.1.6 by Aaron Bentley
Add --store option for zap.
127
128
    class PipelinePluginFeature:
129
130
        @staticmethod
131
        def available():
132
            try:
133
                import bzrlib.plugins.pipeline
134
            except ImportError:
135
                return False
136
            else:
137
                return True
138
139
787 by Aaron Bentley
Fix zap command for 2.6/7
140
    class TestZap(TestCaseWithTransport):
345 by Aaron Bentley
Added zap command
141
142
        def make_checkout(self):
743 by Aaron Bentley
Remove unneeded imports
143
            wt = bzrdir.BzrDir.create_standalone_workingtree('source')
742 by Aaron Bentley
Fix zap tests.
144
            return wt.branch.create_checkout('checkout', lightweight=True)
345 by Aaron Bentley
Added zap command
145
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
146
        def make_checkout2(self):
147
            wt = self.make_checkout()
148
            wt2 = wt.branch.bzrdir.sprout('source2').open_workingtree()
742 by Aaron Bentley
Fix zap tests.
149
            return wt2.branch.create_checkout('checkout2', lightweight=True)
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
150
345 by Aaron Bentley
Added zap command
151
        def test_is_checkout(self):
152
            self.assertRaises(NotCheckout, zap, '.')
743 by Aaron Bentley
Remove unneeded imports
153
            wt = bzrdir.BzrDir.create_standalone_workingtree('.')
345 by Aaron Bentley
Added zap command
154
            self.assertRaises(NotCheckout, zap, '.')
155
156
        def test_zap_works(self):
157
            self.make_checkout()
158
            self.assertIs(True, os.path.exists('checkout'))
159
            zap('checkout')
160
            self.assertIs(False, os.path.exists('checkout'))
355.1.1 by Aaron Bentley
Provided --branch option to for zapping branches
161
            self.assertIs(True, os.path.exists('source'))
162
743 by Aaron Bentley
Remove unneeded imports
163
        def test_zap_branch(self):
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
164
            self.make_checkout2()
355.1.1 by Aaron Bentley
Provided --branch option to for zapping branches
165
            base = WorkingTree.open('checkout').branch.base
166
            self.assertIs(True, os.path.exists('checkout'))
407 by Aaron Bentley
Fix zap for checkouts of branches with no parents
167
            self.assertRaises(NoParent, zap, 'checkout', remove_branch=True)
168
            self.assertIs(True, os.path.exists('checkout'))
169
            self.assertIs(True, os.path.exists('source'))
170
            zap('checkout2', remove_branch=True)
171
            self.assertIs(False, os.path.exists('checkout2'))
172
            self.assertIs(False, os.path.exists('source2'))
345 by Aaron Bentley
Added zap command
173
174
        def test_checks_modified(self):
175
            checkout = self.make_checkout()
176
            os.mkdir('checkout/foo')
177
            checkout.add('foo')
178
            self.assertRaises(UncommittedCheckout, zap, 'checkout')
179
            checkout.commit('commit changes to branch')
180
            zap('checkout')
181
749.1.6 by Aaron Bentley
Add --store option for zap.
182
        def make_modified_checkout(self):
183
            checkout = self.make_checkout()
184
            os.mkdir('checkout/foo')
185
            checkout.add('foo')
186
            return checkout
187
573.1.3 by Aaron Bentley
Allow zap --force to delete modified checkouts
188
        def test_allow_modified(self):
749.1.6 by Aaron Bentley
Add --store option for zap.
189
            self.make_modified_checkout()
573.1.3 by Aaron Bentley
Allow zap --force to delete modified checkouts
190
            self.assertRaises(UncommittedCheckout, zap, 'checkout')
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
191
            zap('checkout', policy=AllowChanged)
573.1.3 by Aaron Bentley
Allow zap --force to delete modified checkouts
192
749.1.6 by Aaron Bentley
Add --store option for zap.
193
        def test_store(self):
194
            self.requireFeature(PipelinePluginFeature)
195
            checkout = self.make_modified_checkout()
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
196
            zap('checkout', policy=StoreChanges)
749.1.6 by Aaron Bentley
Add --store option for zap.
197
            self.assertIn('stored-transform',
198
                checkout.branch.bzrdir.transport.list_dir('branch'))
199
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
200
        def test_store_remove_branch(self):
201
            self.requireFeature(PipelinePluginFeature)
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
202
            checkout = self.make_modified_checkout()
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
203
            branch = self.make_branch('branch')
204
            checkout.branch.set_parent(branch.base)
758 by Aaron Bentley
Allow zap --branch --store if no uncommitted changes.
205
            e = self.assertRaises(BzrCommandError, zap, 'checkout',
749.1.8 by Aaron Bentley
Control change behaviour with policies, not flags.
206
                                  policy=StoreChanges, remove_branch=True)
207
            self.assertEqual('Cannot store changes in deleted branch.', str(e))
749.1.6 by Aaron Bentley
Add --store option for zap.
208
749.1.9 by Aaron Bentley
Revamp zap's changed-file handling.
209
        def test_store_remove_branch_unmodified(self):
210
            self.requireFeature(PipelinePluginFeature)
211
            checkout = self.make_checkout()
212
            branch = self.make_branch('branch')
213
            checkout.branch.set_parent(branch.base)
214
            zap('checkout', policy=StoreChanges, remove_branch=True)
215
787 by Aaron Bentley
Fix zap command for 2.6/7
216
        def test_zap_branch_with_unique_revision(self):
217
            parent = self.make_branch_and_tree('parent')
218
            parent.commit('foo')
219
            new_branch = self.make_branch('new')
220
            new_branch.set_parent(parent.branch.base)
221
            checkout = new_branch.create_checkout('checkout', lightweight=True)
222
            checkout.commit('unique')
223
            self.assertRaises(ParentMissingRevisions, zap, 'checkout',
224
                              remove_branch=True)
225
345 by Aaron Bentley
Added zap command
226
    return makeSuite(TestZap)