/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.14.26 by Aaron Bentley
Update copyright
1
# Copyright (C) 2008 Canonical Ltd
0.12.12 by Aaron Bentley
Implement shelf creator
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.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
18
import errno
0.12.13 by Aaron Bentley
Implement shelving content
19
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
20
from bzrlib import (
0.15.15 by Aaron Bentley
Merge prepare-shelf into unshelve
21
    errors,
22
    merge,
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
23
    merge3,
24
    osutils,
25
    pack,
26
    transform,
0.15.15 by Aaron Bentley
Merge prepare-shelf into unshelve
27
    ui,
0.12.47 by Aaron Bentley
Merge unshelve into shelf-manager
28
    workingtree
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
29
)
0.15.19 by Aaron Bentley
Generalize first record as metadata.
30
from bzrlib.util import bencode
0.12.19 by Aaron Bentley
Add support for writing shelves
31
0.12.12 by Aaron Bentley
Implement shelf creator
32
33
class ShelfCreator(object):
34
0.14.21 by Aaron Bentley
Update to accept a list of files.
35
    def __init__(self, work_tree, target_tree, file_list=None):
0.12.12 by Aaron Bentley
Implement shelf creator
36
        self.work_tree = work_tree
37
        self.work_transform = transform.TreeTransform(work_tree)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
38
        self.target_tree = target_tree
39
        self.shelf_transform = transform.TransformPreview(self.target_tree)
0.12.12 by Aaron Bentley
Implement shelf creator
40
        self.renames = {}
0.14.2 by Aaron Bentley
Somewhat clean up shelving
41
        self.creation = {}
0.14.4 by Aaron Bentley
Implement shelving deletion
42
        self.deletion = {}
0.16.47 by Aaron Bentley
Support selecting files to shelve
43
        self.iter_changes = work_tree.iter_changes(self.target_tree,
44
                                                   specific_files=file_list)
0.12.12 by Aaron Bentley
Implement shelf creator
45
46
    def __iter__(self):
47
        for (file_id, paths, changed, versioned, parents, names, kind,
48
             executable) in self.iter_changes:
0.12.14 by Aaron Bentley
Add shelving of created files
49
            if kind[0] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
50
                self.creation[file_id] = (kind[1], names[1], parents[1],
51
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
52
                yield ('add file', file_id, kind[1], paths[1])
0.14.4 by Aaron Bentley
Implement shelving deletion
53
            elif kind[1] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
54
                self.deletion[file_id] = (kind[0], names[0], parents[0],
55
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
56
                yield ('delete file', file_id, kind[0], paths[0])
0.12.14 by Aaron Bentley
Add shelving of created files
57
            else:
58
                if names[0] != names[1] or parents[0] != parents[1]:
59
                    self.renames[file_id] = (names, parents)
60
                    yield ('rename', file_id) + paths
0.14.23 by Aaron Bentley
Allow shelving kind change
61
62
                if kind[0] != kind [1]:
63
                    yield ('change kind', file_id, kind[0], kind[1], paths[0])
64
                elif changed:
0.12.14 by Aaron Bentley
Add shelving of created files
65
                    yield ('modify text', file_id)
0.12.12 by Aaron Bentley
Implement shelf creator
66
67
    def shelve_rename(self, file_id):
68
        names, parents = self.renames[file_id]
69
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
70
        work_parent = self.work_transform.trans_id_file_id(parents[0])
71
        self.work_transform.adjust_path(names[0], work_parent, w_trans_id)
72
73
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
74
        shelf_parent = self.shelf_transform.trans_id_file_id(parents[1])
75
        self.shelf_transform.adjust_path(names[1], shelf_parent, s_trans_id)
76
0.14.14 by Aaron Bentley
Change shelf_text to shelve_lines
77
    def shelve_lines(self, file_id, new_lines):
0.12.13 by Aaron Bentley
Implement shelving content
78
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
79
        self.work_transform.delete_contents(w_trans_id)
80
        self.work_transform.create_file(new_lines, w_trans_id)
81
82
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
83
        self.shelf_transform.delete_contents(s_trans_id)
84
        inverse_lines = self._inverse_lines(new_lines, file_id)
85
        self.shelf_transform.create_file(inverse_lines, s_trans_id)
86
0.14.23 by Aaron Bentley
Allow shelving kind change
87
    @staticmethod
88
    def _content_from_tree(tt, tree, file_id):
89
        trans_id = tt.trans_id_file_id(file_id)
90
        tt.delete_contents(trans_id)
91
        transform.create_from_tree(tt, trans_id, tree, file_id)
92
93
    def shelve_content_change(self, file_id):
94
        self._content_from_tree(self.work_transform, self.target_tree, file_id)
95
        self._content_from_tree(self.shelf_transform, self.work_tree, file_id)
96
0.14.2 by Aaron Bentley
Somewhat clean up shelving
97
    def shelve_creation(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
98
        kind, name, parent, versioned = self.creation[file_id]
99
        version = not versioned[0]
0.14.4 by Aaron Bentley
Implement shelving deletion
100
        self._shelve_creation(self.work_tree, file_id, self.work_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
101
                              self.shelf_transform, kind, name, parent,
102
                              version)
0.14.4 by Aaron Bentley
Implement shelving deletion
103
104
    def shelve_deletion(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
105
        kind, name, parent, versioned = self.deletion[file_id]
106
        existing_path = self.target_tree.id2path(file_id)
107
        if not self.work_tree.has_filename(existing_path):
108
            existing_path = None
109
        version = not versioned[1]
0.14.4 by Aaron Bentley
Implement shelving deletion
110
        self._shelve_creation(self.target_tree, file_id, self.shelf_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
111
                              self.work_transform, kind, name, parent,
112
                              version, existing_path=existing_path)
0.14.4 by Aaron Bentley
Implement shelving deletion
113
114
    def _shelve_creation(self, tree, file_id, from_transform, to_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
115
                         kind, name, parent, version, existing_path=None):
0.14.4 by Aaron Bentley
Implement shelving deletion
116
        w_trans_id = from_transform.trans_id_file_id(file_id)
0.14.12 by Aaron Bentley
Handle new dangling ids
117
        if parent is not None and kind is not None:
0.14.4 by Aaron Bentley
Implement shelving deletion
118
            from_transform.delete_contents(w_trans_id)
119
        from_transform.unversion_file(w_trans_id)
120
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
121
        if existing_path is not None:
122
            s_trans_id = to_transform.trans_id_tree_path(existing_path)
123
        else:
124
            s_trans_id = to_transform.trans_id_file_id(file_id)
0.14.4 by Aaron Bentley
Implement shelving deletion
125
        if parent is not None:
126
            s_parent_id = to_transform.trans_id_file_id(parent)
0.14.9 by Aaron Bentley
Shelve deleted files properly
127
            to_transform.adjust_path(name, s_parent_id, s_trans_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
128
            if existing_path is None:
0.14.18 by Aaron Bentley
Simplify creating files
129
                if kind is None:
0.14.12 by Aaron Bentley
Handle new dangling ids
130
                    to_transform.create_file('', s_trans_id)
0.14.18 by Aaron Bentley
Simplify creating files
131
                else:
132
                    transform.create_from_tree(to_transform, s_trans_id,
133
                                               tree, file_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
134
        if version:
135
            to_transform.version_file(file_id, s_trans_id)
0.12.14 by Aaron Bentley
Add shelving of created files
136
0.14.4 by Aaron Bentley
Implement shelving deletion
137
    def read_tree_lines(self, tree, file_id):
0.14.17 by Aaron Bentley
Use safer line-splitting
138
        return osutils.split_lines(tree.get_file_text(file_id))
0.12.14 by Aaron Bentley
Add shelving of created files
139
140
    def _inverse_lines(self, new_lines, file_id):
141
        """Produce a version with only those changes removed from new_lines."""
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
142
        target_lines = self.target_tree.get_file_lines(file_id)
0.14.5 by Aaron Bentley
Fix call to read_tree_lines
143
        work_lines = self.read_tree_lines(self.work_tree, file_id)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
144
        return merge3.Merge3(new_lines, target_lines, work_lines).merge_lines()
0.12.13 by Aaron Bentley
Implement shelving content
145
0.12.12 by Aaron Bentley
Implement shelf creator
146
    def finalize(self):
147
        self.work_transform.finalize()
148
        self.shelf_transform.finalize()
0.12.13 by Aaron Bentley
Implement shelving content
149
150
    def transform(self):
151
        self.work_transform.apply()
0.12.19 by Aaron Bentley
Add support for writing shelves
152
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
153
    def write_shelf(self, shelf_file, message=None):
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
154
        transform.resolve_conflicts(self.shelf_transform)
0.12.28 by Aaron Bentley
Update for shelf manager
155
        serializer = pack.ContainerSerialiser()
156
        shelf_file.write(serializer.begin())
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
157
        metadata = {
158
            'revision_id': self.target_tree.get_revision_id(),
159
        }
160
        if message is not None:
0.12.52 by Aaron Bentley
Merge unshelve into shelf-manager
161
            metadata['message'] = message.encode('utf-8')
0.12.28 by Aaron Bentley
Update for shelf manager
162
        shelf_file.write(serializer.bytes_record(
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
163
            bencode.bencode(metadata), (('metadata',),)))
0.12.63 by Aaron Bentley
Merge with unshelve
164
        for bytes in self.shelf_transform.serialize(serializer):
0.12.28 by Aaron Bentley
Update for shelf manager
165
            shelf_file.write(bytes)
166
        shelf_file.write(serializer.end())
0.12.21 by Aaron Bentley
Add failing test of unshelver
167
168
169
class Unshelver(object):
170
0.15.19 by Aaron Bentley
Generalize first record as metadata.
171
    def __init__(self, tree, base_tree, transform, message):
0.12.21 by Aaron Bentley
Add failing test of unshelver
172
        self.tree = tree
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
173
        self.base_tree = base_tree
0.12.21 by Aaron Bentley
Add failing test of unshelver
174
        self.transform = transform
0.15.19 by Aaron Bentley
Generalize first record as metadata.
175
        self.message = message
0.12.21 by Aaron Bentley
Add failing test of unshelver
176
177
    @classmethod
0.12.28 by Aaron Bentley
Update for shelf manager
178
    def from_tree_and_shelf(klass, tree, shelf_file):
0.12.21 by Aaron Bentley
Add failing test of unshelver
179
        parser = pack.ContainerPushParser()
0.12.28 by Aaron Bentley
Update for shelf manager
180
        parser.accept_bytes(shelf_file.read())
0.12.21 by Aaron Bentley
Add failing test of unshelver
181
        records = iter(parser.read_pending_records())
0.15.19 by Aaron Bentley
Generalize first record as metadata.
182
        names, metadata_bytes = records.next()
183
        assert names[0] == ('metadata',)
184
        metadata = bencode.bdecode(metadata_bytes)
185
        base_revision_id = metadata['revision_id']
186
        message = metadata.get('message')
187
        if message is not None:
188
            message = message.decode('utf-8')
0.12.26 by Aaron Bentley
Use correct base for shelving
189
        try:
190
            base_tree = tree.revision_tree(base_revision_id)
191
        except errors.NoSuchRevisionInTree:
192
            base_tree = tree.branch.repository.revision_tree(base_revision_id)
0.15.23 by Aaron Bentley
Use correct tree for desrializing transform
193
        tt = transform.TransformPreview(base_tree)
0.15.26 by Aaron Bentley
Merge with prepare-shelf
194
        tt.deserialize(records)
0.15.19 by Aaron Bentley
Generalize first record as metadata.
195
        return klass(tree, base_tree, tt, message)
0.12.21 by Aaron Bentley
Add failing test of unshelver
196
0.16.50 by Aaron Bentley
Display changes being unshelved
197
    def unshelve(self, change_reporter=None):
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
198
        pb = ui.ui_factory.nested_progress_bar()
199
        try:
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
200
            merger = self.get_merger()
201
            merger.change_reporter = change_reporter
202
            merger.do_merge()
203
        finally:
204
            pb.finished()
205
206
    def get_merger(self):
207
        pb = ui.ui_factory.nested_progress_bar()
208
        try:
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
209
            target_tree = self.transform.get_preview_tree()
210
            merger = merge.Merger.from_uncommitted(self.tree, target_tree, pb,
211
                                                   self.base_tree)
212
            merger.merge_type = merge.Merge3Merger
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
213
            return merger
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
214
        finally:
215
            pb.finished()
216
217
    def finalize(self):
218
        self.transform.finalize()
0.12.27 by Aaron Bentley
Implement shelf manager
219
220
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
221
class NoSuchShelfId(errors.BzrError):
222
223
    _fmt = 'No changes are shelved with id "%(shelf_id)d".'
224
225
    def __init__(self, shelf_id):
226
        errors.BzrError.__init__(self, shelf_id=shelf_id)
227
0.12.27 by Aaron Bentley
Implement shelf manager
228
class ShelfManager(object):
229
0.12.42 by Aaron Bentley
Get shelf from tree
230
    def __init__(self, tree, transport):
231
        self.tree = tree
0.12.41 by Aaron Bentley
Change shelf to use WT control dir for shelves
232
        self.transport = transport.clone('shelf')
0.12.27 by Aaron Bentley
Implement shelf manager
233
        self.transport.ensure_base()
234
235
    def new_shelf(self):
236
        last_shelf = self.last_shelf()
237
        if last_shelf is None:
238
            next_shelf = 1
239
        else:
240
            next_shelf = last_shelf + 1
241
        shelf_file = open(self.transport.local_abspath(str(next_shelf)), 'wb')
242
        return next_shelf, shelf_file
243
0.12.53 by Aaron Bentley
Allow adding message to shelf
244
    def shelve_changes(self, creator, message=None):
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
245
        next_shelf, shelf_file = self.new_shelf()
246
        try:
0.12.53 by Aaron Bentley
Allow adding message to shelf
247
            creator.write_shelf(shelf_file, message)
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
248
        finally:
249
            shelf_file.close()
0.12.44 by Aaron Bentley
Give manager responsibility for applying transform
250
        creator.transform()
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
251
        return next_shelf
252
0.12.27 by Aaron Bentley
Implement shelf manager
253
    def read_shelf(self, shelf_id):
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
254
        try:
255
            return open(self.transport.local_abspath(str(shelf_id)), 'rb')
256
        except IOError, e:
257
            if e.errno != errno.ENOENT:
258
                raise
259
            raise NoSuchShelfId(shelf_id)
0.12.27 by Aaron Bentley
Implement shelf manager
260
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
261
    def get_unshelver(self, shelf_id):
262
        shelf_file = self.read_shelf(shelf_id)
263
        try:
264
            return Unshelver.from_tree_and_shelf(self.tree, shelf_file)
265
        finally:
266
            shelf_file.close()
267
0.12.27 by Aaron Bentley
Implement shelf manager
268
    def delete_shelf(self, shelf_id):
269
        self.transport.delete(str(shelf_id))
270
271
    def active_shelves(self):
272
        return [int(f) for f in self.transport.list_dir('.')]
273
274
    def last_shelf(self):
275
        active = self.active_shelves()
276
        if len(active) > 0:
277
            return max(active)
278
        else:
279
            return None
0.12.42 by Aaron Bentley
Get shelf from tree
280
281
282
def get_shelf_manager(self):
283
    return ShelfManager(self, self._transport)
284
285
286
workingtree.WorkingTree.get_shelf_manager = get_shelf_manager