/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5387.2.7 by John Arbash Meinel
Merge bzr.dev 5444 to resolve some small text conflicts.
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
0.12.12 by Aaron Bentley
Implement shelf creator
2
#
0.12.80 by Aaron Bentley
Re-format GPL notifications
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.12.12 by Aaron Bentley
Implement shelf creator
16
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
17
import errno
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
18
import re
0.12.13 by Aaron Bentley
Implement shelving content
19
6734.1.1 by Jelmer Vernooij
Fix more imports.
20
from . import errors
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
21
from .lazy_import import lazy_import
5418.4.8 by Parth Malwankar
fixed import tariff
22
lazy_import(globals(), """
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
23
from breezy import (
2694.5.4 by Jelmer Vernooij
Move bzrlib.util.bencode to bzrlib._bencode_py.
24
    bencode,
0.15.15 by Aaron Bentley
Merge prepare-shelf into unshelve
25
    merge,
0.14.19 by Aaron Bentley
Convert bzrlib import to split-line
26
    merge3,
27
    transform,
28
)
6670.4.1 by Jelmer Vernooij
Update imports.
29
from breezy.bzr import (
30
    pack,
31
    )
5418.4.8 by Parth Malwankar
fixed import tariff
32
""")
0.12.19 by Aaron Bentley
Add support for writing shelves
33
0.12.12 by Aaron Bentley
Implement shelf creator
34
6734.1.1 by Jelmer Vernooij
Fix more imports.
35
class ShelfCorrupt(errors.BzrError):
36
37
    _fmt = "Shelf corrupt."
38
39
40
class NoSuchShelfId(errors.BzrError):
41
42
    _fmt = 'No changes are shelved with id "%(shelf_id)d".'
43
44
    def __init__(self, shelf_id):
45
        errors.BzrError.__init__(self, shelf_id=shelf_id)
46
47
48
class InvalidShelfId(errors.BzrError):
49
50
    _fmt = '"%(invalid_id)s" is not a valid shelf id, try a number instead.'
51
52
    def __init__(self, invalid_id):
53
        errors.BzrError.__init__(self, invalid_id=invalid_id)
54
55
0.12.12 by Aaron Bentley
Implement shelf creator
56
class ShelfCreator(object):
0.14.27 by Aaron Bentley
Update docs
57
    """Create a transform to shelve objects and its inverse."""
0.12.12 by Aaron Bentley
Implement shelf creator
58
0.14.21 by Aaron Bentley
Update to accept a list of files.
59
    def __init__(self, work_tree, target_tree, file_list=None):
0.14.27 by Aaron Bentley
Update docs
60
        """Constructor.
61
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
62
        :param work_tree: The working tree to apply changes to. This is not
63
            required to be locked - a tree_write lock will be taken out.
0.14.27 by Aaron Bentley
Update docs
64
        :param target_tree: The tree to make the working tree more similar to.
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
65
            This is not required to be locked - a read_lock will be taken out.
0.14.27 by Aaron Bentley
Update docs
66
        :param file_list: The files to make more similar to the target.
67
        """
0.12.12 by Aaron Bentley
Implement shelf creator
68
        self.work_tree = work_tree
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
69
        self.work_transform = work_tree.transform()
3873.2.1 by Benoît Pierre
Clean-up when an error occurs during the creation of a ShelfCreator: fix
70
        try:
4123.1.3 by Aaron Bentley
Properly handle exceptions during __init__
71
            self.target_tree = target_tree
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
72
            self.shelf_transform = self.target_tree.preview_transform()
4123.1.3 by Aaron Bentley
Properly handle exceptions during __init__
73
            try:
74
                self.renames = {}
75
                self.creation = {}
76
                self.deletion = {}
77
                self.iter_changes = work_tree.iter_changes(
78
                    self.target_tree, specific_files=file_list)
79
            except:
80
                self.shelf_transform.finalize()
81
                raise
82
        except:
83
            self.work_transform.finalize()
84
            raise
0.12.12 by Aaron Bentley
Implement shelf creator
85
0.14.32 by Aaron Bentley
Replace ShelfCreator.__iter__ with ShelfCreator.iter_shelvable
86
    def iter_shelvable(self):
0.14.27 by Aaron Bentley
Update docs
87
        """Iterable of tuples describing shelvable changes.
88
89
        As well as generating the tuples, this updates several members.
5891.1.3 by Andrew Bennetts
Move docstring formatting fixes.
90
        Tuples may be::
91
0.14.27 by Aaron Bentley
Update docs
92
           ('add file', file_id, work_kind, work_path)
93
           ('delete file', file_id, target_kind, target_path)
94
           ('rename', file_id, target_path, work_path)
95
           ('change kind', file_id, target_kind, work_kind, target_path)
96
           ('modify text', file_id)
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
97
           ('modify target', file_id, target_target, work_target)
0.14.27 by Aaron Bentley
Update docs
98
        """
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
99
        for change in self.iter_changes:
4595.9.1 by Aaron Bentley
Fix shelve in uncommitted trees.
100
            # don't shelve add of tree root.  Working tree should never
101
            # lack roots, and bzr misbehaves when they do.
102
            # FIXME ADHB (2009-08-09): should still shelve adds of tree roots
103
            # when a tree root was deleted / renamed.
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
104
            if change.kind[0] is None and change.name[1] == '':
4595.9.1 by Aaron Bentley
Fix shelve in uncommitted trees.
105
                continue
6011.1.2 by Aaron Bentley
Fix shelve to always ignore roots.
106
            # Also don't shelve deletion of tree root.
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
107
            if change.kind[1] is None and change.name[0] == '':
6011.1.2 by Aaron Bentley
Fix shelve to always ignore roots.
108
                continue
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
109
            if change.kind[0] is None or change.versioned[0] is False:
110
                self.creation[change.file_id] = (
111
                    change.kind[1], change.name[1], change.parent_id[1], change.versioned)
112
                yield ('add file', change.file_id, change.kind[1], change.path[1])
113
            elif change.kind[1] is None or change.versioned[0] is False:
114
                self.deletion[change.file_id] = (
115
                    change.kind[0], change.name[0], change.parent_id[0], change.versioned)
116
                yield ('delete file', change.file_id, change.kind[0], change.path[0])
0.12.14 by Aaron Bentley
Add shelving of created files
117
            else:
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
118
                if change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]:
119
                    self.renames[change.file_id] = (change.name, change.parent_id)
120
                    yield ('rename', change.file_id) + change.path
0.14.23 by Aaron Bentley
Allow shelving kind change
121
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
122
                if change.kind[0] != change.kind[1]:
123
                    yield ('change kind', change.file_id, change.kind[0], change.kind[1], change.path[0])
124
                elif change.kind[0] == 'symlink':
125
                    t_target = self.target_tree.get_symlink_target(change.path[0])
126
                    w_target = self.work_tree.get_symlink_target(change.path[1])
127
                    yield ('modify target', change.file_id, change.path[0], t_target,
7143.15.2 by Jelmer Vernooij
Run autopep8.
128
                           w_target)
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
129
                elif change.changed_content:
130
                    yield ('modify text', change.file_id)
0.12.12 by Aaron Bentley
Implement shelf creator
131
4526.6.1 by Aaron Bentley
Reverse the way changes are described by Shelver.
132
    def shelve_change(self, change):
4526.7.2 by Aaron Bentley
Update docs.
133
        """Shelve a change in the iter_shelvable format."""
4526.6.1 by Aaron Bentley
Reverse the way changes are described by Shelver.
134
        if change[0] == 'rename':
135
            self.shelve_rename(change[1])
136
        elif change[0] == 'delete file':
137
            self.shelve_deletion(change[1])
138
        elif change[0] == 'add file':
139
            self.shelve_creation(change[1])
4595.8.1 by Aaron Bentley
shelve_change handles text modification.
140
        elif change[0] in ('change kind', 'modify text'):
4526.6.1 by Aaron Bentley
Reverse the way changes are described by Shelver.
141
            self.shelve_content_change(change[1])
142
        elif change[0] == 'modify target':
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
143
            self.shelve_modify_target(change[1])
4526.7.3 by Aaron Bentley
Test shelve_change.
144
        else:
145
            raise ValueError('Unknown change kind: "%s"' % change[0])
4526.6.1 by Aaron Bentley
Reverse the way changes are described by Shelver.
146
4595.8.2 by Aaron Bentley
Implement shelve_all
147
    def shelve_all(self):
6538.1.7 by Aaron Bentley
Move to shelve_all and improve it.
148
        """Shelve all changes.
149
7183.3.1 by Martin
Fix E71* lint errors
150
        :return: ``True`` if changes were shelved, otherwise ``False``.
6538.1.7 by Aaron Bentley
Move to shelve_all and improve it.
151
        """
152
        change = None
4595.8.2 by Aaron Bentley
Implement shelve_all
153
        for change in self.iter_shelvable():
154
            self.shelve_change(change)
6538.1.7 by Aaron Bentley
Move to shelve_all and improve it.
155
        return change is not None
4595.8.2 by Aaron Bentley
Implement shelve_all
156
0.12.12 by Aaron Bentley
Implement shelf creator
157
    def shelve_rename(self, file_id):
0.14.27 by Aaron Bentley
Update docs
158
        """Shelve a file rename.
159
160
        :param file_id: The file id of the file to shelve the renaming of.
161
        """
0.12.12 by Aaron Bentley
Implement shelf creator
162
        names, parents = self.renames[file_id]
163
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
164
        work_parent = self.work_transform.trans_id_file_id(parents[0])
165
        self.work_transform.adjust_path(names[0], work_parent, w_trans_id)
166
167
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
168
        shelf_parent = self.shelf_transform.trans_id_file_id(parents[1])
169
        self.shelf_transform.adjust_path(names[1], shelf_parent, s_trans_id)
170
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
171
    def shelve_modify_target(self, file_id):
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
172
        """Shelve a change of symlink target.
173
174
        :param file_id: The file id of the symlink which changed target.
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
175
        :param new_target: The target that the symlink should have due
176
            to shelving.
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
177
        """
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
178
        new_path = self.target_tree.id2path(file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
179
        new_target = self.target_tree.get_symlink_target(new_path)
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
180
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
181
        self.work_transform.delete_contents(w_trans_id)
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
182
        self.work_transform.create_symlink(new_target, w_trans_id)
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
183
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
184
        old_path = self.work_tree.id2path(file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
185
        old_target = self.work_tree.get_symlink_target(old_path)
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
186
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
187
        self.shelf_transform.delete_contents(s_trans_id)
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
188
        self.shelf_transform.create_symlink(old_target, s_trans_id)
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
189
0.14.14 by Aaron Bentley
Change shelf_text to shelve_lines
190
    def shelve_lines(self, file_id, new_lines):
0.14.27 by Aaron Bentley
Update docs
191
        """Shelve text changes to a file, using provided lines.
192
193
        :param file_id: The file id of the file to shelve the text of.
194
        :param new_lines: The lines that the file should have due to shelving.
195
        """
0.12.13 by Aaron Bentley
Implement shelving content
196
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
197
        self.work_transform.delete_contents(w_trans_id)
198
        self.work_transform.create_file(new_lines, w_trans_id)
199
200
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
201
        self.shelf_transform.delete_contents(s_trans_id)
202
        inverse_lines = self._inverse_lines(new_lines, file_id)
203
        self.shelf_transform.create_file(inverse_lines, s_trans_id)
204
0.14.23 by Aaron Bentley
Allow shelving kind change
205
    @staticmethod
206
    def _content_from_tree(tt, tree, file_id):
207
        trans_id = tt.trans_id_file_id(file_id)
208
        tt.delete_contents(trans_id)
7350.5.1 by Jelmer Vernooij
Remove file_id from transform's create_from_tree, get filter tree paths by path.
209
        transform.create_from_tree(tt, trans_id, tree, tree.id2path(file_id))
0.14.23 by Aaron Bentley
Allow shelving kind change
210
211
    def shelve_content_change(self, file_id):
0.14.27 by Aaron Bentley
Update docs
212
        """Shelve a kind change or binary file content change.
213
214
        :param file_id: The file id of the file to shelve the content change
215
            of.
216
        """
0.14.23 by Aaron Bentley
Allow shelving kind change
217
        self._content_from_tree(self.work_transform, self.target_tree, file_id)
218
        self._content_from_tree(self.shelf_transform, self.work_tree, file_id)
219
0.14.2 by Aaron Bentley
Somewhat clean up shelving
220
    def shelve_creation(self, file_id):
0.14.27 by Aaron Bentley
Update docs
221
        """Shelve creation of a file.
222
223
        This handles content and inventory id.
224
        :param file_id: The file_id of the file to shelve creation of.
225
        """
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
226
        kind, name, parent, versioned = self.creation[file_id]
227
        version = not versioned[0]
0.14.4 by Aaron Bentley
Implement shelving deletion
228
        self._shelve_creation(self.work_tree, file_id, self.work_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
229
                              self.shelf_transform, kind, name, parent,
230
                              version)
0.14.4 by Aaron Bentley
Implement shelving deletion
231
232
    def shelve_deletion(self, file_id):
0.14.27 by Aaron Bentley
Update docs
233
        """Shelve deletion of a file.
234
235
        This handles content and inventory id.
236
        :param file_id: The file_id of the file to shelve deletion of.
237
        """
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
238
        kind, name, parent, versioned = self.deletion[file_id]
239
        existing_path = self.target_tree.id2path(file_id)
240
        if not self.work_tree.has_filename(existing_path):
241
            existing_path = None
242
        version = not versioned[1]
0.14.4 by Aaron Bentley
Implement shelving deletion
243
        self._shelve_creation(self.target_tree, file_id, self.shelf_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
244
                              self.work_transform, kind, name, parent,
245
                              version, existing_path=existing_path)
0.14.4 by Aaron Bentley
Implement shelving deletion
246
247
    def _shelve_creation(self, tree, file_id, from_transform, to_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
248
                         kind, name, parent, version, existing_path=None):
0.14.4 by Aaron Bentley
Implement shelving deletion
249
        w_trans_id = from_transform.trans_id_file_id(file_id)
0.14.12 by Aaron Bentley
Handle new dangling ids
250
        if parent is not None and kind is not None:
0.14.4 by Aaron Bentley
Implement shelving deletion
251
            from_transform.delete_contents(w_trans_id)
252
        from_transform.unversion_file(w_trans_id)
253
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
254
        if existing_path is not None:
255
            s_trans_id = to_transform.trans_id_tree_path(existing_path)
256
        else:
257
            s_trans_id = to_transform.trans_id_file_id(file_id)
0.14.4 by Aaron Bentley
Implement shelving deletion
258
        if parent is not None:
259
            s_parent_id = to_transform.trans_id_file_id(parent)
0.14.9 by Aaron Bentley
Shelve deleted files properly
260
            to_transform.adjust_path(name, s_parent_id, s_trans_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
261
            if existing_path is None:
0.14.18 by Aaron Bentley
Simplify creating files
262
                if kind is None:
6973.11.7 by Jelmer Vernooij
Fix more tests.
263
                    to_transform.create_file([b''], s_trans_id)
0.14.18 by Aaron Bentley
Simplify creating files
264
                else:
6809.4.21 by Jelmer Vernooij
Fix long lines.
265
                    transform.create_from_tree(
7143.15.2 by Jelmer Vernooij
Run autopep8.
266
                        to_transform, s_trans_id, tree,
7350.5.1 by Jelmer Vernooij
Remove file_id from transform's create_from_tree, get filter tree paths by path.
267
                        tree.id2path(file_id))
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
268
        if version:
7490.77.8 by Jelmer Vernooij
Change argument order for Transform.version_file.
269
            to_transform.version_file(s_trans_id, file_id=file_id)
0.12.14 by Aaron Bentley
Add shelving of created files
270
271
    def _inverse_lines(self, new_lines, file_id):
272
        """Produce a version with only those changes removed from new_lines."""
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
273
        target_path = self.target_tree.id2path(file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
274
        target_lines = self.target_tree.get_file_lines(target_path)
6809.4.14 by Jelmer Vernooij
Fix shelf failures.
275
        work_path = self.work_tree.id2path(file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
276
        work_lines = self.work_tree.get_file_lines(work_path)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
277
        return merge3.Merge3(new_lines, target_lines, work_lines).merge_lines()
0.12.13 by Aaron Bentley
Implement shelving content
278
0.12.12 by Aaron Bentley
Implement shelf creator
279
    def finalize(self):
0.14.27 by Aaron Bentley
Update docs
280
        """Release all resources used by this ShelfCreator."""
0.12.12 by Aaron Bentley
Implement shelf creator
281
        self.work_transform.finalize()
282
        self.shelf_transform.finalize()
0.12.13 by Aaron Bentley
Implement shelving content
283
284
    def transform(self):
0.14.27 by Aaron Bentley
Update docs
285
        """Shelve changes from working tree."""
0.12.13 by Aaron Bentley
Implement shelving content
286
        self.work_transform.apply()
0.12.19 by Aaron Bentley
Add support for writing shelves
287
6538.1.8 by Aaron Bentley
Implement branch.get_uncommitted_data.
288
    @staticmethod
289
    def metadata_record(serializer, revision_id, message=None):
6855.4.5 by Jelmer Vernooij
Fix more bees, use with rather than try/finally for some files.
290
        metadata = {b'revision_id': revision_id}
6538.1.8 by Aaron Bentley
Implement branch.get_uncommitted_data.
291
        if message is not None:
6855.4.5 by Jelmer Vernooij
Fix more bees, use with rather than try/finally for some files.
292
            metadata[b'message'] = message.encode('utf-8')
6538.1.8 by Aaron Bentley
Implement branch.get_uncommitted_data.
293
        return serializer.bytes_record(
6973.6.2 by Jelmer Vernooij
Fix more tests.
294
            bencode.bencode(metadata), ((b'metadata',),))
6538.1.8 by Aaron Bentley
Implement branch.get_uncommitted_data.
295
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
296
    def write_shelf(self, shelf_file, message=None):
0.14.27 by Aaron Bentley
Update docs
297
        """Serialize the shelved changes to a file.
298
0.12.66 by Aaron Bentley
Merge with unshelve
299
        :param shelf_file: A file-like object to write the shelf to.
0.15.29 by Aaron Bentley
Merge with prepare-shelf
300
        :param message: An optional message describing the shelved changes.
0.14.27 by Aaron Bentley
Update docs
301
        :return: the filename of the written file.
302
        """
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
303
        transform.resolve_conflicts(self.shelf_transform)
6538.1.10 by Aaron Bentley
Implement WorkingTree.get_uncommitted_data
304
        revision_id = self.target_tree.get_revision_id()
305
        return self._write_shelf(shelf_file, self.shelf_transform, revision_id,
306
                                 message)
307
308
    @classmethod
309
    def _write_shelf(cls, shelf_file, transform, revision_id, message=None):
0.12.28 by Aaron Bentley
Update for shelf manager
310
        serializer = pack.ContainerSerialiser()
311
        shelf_file.write(serializer.begin())
6538.1.10 by Aaron Bentley
Implement WorkingTree.get_uncommitted_data
312
        metadata = cls.metadata_record(serializer, revision_id, message)
6538.1.8 by Aaron Bentley
Implement branch.get_uncommitted_data.
313
        shelf_file.write(metadata)
6538.1.10 by Aaron Bentley
Implement WorkingTree.get_uncommitted_data
314
        for bytes in transform.serialize(serializer):
0.12.28 by Aaron Bentley
Update for shelf manager
315
            shelf_file.write(bytes)
316
        shelf_file.write(serializer.end())
0.12.21 by Aaron Bentley
Add failing test of unshelver
317
318
319
class Unshelver(object):
0.15.30 by Aaron Bentley
Update docs.
320
    """Unshelve shelved changes."""
0.12.21 by Aaron Bentley
Add failing test of unshelver
321
0.15.19 by Aaron Bentley
Generalize first record as metadata.
322
    def __init__(self, tree, base_tree, transform, message):
0.15.30 by Aaron Bentley
Update docs.
323
        """Constructor.
324
325
        :param tree: The tree to apply the changes to.
326
        :param base_tree: The basis to apply the tranform to.
327
        :param message: A message from the shelved transform.
328
        """
0.12.21 by Aaron Bentley
Add failing test of unshelver
329
        self.tree = tree
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
330
        self.base_tree = base_tree
0.12.21 by Aaron Bentley
Add failing test of unshelver
331
        self.transform = transform
0.15.19 by Aaron Bentley
Generalize first record as metadata.
332
        self.message = message
0.12.21 by Aaron Bentley
Add failing test of unshelver
333
0.16.110 by Aaron Bentley
Implement ls-shelf command
334
    @staticmethod
335
    def iter_records(shelf_file):
0.12.21 by Aaron Bentley
Add failing test of unshelver
336
        parser = pack.ContainerPushParser()
0.12.28 by Aaron Bentley
Update for shelf manager
337
        parser.accept_bytes(shelf_file.read())
0.16.110 by Aaron Bentley
Implement ls-shelf command
338
        return iter(parser.read_pending_records())
339
340
    @staticmethod
341
    def parse_metadata(records):
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
342
        names, metadata_bytes = next(records)
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
343
        if names[0] != (b'metadata',):
6734.1.1 by Jelmer Vernooij
Fix more imports.
344
            raise ShelfCorrupt
0.15.19 by Aaron Bentley
Generalize first record as metadata.
345
        metadata = bencode.bdecode(metadata_bytes)
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
346
        message = metadata.get(b'message')
0.15.19 by Aaron Bentley
Generalize first record as metadata.
347
        if message is not None:
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
348
            metadata[b'message'] = message.decode('utf-8')
0.16.111 by Aaron Bentley
Return metadata as a dict.
349
        return metadata
0.16.110 by Aaron Bentley
Implement ls-shelf command
350
351
    @classmethod
352
    def from_tree_and_shelf(klass, tree, shelf_file):
353
        """Create an Unshelver from a tree and a shelf file.
354
355
        :param tree: The tree to apply shelved changes to.
356
        :param shelf_file: A file-like object containing shelved changes.
357
        :return: The Unshelver.
358
        """
359
        records = klass.iter_records(shelf_file)
0.16.111 by Aaron Bentley
Return metadata as a dict.
360
        metadata = klass.parse_metadata(records)
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
361
        base_revision_id = metadata[b'revision_id']
0.12.26 by Aaron Bentley
Use correct base for shelving
362
        try:
363
            base_tree = tree.revision_tree(base_revision_id)
364
        except errors.NoSuchRevisionInTree:
365
            base_tree = tree.branch.repository.revision_tree(base_revision_id)
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
366
        tt = base_tree.preview_transform()
0.15.26 by Aaron Bentley
Merge with prepare-shelf
367
        tt.deserialize(records)
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
368
        return klass(tree, base_tree, tt, metadata.get(b'message'))
0.12.21 by Aaron Bentley
Add failing test of unshelver
369
6719.1.2 by Jelmer Vernooij
Fix some tests.
370
    def make_merger(self):
0.15.30 by Aaron Bentley
Update docs.
371
        """Return a merger that can unshelve the changes."""
1551.21.7 by Aaron Bentley
Fix progress warning
372
        target_tree = self.transform.get_preview_tree()
373
        merger = merge.Merger.from_uncommitted(self.tree, target_tree,
7143.15.2 by Jelmer Vernooij
Run autopep8.
374
                                               self.base_tree)
1551.21.7 by Aaron Bentley
Fix progress warning
375
        merger.merge_type = merge.Merge3Merger
376
        return merger
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
377
378
    def finalize(self):
0.15.30 by Aaron Bentley
Update docs.
379
        """Release all resources held by this Unshelver."""
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
380
        self.transform.finalize()
0.12.27 by Aaron Bentley
Implement shelf manager
381
382
383
class ShelfManager(object):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
384
    """Maintain a list of shelved changes."""
0.12.27 by Aaron Bentley
Implement shelf manager
385
0.12.42 by Aaron Bentley
Get shelf from tree
386
    def __init__(self, tree, transport):
387
        self.tree = tree
0.12.41 by Aaron Bentley
Change shelf to use WT control dir for shelves
388
        self.transport = transport.clone('shelf')
0.12.27 by Aaron Bentley
Implement shelf manager
389
        self.transport.ensure_base()
390
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
391
    def get_shelf_filename(self, shelf_id):
392
        return 'shelf-%d' % shelf_id
393
394
    def get_shelf_ids(self, filenames):
395
        matcher = re.compile('shelf-([1-9][0-9]*)')
396
        shelf_ids = []
397
        for filename in filenames:
398
            match = matcher.match(filename)
399
            if match is not None:
400
                shelf_ids.append(int(match.group(1)))
401
        return shelf_ids
402
0.12.27 by Aaron Bentley
Implement shelf manager
403
    def new_shelf(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
404
        """Return a file object and id for a new set of shelved changes."""
0.12.27 by Aaron Bentley
Implement shelf manager
405
        last_shelf = self.last_shelf()
406
        if last_shelf is None:
407
            next_shelf = 1
408
        else:
409
            next_shelf = last_shelf + 1
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
410
        filename = self.get_shelf_filename(next_shelf)
411
        shelf_file = open(self.transport.local_abspath(filename), 'wb')
0.12.27 by Aaron Bentley
Implement shelf manager
412
        return next_shelf, shelf_file
413
0.12.53 by Aaron Bentley
Allow adding message to shelf
414
    def shelve_changes(self, creator, message=None):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
415
        """Store the changes in a ShelfCreator on a shelf."""
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
416
        next_shelf, shelf_file = self.new_shelf()
417
        try:
0.12.53 by Aaron Bentley
Allow adding message to shelf
418
            creator.write_shelf(shelf_file, message)
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
419
        finally:
420
            shelf_file.close()
0.12.44 by Aaron Bentley
Give manager responsibility for applying transform
421
        creator.transform()
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
422
        return next_shelf
423
0.12.27 by Aaron Bentley
Implement shelf manager
424
    def read_shelf(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
425
        """Return the file associated with a shelf_id for reading.
426
427
        :param shelf_id: The id of the shelf to retrive the file for.
428
        """
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
429
        filename = self.get_shelf_filename(shelf_id)
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
430
        try:
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
431
            return open(self.transport.local_abspath(filename), 'rb')
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
432
        except IOError as e:
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
433
            if e.errno != errno.ENOENT:
434
                raise
6734.1.1 by Jelmer Vernooij
Fix more imports.
435
            raise NoSuchShelfId(shelf_id)
0.12.27 by Aaron Bentley
Implement shelf manager
436
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
437
    def get_unshelver(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
438
        """Return an unshelver for a given shelf_id.
439
440
        :param shelf_id: The shelf id to return the unshelver for.
441
        """
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
442
        shelf_file = self.read_shelf(shelf_id)
443
        try:
444
            return Unshelver.from_tree_and_shelf(self.tree, shelf_file)
445
        finally:
446
            shelf_file.close()
447
0.16.112 by Aaron Bentley
Add tests
448
    def get_metadata(self, shelf_id):
449
        """Return the metadata associated with a given shelf_id."""
0.16.110 by Aaron Bentley
Implement ls-shelf command
450
        shelf_file = self.read_shelf(shelf_id)
451
        try:
452
            records = Unshelver.iter_records(shelf_file)
453
        finally:
454
            shelf_file.close()
455
        return Unshelver.parse_metadata(records)
456
0.12.27 by Aaron Bentley
Implement shelf manager
457
    def delete_shelf(self, shelf_id):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
458
        """Delete the shelved changes for a given id.
459
460
        :param shelf_id: id of the shelved changes to delete.
461
        """
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
462
        filename = self.get_shelf_filename(shelf_id)
463
        self.transport.delete(filename)
0.12.27 by Aaron Bentley
Implement shelf manager
464
465
    def active_shelves(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
466
        """Return a list of shelved changes."""
6619.3.18 by Jelmer Vernooij
Run 2to3 idioms fixer.
467
        active = sorted(self.get_shelf_ids(self.transport.list_dir('.')))
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
468
        return active
0.12.27 by Aaron Bentley
Implement shelf manager
469
470
    def last_shelf(self):
0.12.68 by Aaron Bentley
Update docs, move items to proper files.
471
        """Return the id of the last-created shelved change."""
0.12.27 by Aaron Bentley
Implement shelf manager
472
        active = self.active_shelves()
473
        if len(active) > 0:
0.12.77 by Aaron Bentley
Use names of the form shelf-5 for shelves
474
            return active[-1]
0.12.27 by Aaron Bentley
Implement shelf manager
475
        else:
476
            return None