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