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