/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.14.21 by Aaron Bentley
Update to accept a list of files.
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
63
                if changed:
64
                    yield ('modify text', file_id)
0.12.12 by Aaron Bentley
Implement shelf creator
65
66
    def shelve_rename(self, file_id):
67
        names, parents = self.renames[file_id]
68
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
69
        work_parent = self.work_transform.trans_id_file_id(parents[0])
70
        self.work_transform.adjust_path(names[0], work_parent, w_trans_id)
71
72
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
73
        shelf_parent = self.shelf_transform.trans_id_file_id(parents[1])
74
        self.shelf_transform.adjust_path(names[1], shelf_parent, s_trans_id)
75
0.14.14 by Aaron Bentley
Change shelf_text to shelve_lines
76
    def shelve_lines(self, file_id, new_lines):
0.12.13 by Aaron Bentley
Implement shelving content
77
        w_trans_id = self.work_transform.trans_id_file_id(file_id)
78
        self.work_transform.delete_contents(w_trans_id)
79
        self.work_transform.create_file(new_lines, w_trans_id)
80
81
        s_trans_id = self.shelf_transform.trans_id_file_id(file_id)
82
        self.shelf_transform.delete_contents(s_trans_id)
83
        inverse_lines = self._inverse_lines(new_lines, file_id)
84
        self.shelf_transform.create_file(inverse_lines, s_trans_id)
85
0.14.2 by Aaron Bentley
Somewhat clean up shelving
86
    def shelve_creation(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
87
        kind, name, parent, versioned = self.creation[file_id]
88
        version = not versioned[0]
0.14.4 by Aaron Bentley
Implement shelving deletion
89
        self._shelve_creation(self.work_tree, file_id, self.work_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
90
                              self.shelf_transform, kind, name, parent,
91
                              version)
0.14.4 by Aaron Bentley
Implement shelving deletion
92
93
    def shelve_deletion(self, file_id):
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
94
        kind, name, parent, versioned = self.deletion[file_id]
95
        existing_path = self.target_tree.id2path(file_id)
96
        if not self.work_tree.has_filename(existing_path):
97
            existing_path = None
98
        version = not versioned[1]
0.14.4 by Aaron Bentley
Implement shelving deletion
99
        self._shelve_creation(self.target_tree, file_id, self.shelf_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
100
                              self.work_transform, kind, name, parent,
101
                              version, existing_path=existing_path)
0.14.4 by Aaron Bentley
Implement shelving deletion
102
103
    def _shelve_creation(self, tree, file_id, from_transform, to_transform,
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
104
                         kind, name, parent, version, existing_path=None):
0.14.4 by Aaron Bentley
Implement shelving deletion
105
        w_trans_id = from_transform.trans_id_file_id(file_id)
0.14.12 by Aaron Bentley
Handle new dangling ids
106
        if parent is not None and kind is not None:
0.14.4 by Aaron Bentley
Implement shelving deletion
107
            from_transform.delete_contents(w_trans_id)
108
        from_transform.unversion_file(w_trans_id)
109
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
110
        if existing_path is not None:
111
            s_trans_id = to_transform.trans_id_tree_path(existing_path)
112
        else:
113
            s_trans_id = to_transform.trans_id_file_id(file_id)
0.14.4 by Aaron Bentley
Implement shelving deletion
114
        if parent is not None:
115
            s_parent_id = to_transform.trans_id_file_id(parent)
0.14.9 by Aaron Bentley
Shelve deleted files properly
116
            to_transform.adjust_path(name, s_parent_id, s_trans_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
117
            if existing_path is None:
0.14.18 by Aaron Bentley
Simplify creating files
118
                if kind is None:
0.14.12 by Aaron Bentley
Handle new dangling ids
119
                    to_transform.create_file('', s_trans_id)
0.14.18 by Aaron Bentley
Simplify creating files
120
                else:
121
                    transform.create_from_tree(to_transform, s_trans_id,
122
                                               tree, file_id)
0.14.10 by Aaron Bentley
Fix behavior with deletions, unversioning, ...
123
        if version:
124
            to_transform.version_file(file_id, s_trans_id)
0.12.14 by Aaron Bentley
Add shelving of created files
125
0.14.4 by Aaron Bentley
Implement shelving deletion
126
    def read_tree_lines(self, tree, file_id):
0.14.17 by Aaron Bentley
Use safer line-splitting
127
        return osutils.split_lines(tree.get_file_text(file_id))
0.12.14 by Aaron Bentley
Add shelving of created files
128
129
    def _inverse_lines(self, new_lines, file_id):
130
        """Produce a version with only those changes removed from new_lines."""
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
131
        target_lines = self.target_tree.get_file_lines(file_id)
0.14.5 by Aaron Bentley
Fix call to read_tree_lines
132
        work_lines = self.read_tree_lines(self.work_tree, file_id)
0.14.1 by Aaron Bentley
Use explicit target in ShelfCreator
133
        return merge3.Merge3(new_lines, target_lines, work_lines).merge_lines()
0.12.13 by Aaron Bentley
Implement shelving content
134
0.12.12 by Aaron Bentley
Implement shelf creator
135
    def finalize(self):
136
        self.work_transform.finalize()
137
        self.shelf_transform.finalize()
0.12.13 by Aaron Bentley
Implement shelving content
138
139
    def transform(self):
140
        self.work_transform.apply()
0.12.19 by Aaron Bentley
Add support for writing shelves
141
142
    def make_shelf_filename(self):
143
        transport = self.work_tree.bzrdir.root_transport.clone('.shelf2')
144
        transport.ensure_base()
145
        return transport.local_abspath('01')
146
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
147
    def write_shelf(self, shelf_file, message=None):
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
148
        transform.resolve_conflicts(self.shelf_transform)
0.12.28 by Aaron Bentley
Update for shelf manager
149
        serializer = pack.ContainerSerialiser()
150
        shelf_file.write(serializer.begin())
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
151
        metadata = {
152
            'revision_id': self.target_tree.get_revision_id(),
153
        }
154
        if message is not None:
0.12.52 by Aaron Bentley
Merge unshelve into shelf-manager
155
            metadata['message'] = message.encode('utf-8')
0.12.28 by Aaron Bentley
Update for shelf manager
156
        shelf_file.write(serializer.bytes_record(
0.12.51 by Aaron Bentley
Merge unshelve into shelf-manager
157
            bencode.bencode(metadata), (('metadata',),)))
0.12.28 by Aaron Bentley
Update for shelf manager
158
        for bytes in serialize_transform.serialize(
159
            self.shelf_transform, serializer):
160
            shelf_file.write(bytes)
161
        shelf_file.write(serializer.end())
0.12.21 by Aaron Bentley
Add failing test of unshelver
162
163
164
class Unshelver(object):
165
0.15.19 by Aaron Bentley
Generalize first record as metadata.
166
    def __init__(self, tree, base_tree, transform, message):
0.12.21 by Aaron Bentley
Add failing test of unshelver
167
        self.tree = tree
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
168
        self.base_tree = base_tree
0.12.21 by Aaron Bentley
Add failing test of unshelver
169
        self.transform = transform
0.15.19 by Aaron Bentley
Generalize first record as metadata.
170
        self.message = message
0.12.21 by Aaron Bentley
Add failing test of unshelver
171
172
    @classmethod
0.12.28 by Aaron Bentley
Update for shelf manager
173
    def from_tree_and_shelf(klass, tree, shelf_file):
0.12.21 by Aaron Bentley
Add failing test of unshelver
174
        parser = pack.ContainerPushParser()
0.12.28 by Aaron Bentley
Update for shelf manager
175
        parser.accept_bytes(shelf_file.read())
0.12.24 by Aaron Bentley
Get unshelve using merge codepath, not applying transform directly
176
        tt = transform.TransformPreview(tree)
0.12.21 by Aaron Bentley
Add failing test of unshelver
177
        records = iter(parser.read_pending_records())
0.15.19 by Aaron Bentley
Generalize first record as metadata.
178
        names, metadata_bytes = records.next()
179
        assert names[0] == ('metadata',)
0.12.21 by Aaron Bentley
Add failing test of unshelver
180
        serialize_transform.deserialize(tt, records)
0.15.19 by Aaron Bentley
Generalize first record as metadata.
181
        metadata = bencode.bdecode(metadata_bytes)
182
        base_revision_id = metadata['revision_id']
183
        message = metadata.get('message')
184
        if message is not None:
185
            message = message.decode('utf-8')
0.12.26 by Aaron Bentley
Use correct base for shelving
186
        try:
187
            base_tree = tree.revision_tree(base_revision_id)
188
        except errors.NoSuchRevisionInTree:
189
            base_tree = tree.branch.repository.revision_tree(base_revision_id)
0.15.19 by Aaron Bentley
Generalize first record as metadata.
190
        return klass(tree, base_tree, tt, message)
0.12.21 by Aaron Bentley
Add failing test of unshelver
191
0.15.18 by Aaron Bentley
Unshelve takes a change_reporter parameter
192
    def unshelve(self, change_reporter=None):
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
193
        pb = ui.ui_factory.nested_progress_bar()
194
        try:
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
195
            merger = self.get_merger()
196
            merger.change_reporter = change_reporter
197
            merger.do_merge()
198
        finally:
199
            pb.finished()
200
201
    def get_merger(self):
202
        pb = ui.ui_factory.nested_progress_bar()
203
        try:
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
204
            target_tree = self.transform.get_preview_tree()
205
            merger = merge.Merger.from_uncommitted(self.tree, target_tree, pb,
206
                                                   self.base_tree)
207
            merger.merge_type = merge.Merge3Merger
0.15.22 by Aaron Bentley
Add direct access to Merger from Unshelver
208
            return merger
0.12.25 by Aaron Bentley
Update to use new from_uncommitted API
209
        finally:
210
            pb.finished()
211
212
    def finalize(self):
213
        self.transform.finalize()
0.12.27 by Aaron Bentley
Implement shelf manager
214
215
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
216
class NoSuchShelfId(errors.BzrError):
217
218
    _fmt = 'No changes are shelved with id "%(shelf_id)d".'
219
220
    def __init__(self, shelf_id):
221
        errors.BzrError.__init__(self, shelf_id=shelf_id)
222
0.12.27 by Aaron Bentley
Implement shelf manager
223
class ShelfManager(object):
224
0.12.42 by Aaron Bentley
Get shelf from tree
225
    def __init__(self, tree, transport):
226
        self.tree = tree
0.12.41 by Aaron Bentley
Change shelf to use WT control dir for shelves
227
        self.transport = transport.clone('shelf')
0.12.27 by Aaron Bentley
Implement shelf manager
228
        self.transport.ensure_base()
229
230
    def new_shelf(self):
231
        last_shelf = self.last_shelf()
232
        if last_shelf is None:
233
            next_shelf = 1
234
        else:
235
            next_shelf = last_shelf + 1
236
        shelf_file = open(self.transport.local_abspath(str(next_shelf)), 'wb')
237
        return next_shelf, shelf_file
238
0.12.53 by Aaron Bentley
Allow adding message to shelf
239
    def shelve_changes(self, creator, message=None):
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
240
        next_shelf, shelf_file = self.new_shelf()
241
        try:
0.12.53 by Aaron Bentley
Allow adding message to shelf
242
            creator.write_shelf(shelf_file, message)
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
243
        finally:
244
            shelf_file.close()
0.12.44 by Aaron Bentley
Give manager responsibility for applying transform
245
        creator.transform()
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
246
        return next_shelf
247
0.12.27 by Aaron Bentley
Implement shelf manager
248
    def read_shelf(self, shelf_id):
0.12.50 by Aaron Bentley
Improve error handling for non-existant shelf-ids
249
        try:
250
            return open(self.transport.local_abspath(str(shelf_id)), 'rb')
251
        except IOError, e:
252
            if e.errno != errno.ENOENT:
253
                raise
254
            raise NoSuchShelfId(shelf_id)
0.12.27 by Aaron Bentley
Implement shelf manager
255
0.12.43 by Aaron Bentley
Make ShelfManager consume ShelfCreator and produce Unshelver
256
    def get_unshelver(self, shelf_id):
257
        shelf_file = self.read_shelf(shelf_id)
258
        try:
259
            return Unshelver.from_tree_and_shelf(self.tree, shelf_file)
260
        finally:
261
            shelf_file.close()
262
0.12.27 by Aaron Bentley
Implement shelf manager
263
    def delete_shelf(self, shelf_id):
264
        self.transport.delete(str(shelf_id))
265
266
    def active_shelves(self):
267
        return [int(f) for f in self.transport.list_dir('.')]
268
269
    def last_shelf(self):
270
        active = self.active_shelves()
271
        if len(active) > 0:
272
            return max(active)
273
        else:
274
            return None
0.12.42 by Aaron Bentley
Get shelf from tree
275
276
277
def get_shelf_manager(self):
278
    return ShelfManager(self, self._transport)
279
280
281
workingtree.WorkingTree.get_shelf_manager = get_shelf_manager