/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.16.101 by Aaron Bentley
Update GPL formatting and copyright
1
# Copyright (C) 2008 Canonical Ltd
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
0.16.1 by Aaron Bentley
Begin implementing UI
16
17
18
from cStringIO import StringIO
0.16.5 by Aaron Bentley
Get text shelving working
19
import shutil
0.16.1 by Aaron Bentley
Begin implementing UI
20
import sys
0.16.5 by Aaron Bentley
Get text shelving working
21
import tempfile
0.16.1 by Aaron Bentley
Begin implementing UI
22
0.16.25 by Aaron Bentley
Show selected changes before shelving
23
from bzrlib import (
24
    builtins,
25
    delta,
26
    diff,
27
    errors,
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
28
    osutils,
0.16.25 by Aaron Bentley
Show selected changes before shelving
29
    patches,
0.16.74 by Aaron Bentley
Merge with shelf-manager
30
    shelf,
0.16.72 by Aaron Bentley
Allow shelving binary changes
31
    textfile,
0.16.54 by Aaron Bentley
Inform user about shelf ids.
32
    trace,
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
33
    ui,
0.16.102 by Aaron Bentley
Minor updates
34
    workingtree,
35
)
3835.2.6 by Aaron Bentley
Restore vila's colordiff change
36
37
38
# Plugins may want to override the following
39
diff_writer_factory = None
0.16.1 by Aaron Bentley
Begin implementing UI
40
41
42
class Shelver(object):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
43
    """Interactively shelve the changes in a working tree."""
0.16.1 by Aaron Bentley
Begin implementing UI
44
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
45
    def __init__(self, work_tree, target_tree, auto=False,
0.16.57 by Aaron Bentley
Expose messages in the UI
46
                 auto_apply=False, file_list=None, message=None):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
47
        """Constructor.
48
49
        :param work_tree: The working tree to shelve changes from.
50
        :param target_tree: The "unchanged" / old tree to compare the
51
            work_tree to.
52
        :param auto: If True, shelve each possible change.
53
        :param auto_apply: If True, shelve changes with no final prompt.
0.16.102 by Aaron Bentley
Minor updates
54
        :param file_list: If supplied, only files in this list may be shelved.
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
55
        :param message: The message to associate with the shelved changes.
56
        """
0.16.1 by Aaron Bentley
Begin implementing UI
57
        self.work_tree = work_tree
58
        self.target_tree = target_tree
3835.2.6 by Aaron Bentley
Restore vila's colordiff change
59
        if diff_writer_factory is not None:
60
            self.diff_writer = diff_writer_factory(target=sys.stdout,
61
                                                   check_style=False)
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
62
        else:
63
            self.diff_writer = sys.stdout
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
64
        self.manager = work_tree.get_shelf_manager()
0.16.15 by Aaron Bentley
Implement auto mode
65
        self.auto = auto
0.16.23 by Aaron Bentley
Improve prompting
66
        self.auto_apply = auto_apply
0.16.47 by Aaron Bentley
Support selecting files to shelve
67
        self.file_list = file_list
0.16.57 by Aaron Bentley
Expose messages in the UI
68
        self.message = message
0.16.1 by Aaron Bentley
Begin implementing UI
69
70
    @classmethod
0.16.57 by Aaron Bentley
Expose messages in the UI
71
    def from_args(klass, revision=None, all=False, file_list=None,
0.16.94 by Aaron Bentley
Add unshelve tests
72
                  message=None, directory='.'):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
73
        """Create a shelver from commandline arguments.
74
75
        :param revision: RevisionSpec of the revision to compare to.
76
        :param all: If True, shelve all changes without prompting.
77
        :param file_list: If supplied, only files in this list may be  shelved.
78
        :param message: The message to associate with the shelved changes.
79
        :param directory: The directory containing the working tree.
80
        """
0.16.94 by Aaron Bentley
Add unshelve tests
81
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
82
        target_tree = builtins._get_one_revision_tree('shelf2', revision,
83
            tree.branch, tree)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
84
        return klass(tree, target_tree, all, all, file_list, message)
0.16.1 by Aaron Bentley
Begin implementing UI
85
86
    def run(self):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
87
        """Interactively shelve the changes."""
0.16.47 by Aaron Bentley
Support selecting files to shelve
88
        creator = shelf.ShelfCreator(self.work_tree, self.target_tree,
89
                                     self.file_list)
0.16.5 by Aaron Bentley
Get text shelving working
90
        self.tempdir = tempfile.mkdtemp()
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
91
        changes_shelved = 0
0.16.1 by Aaron Bentley
Begin implementing UI
92
        try:
0.16.86 by Aaron Bentley
Switch to iter_shelvable
93
            for change in creator.iter_shelvable():
0.16.5 by Aaron Bentley
Get text shelving working
94
                if change[0] == 'modify text':
0.16.72 by Aaron Bentley
Allow shelving binary changes
95
                    try:
96
                        changes_shelved += self.handle_modify_text(creator,
97
                                                                   change[1])
98
                    except errors.BinaryFile:
99
                        if self.prompt_bool('Shelve binary changes?'):
100
                            changes_shelved += 1
101
                            creator.shelve_content_change(change[1])
0.16.16 by Aaron Bentley
Allow shelving renames and creation
102
                if change[0] == 'add file':
0.16.36 by Aaron Bentley
Better prompts on add/delete
103
                    if self.prompt_bool('Shelve adding file "%s"?'
104
                                        % change[3]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
105
                        creator.shelve_creation(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
106
                        changes_shelved += 1
0.16.19 by Aaron Bentley
Implement shelving deletion
107
                if change[0] == 'delete file':
0.16.102 by Aaron Bentley
Minor updates
108
                    if self.prompt_bool('Shelve removing file "%s"?'
0.16.36 by Aaron Bentley
Better prompts on add/delete
109
                                        % change[3]):
0.16.19 by Aaron Bentley
Implement shelving deletion
110
                        creator.shelve_deletion(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
111
                        changes_shelved += 1
0.16.72 by Aaron Bentley
Allow shelving binary changes
112
                if change[0] == 'change kind':
113
                    if self.prompt_bool('Shelve changing "%s" from %s to %s? '
114
                                        % (change[4], change[2], change[3])):
115
                        creator.shelve_content_change(change[1])
116
                        changes_shelved += 1
0.16.16 by Aaron Bentley
Allow shelving renames and creation
117
                if change[0] == 'rename':
0.16.102 by Aaron Bentley
Minor updates
118
                    if self.prompt_bool('Shelve renaming "%s" => "%s"?' %
0.16.23 by Aaron Bentley
Improve prompting
119
                                   change[2:]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
120
                        creator.shelve_rename(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
121
                        changes_shelved += 1
122
            if changes_shelved > 0:
0.16.60 by Aaron Bentley
Clean up I/O handling
123
                trace.note("Selected changes:")
0.16.25 by Aaron Bentley
Show selected changes before shelving
124
                changes = creator.work_transform.iter_changes()
0.16.60 by Aaron Bentley
Clean up I/O handling
125
                reporter = delta._ChangeReporter()
0.16.25 by Aaron Bentley
Show selected changes before shelving
126
                delta.report_changes(changes, reporter)
0.16.98 by Aaron Bentley
Update docs and prompting
127
                if (self.auto_apply or self.prompt_bool(
128
                    'Shelve %d change(s)?' % changes_shelved)):
0.16.57 by Aaron Bentley
Expose messages in the UI
129
                    shelf_id = self.manager.shelve_changes(creator,
130
                                                           self.message)
0.16.54 by Aaron Bentley
Inform user about shelf ids.
131
                    trace.note('Changes shelved with id "%d".' % shelf_id)
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
132
            else:
0.16.60 by Aaron Bentley
Clean up I/O handling
133
                trace.warning('No changes to shelve.')
0.16.1 by Aaron Bentley
Begin implementing UI
134
        finally:
0.16.5 by Aaron Bentley
Get text shelving working
135
            shutil.rmtree(self.tempdir)
0.16.1 by Aaron Bentley
Begin implementing UI
136
            creator.finalize()
137
138
    def get_parsed_patch(self, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
139
        """Return a parsed version of a file's patch.
140
141
        :param file_id: The id of the file to generate a patch for.
142
        :return: A patches.Patch.
143
        """
0.16.96 by Aaron Bentley
Fix shelving with renames
144
        old_path = self.target_tree.id2path(file_id)
145
        new_path = self.work_tree.id2path(file_id)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
146
        diff_file = StringIO()
147
        text_differ = diff.DiffText(self.target_tree, self.work_tree,
148
                                    diff_file)
149
        patch = text_differ.diff(file_id, old_path, new_path, 'file', 'file')
150
        diff_file.seek(0)
151
        return patches.parse_patch(diff_file)
0.16.1 by Aaron Bentley
Begin implementing UI
152
0.16.89 by Aaron Bentley
Add tests for Shelver
153
    def prompt(self, message):
0.16.98 by Aaron Bentley
Update docs and prompting
154
        """Prompt the user for a character.
155
156
        :param message: The message to prompt a user with.
157
        :return: A character.
158
        """
0.16.89 by Aaron Bentley
Add tests for Shelver
159
        sys.stdout.write(message)
160
        char = osutils.getchar()
161
        sys.stdout.write("\r" + ' ' * len(message) + '\r')
162
        sys.stdout.flush()
163
        return char
164
0.16.98 by Aaron Bentley
Update docs and prompting
165
    def prompt_bool(self, question):
166
        """Prompt the user with a yes/no question.
167
0.16.102 by Aaron Bentley
Minor updates
168
        This may be overridden by self.auto.  It may also *set* self.auto.  It
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
169
        may also raise UserAbort.
0.16.98 by Aaron Bentley
Update docs and prompting
170
        :param question: The question to ask the user.
171
        :return: True or False
172
        """
173
        if self.auto:
0.16.23 by Aaron Bentley
Improve prompting
174
            return True
0.16.89 by Aaron Bentley
Add tests for Shelver
175
        char = self.prompt(question + ' [yNfq]')
0.16.23 by Aaron Bentley
Improve prompting
176
        if char == 'y':
177
            return True
178
        elif char == 'f':
179
            self.auto = True
180
            return True
0.16.24 by Aaron Bentley
Regularize prompts
181
        if char == 'q':
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
182
            raise errors.UserAbort()
0.16.23 by Aaron Bentley
Improve prompting
183
        else:
184
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
185
0.16.5 by Aaron Bentley
Get text shelving working
186
    def handle_modify_text(self, creator, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
187
        """Provide diff hunk selection for modified text.
188
189
        :param creator: a ShelfCreator
190
        :param file_id: The id of the file to shelve.
191
        :return: number of shelved hunks.
192
        """
0.16.72 by Aaron Bentley
Allow shelving binary changes
193
        target_lines = self.target_tree.get_file_lines(file_id)
0.16.102 by Aaron Bentley
Minor updates
194
        textfile.check_text_lines(self.work_tree.get_file_lines(file_id))
0.16.72 by Aaron Bentley
Allow shelving binary changes
195
        textfile.check_text_lines(target_lines)
0.16.1 by Aaron Bentley
Begin implementing UI
196
        parsed = self.get_parsed_patch(file_id)
0.16.43 by Aaron Bentley
Reduce API friction.
197
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
198
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
199
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
200
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
201
            for hunk in parsed.hunks:
202
                self.diff_writer.write(str(hunk))
0.16.24 by Aaron Bentley
Regularize prompts
203
                if not self.prompt_bool('Shelve?'):
0.16.41 by Aaron Bentley
Implement shelving with internal patch
204
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
205
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
206
                else:
207
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
208
        sys.stdout.flush()
0.16.62 by Aaron Bentley
Make status nicer by not shelving lines for files not being changed
209
        if len(parsed.hunks) == len(final_hunks):
210
            return 0
0.16.43 by Aaron Bentley
Reduce API friction.
211
        patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
0.16.45 by Aaron Bentley
switch to shelve_lines
212
        creator.shelve_lines(file_id, list(patched))
0.16.43 by Aaron Bentley
Reduce API friction.
213
        return len(parsed.hunks) - len(final_hunks)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
214
215
216
class Unshelver(object):
0.16.98 by Aaron Bentley
Update docs and prompting
217
    """Unshelve changes into a working tree."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
218
219
    @classmethod
0.16.94 by Aaron Bentley
Add unshelve tests
220
    def from_args(klass, shelf_id=None, action='apply', directory='.'):
0.16.98 by Aaron Bentley
Update docs and prompting
221
        """Create an unshelver from commandline arguments.
222
223
        :param shelf_id: Integer id of the shelf, as a string.
224
        :param action: action to perform.  May be 'apply', 'dry-run',
225
            'delete'.
226
        :param directory: The directory to unshelve changes into.
227
        """
0.16.94 by Aaron Bentley
Add unshelve tests
228
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
229
        manager = tree.get_shelf_manager()
0.16.52 by Aaron Bentley
Allow user-specified shelves
230
        if shelf_id is not None:
231
            shelf_id = int(shelf_id)
232
        else:
233
            shelf_id = manager.last_shelf()
234
            if shelf_id is None:
235
                raise errors.BzrCommandError('No changes are shelved.')
0.16.54 by Aaron Bentley
Inform user about shelf ids.
236
            trace.note('Unshelving changes with id "%d".' % shelf_id)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
237
        apply_changes = True
238
        delete_shelf = True
0.16.65 by Aaron Bentley
Implement unshelve --delete
239
        read_shelf = True
240
        if action == 'dry-run':
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
241
            apply_changes = False
242
            delete_shelf = False
0.16.65 by Aaron Bentley
Implement unshelve --delete
243
        if action == 'delete-only':
244
            apply_changes = False
245
            read_shelf = False
246
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
247
                     read_shelf)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
248
0.16.94 by Aaron Bentley
Add unshelve tests
249
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
250
                 delete_shelf=True, read_shelf=True):
0.16.98 by Aaron Bentley
Update docs and prompting
251
        """Constructor.
252
253
        :param tree: The working tree to unshelve into.
254
        :param manager: The ShelveManager containing the shelved changes.
255
        :param shelf_id:
256
        :param apply_changes: If True, apply the shelved changes to the
257
            working tree.
258
        :param delete_shelf: If True, delete the changes from the shelf.
259
        :param read_shelf: If True, read the changes from the shelf.
260
        """
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
261
        self.tree = tree
0.16.98 by Aaron Bentley
Update docs and prompting
262
        manager = tree.get_shelf_manager()
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
263
        self.manager = manager
264
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
265
        self.apply_changes = apply_changes
266
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
267
        self.read_shelf = read_shelf
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
268
269
    def run(self):
0.16.98 by Aaron Bentley
Update docs and prompting
270
        """Perform the unshelving operation."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
271
        self.tree.lock_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
272
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
273
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
274
            if self.read_shelf:
275
                unshelver = self.manager.get_unshelver(self.shelf_id)
276
                cleanups.append(unshelver.finalize)
277
                if unshelver.message is not None:
278
                    trace.note('Message: %s' % unshelver.message)
279
                change_reporter = delta._ChangeReporter()
0.16.78 by Aaron Bentley
Update for name change
280
                merger = unshelver.make_merger()
0.16.65 by Aaron Bentley
Implement unshelve --delete
281
                merger.change_reporter = change_reporter
282
                if self.apply_changes:
283
                    pb = ui.ui_factory.nested_progress_bar()
284
                    try:
285
                        merger.do_merge()
286
                    finally:
287
                        pb.finished()
288
                else:
289
                    self.show_changes(merger)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
290
            if self.delete_shelf:
291
                self.manager.delete_shelf(self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
292
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
293
            for cleanup in reversed(cleanups):
294
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
295
296
    def show_changes(self, merger):
0.16.98 by Aaron Bentley
Update docs and prompting
297
        """Show the changes that this operation specifies."""
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
298
        tree_merger = merger.make_merger()
299
        # This implicitly shows the changes via the reporter, so we're done...
300
        tt = tree_merger.make_preview_transform()
301
        tt.finalize()