/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):
0.14.27 by Aaron Bentley
Update docs
34
    """Create a transform to shelve objects and its inverse."""
0.12.12 by Aaron Bentley
Implement shelf creator
35
0.14.21 by Aaron Bentley
Update to accept a list of files.
36
    def __init__(self, work_tree, target_tree, file_list=None):
0.14.27 by Aaron Bentley
Update docs
37
        """Constructor.
38
39
        :param work_tree: The working tree to apply changes to
40
        :param target_tree: The tree to make the working tree more similar to.
41
        :param file_list: The files to make more similar to the target.
42
        """
0.12.12 by Aaron Bentley
Implement shelf creator
43
        self.work_tree = work_tree
44
        self.work_transform = transform.TreeTransform(work_tree)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
45
        self.target_tree = target_tree
46
        self.shelf_transform = transform.TransformPreview(self.target_tree)
0.12.12 by Aaron Bentley
Implement shelf creator
47
        self.renames = {}
0.14.2 by Aaron Bentley
Somewhat clean up shelving
48
        self.creation = {}
0.14.4 by Aaron Bentley
Implement shelving deletion
49
        self.deletion = {}
0.14.21 by Aaron Bentley
Update to accept a list of files.
50
        self.iter_changes = work_tree.iter_changes(self.target_tree,
51
                                                   specific_files=file_list)
0.12.12 by Aaron Bentley
Implement shelf creator
52
0.14.32 by Aaron Bentley
Replace ShelfCreator.__iter__ with ShelfCreator.iter_shelvable
53
    def iter_shelvable(self):
0.14.27 by Aaron Bentley
Update docs
54
        """Iterable of tuples describing shelvable changes.
55
56
        As well as generating the tuples, this updates several members.
57
        Tuples may be:
58
           ('add file', file_id, work_kind, work_path)
59
           ('delete file', file_id, target_kind, target_path)
60
           ('rename', file_id, target_path, work_path)
61
           ('change kind', file_id, target_kind, work_kind, target_path)
62
           ('modify text', file_id)
63
        """
0.12.12 by Aaron Bentley
Implement shelf creator
64
        for (file_id, paths, changed, versioned, parents, names, kind,
65
             executable) in self.iter_changes:
0.12.14 by Aaron Bentley
Add shelving of created files
66
            if kind[0] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
67
                self.creation[file_id] = (kind[1], names[1], parents[1],
68
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
69
                yield ('add file', file_id, kind[1], paths[1])
0.14.4 by Aaron Bentley
Implement shelving deletion
70
            elif kind[1] is None or versioned[0] == False:
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
71
                self.deletion[file_id] = (kind[0], names[0], parents[0],
72
                                          versioned)
0.14.13 by Aaron Bentley
Provide path and kind when deletes/adds are detected.
73
                yield ('delete file', file_id, kind[0], paths[0])
0.12.14 by Aaron Bentley
Add shelving of created files
74
            else:
75
                if names[0] != names[1] or parents[0] != parents[1]:
76
                    self.renames[file_id] = (names, parents)
77
                    yield ('rename', file_id) + paths
0.14.23 by Aaron Bentley
Allow shelving kind change
78
79
                if kind[0] != kind [1]:
80
                    yield ('change kind', file_id, kind[0], kind[1], paths[0])
81
                elif changed:
0.12.14 by Aaron Bentley
Add shelving of created files
82
                    yield ('modify text', file_id)
0.12.12 by Aaron Bentley
Implement shelf creator
83
84
    def shelve_rename(self, file_id):
0.14.27 by Aaron Bentley
Update docs
85
        """Shelve a file rename.
86
87
        :param file_id: The file id of the file to shelve the renaming of.
88
        """
0.12.12 by Aaron Bentley
Implement shelf creator
89
        names, parents = self.renames[file_id]
90
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
91
        work_parent = self.work_transform.trans_id_file_id(parents[0])
92
        self.work_transform.adjust_path(names[0], work_parent, w_trans_id)
93
94
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
95
        shelf_parent = self.shelf_transform.trans_id_file_id(parents[1])
96
        self.shelf_transform.adjust_path(names[1], shelf_parent, s_trans_id)
97
0.14.14 by Aaron Bentley
Change shelf_text to shelve_lines
98
    def shelve_lines(self, file_id, new_lines):
0.14.27 by Aaron Bentley
Update docs
99
        """Shelve text changes to a file, using provided lines.
100
101
        :param file_id: The file id of the file to shelve the text of.
102
        :param new_lines: The lines that the file should have due to shelving.
103
        """
0.12.13 by Aaron Bentley
Implement shelving content
104
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
105
        self.work_transform.delete_contents(w_trans_id)
106
        self.work_transform.create_file(new_lines, w_trans_id)
107
108
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
109
        self.shelf_transform.delete_contents(s_trans_id)
110
        inverse_lines = self._inverse_lines(new_lines, file_id)
111
        self.shelf_transform.create_file(inverse_lines, s_trans_id)
112
0.14.23 by Aaron Bentley
Allow shelving kind change
113
    @staticmethod
114
    def _content_from_tree(tt, tree, file_id):
115
        trans_id = tt.trans_id_file_id(file_id)
116
        tt.delete_contents(trans_id)
117
        transform.create_from_tree(tt, trans_id, tree, file_id)
118
119
    def shelve_content_change(self, file_id):
0.14.27 by Aaron Bentley
Update docs
120
        """Shelve a kind change or binary file content change.
121
122
        :param file_id: The file id of the file to shelve the content change
123
            of.
124
        """
0.14.23 by Aaron Bentley
Allow shelving kind change
125
        self._content_from_tree(self.work_transform, self.target_tree, file_id)
126
        self._content_from_tree(self.shelf_transform, self.work_tree, file_id)
127
0.14.2 by Aaron Bentley
Somewhat clean up shelving
128
    def shelve_creation(self, file_id):
0.14.27 by Aaron Bentley
Update docs
129
        """Shelve creation of a file.
130
131
        This handles content and inventory id.
132
        :param file_id: The file_id of the file to shelve creation of.
133
        """
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
134
        kind, name, parent, versioned = self.creation[file_id]
135
        version = not versioned[0]
0.14.4 by Aaron Bentley
Implement shelving deletion
136
        self._shelve_creation(self.work_tree, file_id, self.work_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
137
                              self.shelf_transform, kind, name, parent,
138
                              version)
0.14.4 by Aaron Bentley
Implement shelving deletion
139
140
    def shelve_deletion(self, file_id):
0.14.27 by Aaron Bentley
Update docs
141
        """Shelve deletion of a file.
142
143
        This handles content and inventory id.
144
        :param file_id: The file_id of the file to shelve deletion of.
145
        """
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
146
        kind, name, parent, versioned = self.deletion[file_id]
147
        existing_path = self.target_tree.id2path(file_id)
148
        if not self.work_tree.has_filename(existing_path):
149
            existing_path = None
150
        version = not versioned[1]
0.14.4 by Aaron Bentley
Implement shelving deletion
151
        self._shelve_creation(self.target_tree, file_id, self.shelf_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
152
                              self.work_transform, kind, name, parent,
153
                              version, existing_path=existing_path)
0.14.4 by Aaron Bentley
Implement shelving deletion
154
155
    def _shelve_creation(self, tree, file_id, from_transform, to_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
156
                         kind, name, parent, version, existing_path=None):
0.14.4 by Aaron Bentley
Implement shelving deletion
157
        w_trans_id = from_transform.trans_id_file_id(file_id)
0.14.12 by Aaron Bentley
Handle new dangling ids
158
        if parent is not None and kind is not None:
0.14.4 by Aaron Bentley
Implement shelving deletion
159
            from_transform.delete_contents(w_trans_id)
160
        from_transform.unversion_file(w_trans_id)
161
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
162
        if existing_path is not None:
163
            s_trans_id = to_transform.trans_id_tree_path(existing_path)
164
        else:
165
            s_trans_id = to_transform.trans_id_file_id(file_id)
0.14.4 by Aaron Bentley
Implement shelving deletion
166
        if parent is not None:
167
            s_parent_id = to_transform.trans_id_file_id(parent)
0.14.9 by Aaron Bentley
Shelve deleted files properly
168
            to_transform.adjust_path(name, s_parent_id, s_trans_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
169
            if existing_path is None:
0.14.18 by Aaron Bentley
Simplify creating files
170
                if kind is None:
0.14.12 by Aaron Bentley
Handle new dangling ids
171
                    to_transform.create_file('', s_trans_id)
0.14.18 by Aaron Bentley
Simplify creating files
172
                else:
173
                    transform.create_from_tree(to_transform, s_trans_id,
174
                                               tree, file_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
175
        if version:
176
            to_transform.version_file(file_id, s_trans_id)
0.12.14 by Aaron Bentley
Add shelving of created files
177
0.14.4 by Aaron Bentley
Implement shelving deletion
178
    def read_tree_lines(self, tree, file_id):
0.14.27 by Aaron Bentley
Update docs
179
        """Read text lines from a tree.
180
181
        (Tree.get_file_lines is not an official API)
182
        """
0.14.17 by Aaron Bentley
Use safer line-splitting
183
        return osutils.split_lines(tree.get_file_text(file_id))
0.12.14 by Aaron Bentley
Add shelving of created files
184
185
    def _inverse_lines(self, new_lines, file_id):
186
        """Produce a version with only those changes removed from new_lines."""
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
187
        target_lines = self.target_tree.get_file_lines(file_id)
0.14.5 by Aaron Bentley
Fix call to read_tree_lines
188
        work_lines = self.read_tree_lines(self.work_tree, file_id)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
189
        return merge3.Merge3(new_lines, target_lines, work_lines).merge_lines()
0.12.13 by Aaron Bentley
Implement shelving content
190
0.12.12 by Aaron Bentley
Implement shelf creator
191
    def finalize(self):
0.14.27 by Aaron Bentley
Update docs
192
        """Release all resources used by this ShelfCreator."""
0.12.12 by Aaron Bentley
Implement shelf creator
193
        self.work_transform.finalize()
194
        self.shelf_transform.finalize()
0.12.13 by Aaron Bentley
Implement shelving content
195
196
    def transform(self):
0.14.27 by Aaron Bentley
Update docs
197
        """Shelve changes from working tree."""
0.12.13 by Aaron Bentley
Implement shelving content
198
        self.work_transform.apply()
0.12.19 by Aaron Bentley
Add support for writing shelves
199
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
200
    def write_shelf(self, shelf_file, message=None):
0.14.27 by Aaron Bentley
Update docs
201
        """Serialize the shelved changes to a file.
202
0.12.66 by Aaron Bentley
Merge with unshelve
203
        :param shelf_file: A file-like object to write the shelf to.
0.15.29 by Aaron Bentley
Merge with prepare-shelf
204
        :param message: An optional message describing the shelved changes.
0.14.27 by Aaron Bentley
Update docs
205
        :return: the filename of the written file.
206
        """
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
207
        transform.resolve_conflicts(self.shelf_transform)
0.12.28 by Aaron Bentley
Update for shelf manager
208
        serializer = pack.ContainerSerialiser()
209
        shelf_file.write(serializer.begin())
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
210
        metadata = {
211
            'revision_id': self.target_tree.get_revision_id(),
212
        }
213
        if message is not None:
0.12.52 by Aaron Bentley
Merge unshelve into shelf-manager
214
            metadata['message'] = message.encode('utf-8')
0.12.28 by Aaron Bentley
Update for shelf manager
215
        shelf_file.write(serializer.bytes_record(
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
216
            bencode.bencode(metadata), (('metadata',),)))
0.12.63 by Aaron Bentley
Merge with unshelve
217
        for bytes in self.shelf_transform.serialize(serializer):
0.12.28 by Aaron Bentley
Update for shelf manager
218
            shelf_file.write(bytes)
219
        shelf_file.write(serializer.end())
0.12.21 by Aaron Bentley
Add failing test of unshelver
220
221
222
class Unshelver(object):
0.15.30 by Aaron Bentley
Update docs.
223
    """Unshelve shelved changes."""
0.12.21 by Aaron Bentley
Add failing test of unshelver
224
0.15.19 by Aaron Bentley
Generalize first record as metadata.
225
    def __init__(self, tree, base_tree, transform, message):
0.15.30 by Aaron Bentley
Update docs.
226
        """Constructor.
227
228
        :param tree: The tree to apply the changes to.
229
        :param base_tree: The basis to apply the tranform to.
230
        :param message: A message from the shelved transform.
231
        """
0.12.21 by Aaron Bentley
Add failing test of unshelver
232
        self.tree = tree
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
233
        self.base_tree = base_tree
0.12.21 by Aaron Bentley
Add failing test of unshelver
234
        self.transform = transform
0.15.19 by Aaron Bentley
Generalize first record as metadata.
235
        self.message = message
0.12.21 by Aaron Bentley
Add failing test of unshelver
236
237
    @classmethod
0.12.28 by Aaron Bentley
Update for shelf manager
238
    def from_tree_and_shelf(klass, tree, shelf_file):
0.15.30 by Aaron Bentley
Update docs.
239
        """Create an Unshelver from a tree and a shelf file.
240
241
        :param tree: The tree to apply shelved changes to.
0.12.66 by Aaron Bentley
Merge with unshelve
242
        :param shelf_file: A file-like object containing shelved changes.
0.15.30 by Aaron Bentley
Update docs.
243
        :return: The Unshelver.
244
        """
0.12.21 by Aaron Bentley
Add failing test of unshelver
245
        parser = pack.ContainerPushParser()
0.12.28 by Aaron Bentley
Update for shelf manager
246
        parser.accept_bytes(shelf_file.read())
0.12.21 by Aaron Bentley
Add failing test of unshelver
247
        records = iter(parser.read_pending_records())
0.15.19 by Aaron Bentley
Generalize first record as metadata.
248
        names, metadata_bytes = records.next()
0.15.41 by Aaron Bentley
Replace assert with proper error handling
249
        if names[0] != ('metadata',):
250
            raise errors.ShelfCorrupt
0.15.19 by Aaron Bentley
Generalize first record as metadata.
251
        metadata = bencode.bdecode(metadata_bytes)
252
        base_revision_id = metadata['revision_id']
253
        message = metadata.get('message')
254
        if message is not None:
255
            message = message.decode('utf-8')
0.12.26 by Aaron Bentley
Use correct base for shelving
256
        try:
257
            base_tree = tree.revision_tree(base_revision_id)
258
        except errors.NoSuchRevisionInTree:
259
            base_tree = tree.branch.repository.revision_tree(base_revision_id)
0.15.23 by Aaron Bentley
Use correct tree for desrializing transform
260
        tt = transform.TransformPreview(base_tree)
0.15.26 by Aaron Bentley
Merge with prepare-shelf
261
        tt.deserialize(records)
0.15.19 by Aaron Bentley
Generalize first record as metadata.
262
        return klass(tree, base_tree, tt, message)
0.12.21 by Aaron Bentley
Add failing test of unshelver
263
0.15.31 by Aaron Bentley
Remove 'unshelve' method, test make_merger
264
    def make_merger(self):
0.15.30 by Aaron Bentley
Update docs.
265
        """Return a merger that can unshelve the changes."""
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
266
        pb = ui.ui_factory.nested_progress_bar()
267
        try:
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
268
            target_tree = self.transform.get_preview_tree()
269
            merger = merge.Merger.from_uncommitted(self.tree, target_tree, pb,
270
                                                   self.base_tree)
271
            merger.merge_type = merge.Merge3Merger
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
272
            return merger
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
273
        finally:
274
            pb.finished()
275
276
    def finalize(self):
0.15.30 by Aaron Bentley
Update docs.
277
        """Release all resources held by this Unshelver."""
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
278
        self.transform.finalize()
0.12.27 by Aaron Bentley
Implement shelf manager
279
280
281
class ShelfManager(object):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
282
    """Maintain a list of shelved changes."""
0.12.27 by Aaron Bentley
Implement shelf manager
283
0.12.42 by Aaron Bentley
Get shelf from tree
284
    def __init__(self, tree, transport):
285
        self.tree = tree
0.12.41 by Aaron Bentley
Change shelf to use WT control dir for shelves
286
        self.transport = transport.clone('shelf')
0.12.27 by Aaron Bentley
Implement shelf manager
287
        self.transport.ensure_base()
288
289
    def new_shelf(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
290
        """Return a file object and id for a new set of shelved changes."""
0.12.27 by Aaron Bentley
Implement shelf manager
291
        last_shelf = self.last_shelf()
292
        if last_shelf is None:
293
            next_shelf = 1
294
        else:
295
            next_shelf = last_shelf + 1
296
        shelf_file = open(self.transport.local_abspath(str(next_shelf)), 'wb')
297
        return next_shelf, shelf_file
298
0.12.53 by Aaron Bentley
Allow adding message to shelf
299
    def shelve_changes(self, creator, message=None):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
300
        """Store the changes in a ShelfCreator on a shelf."""
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
301
        next_shelf, shelf_file = self.new_shelf()
302
        try:
0.12.53 by Aaron Bentley
Allow adding message to shelf
303
            creator.write_shelf(shelf_file, message)
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
304
        finally:
305
            shelf_file.close()
0.12.44 by Aaron Bentley
Give manager responsibility for applying transform
306
        creator.transform()
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
307
        return next_shelf
308
0.12.27 by Aaron Bentley
Implement shelf manager
309
    def read_shelf(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
310
        """Return the file associated with a shelf_id for reading.
311
312
        :param shelf_id: The id of the shelf to retrive the file for.
313
        """
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
314
        try:
315
            return open(self.transport.local_abspath(str(shelf_id)), 'rb')
316
        except IOError, e:
317
            if e.errno != errno.ENOENT:
318
                raise
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
319
            from bzrlib import errors
320
            raise errors.NoSuchShelfId(shelf_id)
0.12.27 by Aaron Bentley
Implement shelf manager
321
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
322
    def get_unshelver(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
323
        """Return an unshelver for a given shelf_id.
324
325
        :param shelf_id: The shelf id to return the unshelver for.
326
        """
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
327
        shelf_file = self.read_shelf(shelf_id)
328
        try:
329
            return Unshelver.from_tree_and_shelf(self.tree, shelf_file)
330
        finally:
331
            shelf_file.close()
332
0.12.27 by Aaron Bentley
Implement shelf manager
333
    def delete_shelf(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
334
        """Delete the shelved changes for a given id.
335
336
        :param shelf_id: id of the shelved changes to delete.
337
        """
0.12.27 by Aaron Bentley
Implement shelf manager
338
        self.transport.delete(str(shelf_id))
339
340
    def active_shelves(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
341
        """Return a list of shelved changes."""
0.12.27 by Aaron Bentley
Implement shelf manager
342
        return [int(f) for f in self.transport.list_dir('.')]
343
344
    def last_shelf(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
345
        """Return the id of the last-created shelved change."""
0.12.27 by Aaron Bentley
Implement shelf manager
346
        active = self.active_shelves()
347
        if len(active) > 0:
348
            return max(active)
349
        else:
350
            return None