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