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