/brz/remove-bazaar

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