/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.12.12 by Aaron Bentley
Implement shelf creator
1
# Copyright (C) 2008 Aaron Bentley <aaron@aaronbentley.com>
2
#
3
#    This program is free software; you can redistribute it and/or modify
4
#    it under the terms of the GNU General Public License as published by
5
#    the Free Software Foundation; either version 2 of the License, or
6
#    (at your option) any later version.
7
#
8
#    This program is distributed in the hope that it will be useful,
9
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
10
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
#    GNU General Public License for more details.
12
#
13
#    You should have received a copy of the GNU General Public License
14
#    along with this program; if not, write to the Free Software
15
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
0.12.13 by Aaron Bentley
Implement shelving content
18
from cStringIO import StringIO
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
19
import errno
0.12.13 by Aaron Bentley
Implement shelving content
20
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
21
from bzrlib import (
0.15.15 by Aaron Bentley
Merge prepare-shelf into unshelve
22
    errors,
23
    merge,
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
24
    merge3,
25
    osutils,
26
    pack,
27
    transform,
0.15.15 by Aaron Bentley
Merge prepare-shelf into unshelve
28
    ui,
0.12.47 by Aaron Bentley
Merge unshelve into shelf-manager
29
    workingtree
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
30
)
0.12.19 by Aaron Bentley
Add support for writing shelves
31
32
from bzrlib.plugins.shelf2 import serialize_transform
0.12.12 by Aaron Bentley
Implement shelf creator
33
34
35
class ShelfCreator(object):
36
0.14.21 by Aaron Bentley
Update to accept a list of files.
37
    def __init__(self, work_tree, target_tree, file_list=None):
0.12.12 by Aaron Bentley
Implement shelf creator
38
        self.work_tree = work_tree
39
        self.work_transform = transform.TreeTransform(work_tree)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
40
        self.target_tree = target_tree
41
        self.shelf_transform = transform.TransformPreview(self.target_tree)
0.12.12 by Aaron Bentley
Implement shelf creator
42
        self.renames = {}
0.14.2 by Aaron Bentley
Somewhat clean up shelving
43
        self.creation = {}
0.14.4 by Aaron Bentley
Implement shelving deletion
44
        self.deletion = {}
0.16.47 by Aaron Bentley
Support selecting files to shelve
45
        self.iter_changes = work_tree.iter_changes(self.target_tree,
46
                                                   specific_files=file_list)
0.12.12 by Aaron Bentley
Implement shelf creator
47
48
    def __iter__(self):
49
        for (file_id, paths, changed, versioned, parents, names, kind,
50
             executable) in self.iter_changes:
0.12.14 by Aaron Bentley
Add shelving of created files
51
            if kind[0] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
52
                self.creation[file_id] = (kind[1], names[1], parents[1],
53
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
54
                yield ('add file', file_id, kind[1], paths[1])
0.14.4 by Aaron Bentley
Implement shelving deletion
55
            elif kind[1] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
56
                self.deletion[file_id] = (kind[0], names[0], parents[0],
57
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
58
                yield ('delete file', file_id, kind[0], paths[0])
0.12.14 by Aaron Bentley
Add shelving of created files
59
            else:
60
                if names[0] != names[1] or parents[0] != parents[1]:
61
                    self.renames[file_id] = (names, parents)
62
                    yield ('rename', file_id) + paths
63
                if changed:
64
                    yield ('modify text', file_id)
0.12.12 by Aaron Bentley
Implement shelf creator
65
66
    def shelve_rename(self, file_id):
67
        names, parents = self.renames[file_id]
68
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
69
        work_parent = self.work_transform.trans_id_file_id(parents[0])
70
        self.work_transform.adjust_path(names[0], work_parent, w_trans_id)
71
72
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
73
        shelf_parent = self.shelf_transform.trans_id_file_id(parents[1])
74
        self.shelf_transform.adjust_path(names[1], shelf_parent, s_trans_id)
75
0.14.14 by Aaron Bentley
Change shelf_text to shelve_lines
76
    def shelve_lines(self, file_id, new_lines):
0.12.13 by Aaron Bentley
Implement shelving content
77
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
78
        self.work_transform.delete_contents(w_trans_id)
79
        self.work_transform.create_file(new_lines, w_trans_id)
80
81
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
82
        self.shelf_transform.delete_contents(s_trans_id)
83
        inverse_lines = self._inverse_lines(new_lines, file_id)
84
        self.shelf_transform.create_file(inverse_lines, s_trans_id)
85
0.14.2 by Aaron Bentley
Somewhat clean up shelving
86
    def shelve_creation(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
87
        kind, name, parent, versioned = self.creation[file_id]
88
        version = not versioned[0]
0.14.4 by Aaron Bentley
Implement shelving deletion
89
        self._shelve_creation(self.work_tree, file_id, self.work_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
90
                              self.shelf_transform, kind, name, parent,
91
                              version)
0.14.4 by Aaron Bentley
Implement shelving deletion
92
93
    def shelve_deletion(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
94
        kind, name, parent, versioned = self.deletion[file_id]
95
        existing_path = self.target_tree.id2path(file_id)
96
        if not self.work_tree.has_filename(existing_path):
97
            existing_path = None
98
        version = not versioned[1]
0.14.4 by Aaron Bentley
Implement shelving deletion
99
        self._shelve_creation(self.target_tree, file_id, self.shelf_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
100
                              self.work_transform, kind, name, parent,
101
                              version, existing_path=existing_path)
0.14.4 by Aaron Bentley
Implement shelving deletion
102
103
    def _shelve_creation(self, tree, file_id, from_transform, to_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
104
                         kind, name, parent, version, existing_path=None):
0.14.4 by Aaron Bentley
Implement shelving deletion
105
        w_trans_id = from_transform.trans_id_file_id(file_id)
0.14.12 by Aaron Bentley
Handle new dangling ids
106
        if parent is not None and kind is not None:
0.14.4 by Aaron Bentley
Implement shelving deletion
107
            from_transform.delete_contents(w_trans_id)
108
        from_transform.unversion_file(w_trans_id)
109
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
110
        if existing_path is not None:
111
            s_trans_id = to_transform.trans_id_tree_path(existing_path)
112
        else:
113
            s_trans_id = to_transform.trans_id_file_id(file_id)
0.14.4 by Aaron Bentley
Implement shelving deletion
114
        if parent is not None:
115
            s_parent_id = to_transform.trans_id_file_id(parent)
0.14.9 by Aaron Bentley
Shelve deleted files properly
116
            to_transform.adjust_path(name, s_parent_id, s_trans_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
117
            if existing_path is None:
0.14.18 by Aaron Bentley
Simplify creating files
118
                if kind is None:
0.14.12 by Aaron Bentley
Handle new dangling ids
119
                    to_transform.create_file('', s_trans_id)
0.14.18 by Aaron Bentley
Simplify creating files
120
                else:
121
                    transform.create_from_tree(to_transform, s_trans_id,
122
                                               tree, file_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
123
        if version:
124
            to_transform.version_file(file_id, s_trans_id)
0.12.14 by Aaron Bentley
Add shelving of created files
125
0.14.4 by Aaron Bentley
Implement shelving deletion
126
    def read_tree_lines(self, tree, file_id):
0.14.17 by Aaron Bentley
Use safer line-splitting
127
        return osutils.split_lines(tree.get_file_text(file_id))
0.12.14 by Aaron Bentley
Add shelving of created files
128
129
    def _inverse_lines(self, new_lines, file_id):
130
        """Produce a version with only those changes removed from new_lines."""
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
131
        target_lines = self.target_tree.get_file_lines(file_id)
0.14.5 by Aaron Bentley
Fix call to read_tree_lines
132
        work_lines = self.read_tree_lines(self.work_tree, file_id)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
133
        return merge3.Merge3(new_lines, target_lines, work_lines).merge_lines()
0.12.13 by Aaron Bentley
Implement shelving content
134
0.12.12 by Aaron Bentley
Implement shelf creator
135
    def finalize(self):
136
        self.work_transform.finalize()
137
        self.shelf_transform.finalize()
0.12.13 by Aaron Bentley
Implement shelving content
138
139
    def transform(self):
140
        self.work_transform.apply()
0.12.19 by Aaron Bentley
Add support for writing shelves
141
142
    def make_shelf_filename(self):
143
        transport = self.work_tree.bzrdir.root_transport.clone('.shelf2')
144
        transport.ensure_base()
145
        return transport.local_abspath('01')
146
0.12.28 by Aaron Bentley
Update for shelf manager
147
    def write_shelf(self, shelf_file):
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
148
        transform.resolve_conflicts(self.shelf_transform)
0.12.28 by Aaron Bentley
Update for shelf manager
149
        serializer = pack.ContainerSerialiser()
150
        shelf_file.write(serializer.begin())
151
        shelf_file.write(serializer.bytes_record(
152
            self.target_tree.get_revision_id(), (('revision-id',),)))
153
        for bytes in serialize_transform.serialize(
154
            self.shelf_transform, serializer):
155
            shelf_file.write(bytes)
156
        shelf_file.write(serializer.end())
0.12.21 by Aaron Bentley
Add failing test of unshelver
157
158
159
class Unshelver(object):
160
161
    def __init__(self, tree, base_tree, transform):
162
        self.tree = tree
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
163
        self.base_tree = base_tree
0.12.21 by Aaron Bentley
Add failing test of unshelver
164
        self.transform = transform
165
166
    @classmethod
0.12.28 by Aaron Bentley
Update for shelf manager
167
    def from_tree_and_shelf(klass, tree, shelf_file):
0.12.21 by Aaron Bentley
Add failing test of unshelver
168
        parser = pack.ContainerPushParser()
0.12.28 by Aaron Bentley
Update for shelf manager
169
        parser.accept_bytes(shelf_file.read())
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
170
        tt = transform.TransformPreview(tree)
0.12.21 by Aaron Bentley
Add failing test of unshelver
171
        records = iter(parser.read_pending_records())
0.12.26 by Aaron Bentley
Use correct base for shelving
172
        names, base_revision_id = records.next()
0.12.21 by Aaron Bentley
Add failing test of unshelver
173
        serialize_transform.deserialize(tt, records)
0.12.26 by Aaron Bentley
Use correct base for shelving
174
        try:
175
            base_tree = tree.revision_tree(base_revision_id)
176
        except errors.NoSuchRevisionInTree:
177
            base_tree = tree.branch.repository.revision_tree(base_revision_id)
178
        return klass(tree, base_tree, tt)
0.12.21 by Aaron Bentley
Add failing test of unshelver
179
0.16.50 by Aaron Bentley
Display changes being unshelved
180
    def unshelve(self, change_reporter=None):
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
181
        pb = ui.ui_factory.nested_progress_bar()
182
        try:
183
            target_tree = self.transform.get_preview_tree()
184
            merger = merge.Merger.from_uncommitted(self.tree, target_tree, pb,
185
                                                   self.base_tree)
186
            merger.merge_type = merge.Merge3Merger
0.16.50 by Aaron Bentley
Display changes being unshelved
187
            merger.change_reporter = change_reporter
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
188
            merger.do_merge()
189
        finally:
190
            pb.finished()
191
192
    def finalize(self):
193
        self.transform.finalize()
0.12.27 by Aaron Bentley
Implement shelf manager
194
195
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
196
class NoSuchShelfId(errors.BzrError):
197
198
    _fmt = 'No changes are shelved with id "%(shelf_id)d".'
199
200
    def __init__(self, shelf_id):
201
        errors.BzrError.__init__(self, shelf_id=shelf_id)
202
0.12.27 by Aaron Bentley
Implement shelf manager
203
class ShelfManager(object):
204
0.12.42 by Aaron Bentley
Get shelf from tree
205
    def __init__(self, tree, transport):
206
        self.tree = tree
0.12.41 by Aaron Bentley
Change shelf to use WT control dir for shelves
207
        self.transport = transport.clone('shelf')
0.12.27 by Aaron Bentley
Implement shelf manager
208
        self.transport.ensure_base()
209
210
    def new_shelf(self):
211
        last_shelf = self.last_shelf()
212
        if last_shelf is None:
213
            next_shelf = 1
214
        else:
215
            next_shelf = last_shelf + 1
216
        shelf_file = open(self.transport.local_abspath(str(next_shelf)), 'wb')
217
        return next_shelf, shelf_file
218
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
219
    def shelve_changes(self, creator):
220
        next_shelf, shelf_file = self.new_shelf()
221
        try:
222
            creator.write_shelf(shelf_file)
223
        finally:
224
            shelf_file.close()
0.12.44 by Aaron Bentley
Give manager responsibility for applying transform
225
        creator.transform()
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
226
        return next_shelf
227
0.12.27 by Aaron Bentley
Implement shelf manager
228
    def read_shelf(self, shelf_id):
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
229
        try:
230
            return open(self.transport.local_abspath(str(shelf_id)), 'rb')
231
        except IOError, e:
232
            if e.errno != errno.ENOENT:
233
                raise
234
            raise NoSuchShelfId(shelf_id)
0.12.27 by Aaron Bentley
Implement shelf manager
235
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
236
    def get_unshelver(self, shelf_id):
237
        shelf_file = self.read_shelf(shelf_id)
238
        try:
239
            return Unshelver.from_tree_and_shelf(self.tree, shelf_file)
240
        finally:
241
            shelf_file.close()
242
0.12.27 by Aaron Bentley
Implement shelf manager
243
    def delete_shelf(self, shelf_id):
244
        self.transport.delete(str(shelf_id))
245
246
    def active_shelves(self):
247
        return [int(f) for f in self.transport.list_dir('.')]
248
249
    def last_shelf(self):
250
        active = self.active_shelves()
251
        if len(active) > 0:
252
            return max(active)
253
        else:
254
            return None
0.12.42 by Aaron Bentley
Get shelf from tree
255
256
257
def get_shelf_manager(self):
258
    return ShelfManager(self, self._transport)
259
260
261
workingtree.WorkingTree.get_shelf_manager = get_shelf_manager