~bzr-pqm/bzr/bzr.dev

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