/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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
38
class ShelfReporter(object):
39
40
    def __init__(self):
41
        self.delta_reporter = delta._ChangeReporter()
42
43
    def no_changes(self):
44
        trace.warning('No changes to shelve.')
45
46
    def shelved_id(self, shelf_id):
47
        trace.note('Changes shelved with id "%d".' % shelf_id)
48
49
    def selected_changes(self, transform):
50
        trace.note("Selected changes:")
51
        changes = transform.iter_changes()
52
        delta.report_changes(changes, self.delta_reporter)
53
54
0.16.1 by Aaron Bentley
Begin implementing UI
55
class Shelver(object):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
56
    """Interactively shelve the changes in a working tree."""
0.16.1 by Aaron Bentley
Begin implementing UI
57
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
58
    def __init__(self, work_tree, target_tree, diff_writer=None, auto=False,
4100.3.1 by Aaron Bentley
Implement shelve --destroy
59
                 auto_apply=False, file_list=None, message=None,
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
60
                 destroy=False, reporter=None):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
61
        """Constructor.
62
63
        :param work_tree: The working tree to shelve changes from.
64
        :param target_tree: The "unchanged" / old tree to compare the
65
            work_tree to.
66
        :param auto: If True, shelve each possible change.
67
        :param auto_apply: If True, shelve changes with no final prompt.
0.16.102 by Aaron Bentley
Minor updates
68
        :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.
69
        :param message: The message to associate with the shelved changes.
4100.3.2 by Aaron Bentley
Update docs
70
        :param destroy: Change the working tree without storing the shelved
71
            changes.
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
72
        """
0.16.1 by Aaron Bentley
Begin implementing UI
73
        self.work_tree = work_tree
74
        self.target_tree = target_tree
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
75
        self.diff_writer = diff_writer
76
        if self.diff_writer is None:
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
77
            self.diff_writer = sys.stdout
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
78
        self.manager = work_tree.get_shelf_manager()
0.16.15 by Aaron Bentley
Implement auto mode
79
        self.auto = auto
0.16.23 by Aaron Bentley
Improve prompting
80
        self.auto_apply = auto_apply
0.16.47 by Aaron Bentley
Support selecting files to shelve
81
        self.file_list = file_list
0.16.57 by Aaron Bentley
Expose messages in the UI
82
        self.message = message
4100.3.1 by Aaron Bentley
Implement shelve --destroy
83
        self.destroy = destroy
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
84
        if reporter is None:
85
            reporter = ShelfReporter()
86
        self.reporter = reporter
0.16.1 by Aaron Bentley
Begin implementing UI
87
88
    @classmethod
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
89
    def from_args(klass, diff_writer, revision=None, all=False, file_list=None,
4100.3.1 by Aaron Bentley
Implement shelve --destroy
90
                  message=None, directory='.', destroy=False):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
91
        """Create a shelver from commandline arguments.
92
93
        :param revision: RevisionSpec of the revision to compare to.
94
        :param all: If True, shelve all changes without prompting.
95
        :param file_list: If supplied, only files in this list may be  shelved.
96
        :param message: The message to associate with the shelved changes.
97
        :param directory: The directory containing the working tree.
4100.3.1 by Aaron Bentley
Implement shelve --destroy
98
        :param destroy: Change the working tree without storing the shelved
99
            changes.
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
100
        """
0.16.94 by Aaron Bentley
Add unshelve tests
101
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
102
        target_tree = builtins._get_one_revision_tree('shelf2', revision,
103
            tree.branch, tree)
0.16.120 by Aaron Bentley
Use relative paths with shelve
104
        files = builtins.safe_relpath_files(tree, file_list)
4100.3.1 by Aaron Bentley
Implement shelve --destroy
105
        return klass(tree, target_tree, diff_writer, all, all, files, message,
106
                     destroy)
0.16.1 by Aaron Bentley
Begin implementing UI
107
108
    def run(self):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
109
        """Interactively shelve the changes."""
0.16.47 by Aaron Bentley
Support selecting files to shelve
110
        creator = shelf.ShelfCreator(self.work_tree, self.target_tree,
111
                                     self.file_list)
0.16.5 by Aaron Bentley
Get text shelving working
112
        self.tempdir = tempfile.mkdtemp()
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
113
        changes_shelved = 0
0.16.1 by Aaron Bentley
Begin implementing UI
114
        try:
0.16.86 by Aaron Bentley
Switch to iter_shelvable
115
            for change in creator.iter_shelvable():
0.16.5 by Aaron Bentley
Get text shelving working
116
                if change[0] == 'modify text':
0.16.72 by Aaron Bentley
Allow shelving binary changes
117
                    try:
118
                        changes_shelved += self.handle_modify_text(creator,
119
                                                                   change[1])
120
                    except errors.BinaryFile:
121
                        if self.prompt_bool('Shelve binary changes?'):
122
                            changes_shelved += 1
123
                            creator.shelve_content_change(change[1])
0.16.16 by Aaron Bentley
Allow shelving renames and creation
124
                if change[0] == 'add file':
0.16.36 by Aaron Bentley
Better prompts on add/delete
125
                    if self.prompt_bool('Shelve adding file "%s"?'
126
                                        % change[3]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
127
                        creator.shelve_creation(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
128
                        changes_shelved += 1
0.16.19 by Aaron Bentley
Implement shelving deletion
129
                if change[0] == 'delete file':
0.16.102 by Aaron Bentley
Minor updates
130
                    if self.prompt_bool('Shelve removing file "%s"?'
0.16.36 by Aaron Bentley
Better prompts on add/delete
131
                                        % change[3]):
0.16.19 by Aaron Bentley
Implement shelving deletion
132
                        creator.shelve_deletion(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
133
                        changes_shelved += 1
0.16.72 by Aaron Bentley
Allow shelving binary changes
134
                if change[0] == 'change kind':
135
                    if self.prompt_bool('Shelve changing "%s" from %s to %s? '
136
                                        % (change[4], change[2], change[3])):
137
                        creator.shelve_content_change(change[1])
138
                        changes_shelved += 1
0.16.16 by Aaron Bentley
Allow shelving renames and creation
139
                if change[0] == 'rename':
0.16.102 by Aaron Bentley
Minor updates
140
                    if self.prompt_bool('Shelve renaming "%s" => "%s"?' %
0.16.23 by Aaron Bentley
Improve prompting
141
                                   change[2:]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
142
                        creator.shelve_rename(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
143
                        changes_shelved += 1
4119.5.1 by James Westby
Shelve can now shelve changes to a symlink's target.
144
                if change[0] == 'modify target':
145
                    if self.prompt_bool('Shelve changing target of "%s" '
146
                            'from "%s" to "%s"?' % change[2:]):
147
                        creator.shelve_modify_target(change[1])
148
                        changes_shelved += 1
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
149
            if changes_shelved > 0:
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
150
                self.reporter.selected_changes(creator.work_transform)
0.16.98 by Aaron Bentley
Update docs and prompting
151
                if (self.auto_apply or self.prompt_bool(
152
                    'Shelve %d change(s)?' % changes_shelved)):
4100.3.1 by Aaron Bentley
Implement shelve --destroy
153
                    if self.destroy:
154
                        creator.transform()
4100.3.3 by Aaron Bentley
Add note when shelve --detroy completes.
155
                        trace.note('Selected changes destroyed.')
4100.3.1 by Aaron Bentley
Implement shelve --destroy
156
                    else:
157
                        shelf_id = self.manager.shelve_changes(creator,
158
                                                               self.message)
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
159
                        self.reporter.shelved_id(shelf_id)
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
160
            else:
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
161
                self.reporter.no_changes()
0.16.1 by Aaron Bentley
Begin implementing UI
162
        finally:
0.16.5 by Aaron Bentley
Get text shelving working
163
            shutil.rmtree(self.tempdir)
0.16.1 by Aaron Bentley
Begin implementing UI
164
            creator.finalize()
165
166
    def get_parsed_patch(self, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
167
        """Return a parsed version of a file's patch.
168
169
        :param file_id: The id of the file to generate a patch for.
170
        :return: A patches.Patch.
171
        """
0.16.96 by Aaron Bentley
Fix shelving with renames
172
        old_path = self.target_tree.id2path(file_id)
173
        new_path = self.work_tree.id2path(file_id)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
174
        diff_file = StringIO()
175
        text_differ = diff.DiffText(self.target_tree, self.work_tree,
176
                                    diff_file)
177
        patch = text_differ.diff(file_id, old_path, new_path, 'file', 'file')
178
        diff_file.seek(0)
179
        return patches.parse_patch(diff_file)
0.16.1 by Aaron Bentley
Begin implementing UI
180
0.16.89 by Aaron Bentley
Add tests for Shelver
181
    def prompt(self, message):
0.16.98 by Aaron Bentley
Update docs and prompting
182
        """Prompt the user for a character.
183
184
        :param message: The message to prompt a user with.
185
        :return: A character.
186
        """
0.16.89 by Aaron Bentley
Add tests for Shelver
187
        sys.stdout.write(message)
188
        char = osutils.getchar()
189
        sys.stdout.write("\r" + ' ' * len(message) + '\r')
190
        sys.stdout.flush()
191
        return char
192
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
193
    def prompt_bool(self, question, long=False):
0.16.98 by Aaron Bentley
Update docs and prompting
194
        """Prompt the user with a yes/no question.
195
0.16.102 by Aaron Bentley
Minor updates
196
        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
197
        may also raise UserAbort.
0.16.98 by Aaron Bentley
Update docs and prompting
198
        :param question: The question to ask the user.
199
        :return: True or False
200
        """
201
        if self.auto:
0.16.23 by Aaron Bentley
Improve prompting
202
            return True
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
203
        if long:
204
            prompt = ' [(y)es, (N)o, (f)inish, or (q)uit]'
205
        else:
206
            prompt = ' [yNfq?]'
207
        char = self.prompt(question + prompt)
0.16.23 by Aaron Bentley
Improve prompting
208
        if char == 'y':
209
            return True
210
        elif char == 'f':
211
            self.auto = True
212
            return True
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
213
        elif char == '?':
214
            return self.prompt_bool(question, long=True)
0.16.24 by Aaron Bentley
Regularize prompts
215
        if char == 'q':
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
216
            raise errors.UserAbort()
0.16.23 by Aaron Bentley
Improve prompting
217
        else:
218
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
219
0.16.5 by Aaron Bentley
Get text shelving working
220
    def handle_modify_text(self, creator, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
221
        """Provide diff hunk selection for modified text.
222
223
        :param creator: a ShelfCreator
224
        :param file_id: The id of the file to shelve.
225
        :return: number of shelved hunks.
226
        """
0.16.72 by Aaron Bentley
Allow shelving binary changes
227
        target_lines = self.target_tree.get_file_lines(file_id)
0.16.102 by Aaron Bentley
Minor updates
228
        textfile.check_text_lines(self.work_tree.get_file_lines(file_id))
0.16.72 by Aaron Bentley
Allow shelving binary changes
229
        textfile.check_text_lines(target_lines)
0.16.1 by Aaron Bentley
Begin implementing UI
230
        parsed = self.get_parsed_patch(file_id)
0.16.43 by Aaron Bentley
Reduce API friction.
231
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
232
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
233
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
234
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
235
            for hunk in parsed.hunks:
236
                self.diff_writer.write(str(hunk))
0.16.24 by Aaron Bentley
Regularize prompts
237
                if not self.prompt_bool('Shelve?'):
0.16.41 by Aaron Bentley
Implement shelving with internal patch
238
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
239
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
240
                else:
241
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
242
        sys.stdout.flush()
0.16.62 by Aaron Bentley
Make status nicer by not shelving lines for files not being changed
243
        if len(parsed.hunks) == len(final_hunks):
244
            return 0
0.16.43 by Aaron Bentley
Reduce API friction.
245
        patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
0.16.45 by Aaron Bentley
switch to shelve_lines
246
        creator.shelve_lines(file_id, list(patched))
0.16.43 by Aaron Bentley
Reduce API friction.
247
        return len(parsed.hunks) - len(final_hunks)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
248
249
250
class Unshelver(object):
0.16.98 by Aaron Bentley
Update docs and prompting
251
    """Unshelve changes into a working tree."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
252
253
    @classmethod
0.16.94 by Aaron Bentley
Add unshelve tests
254
    def from_args(klass, shelf_id=None, action='apply', directory='.'):
0.16.98 by Aaron Bentley
Update docs and prompting
255
        """Create an unshelver from commandline arguments.
256
257
        :param shelf_id: Integer id of the shelf, as a string.
258
        :param action: action to perform.  May be 'apply', 'dry-run',
259
            'delete'.
260
        :param directory: The directory to unshelve changes into.
261
        """
0.16.94 by Aaron Bentley
Add unshelve tests
262
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
263
        manager = tree.get_shelf_manager()
0.16.52 by Aaron Bentley
Allow user-specified shelves
264
        if shelf_id is not None:
3990.2.4 by Daniel Watkins
Don't stack trace with an invalid shelf id.
265
            try:
266
                shelf_id = int(shelf_id)
267
            except ValueError:
268
                raise errors.InvalidShelfId(shelf_id)
0.16.52 by Aaron Bentley
Allow user-specified shelves
269
        else:
270
            shelf_id = manager.last_shelf()
271
            if shelf_id is None:
272
                raise errors.BzrCommandError('No changes are shelved.')
0.16.54 by Aaron Bentley
Inform user about shelf ids.
273
            trace.note('Unshelving changes with id "%d".' % shelf_id)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
274
        apply_changes = True
275
        delete_shelf = True
0.16.65 by Aaron Bentley
Implement unshelve --delete
276
        read_shelf = True
277
        if action == 'dry-run':
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
278
            apply_changes = False
279
            delete_shelf = False
0.16.65 by Aaron Bentley
Implement unshelve --delete
280
        if action == 'delete-only':
281
            apply_changes = False
282
            read_shelf = False
283
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
284
                     read_shelf)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
285
0.16.94 by Aaron Bentley
Add unshelve tests
286
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
287
                 delete_shelf=True, read_shelf=True):
0.16.98 by Aaron Bentley
Update docs and prompting
288
        """Constructor.
289
290
        :param tree: The working tree to unshelve into.
291
        :param manager: The ShelveManager containing the shelved changes.
292
        :param shelf_id:
293
        :param apply_changes: If True, apply the shelved changes to the
294
            working tree.
295
        :param delete_shelf: If True, delete the changes from the shelf.
296
        :param read_shelf: If True, read the changes from the shelf.
297
        """
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
298
        self.tree = tree
0.16.98 by Aaron Bentley
Update docs and prompting
299
        manager = tree.get_shelf_manager()
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
300
        self.manager = manager
301
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
302
        self.apply_changes = apply_changes
303
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
304
        self.read_shelf = read_shelf
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
305
306
    def run(self):
0.16.98 by Aaron Bentley
Update docs and prompting
307
        """Perform the unshelving operation."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
308
        self.tree.lock_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
309
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
310
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
311
            if self.read_shelf:
312
                unshelver = self.manager.get_unshelver(self.shelf_id)
313
                cleanups.append(unshelver.finalize)
314
                if unshelver.message is not None:
315
                    trace.note('Message: %s' % unshelver.message)
316
                change_reporter = delta._ChangeReporter()
1551.21.7 by Aaron Bentley
Fix progress warning
317
                task = ui.ui_factory.nested_progress_bar()
318
                try:
319
                    merger = unshelver.make_merger(task)
320
                    merger.change_reporter = change_reporter
321
                    if self.apply_changes:
0.16.65 by Aaron Bentley
Implement unshelve --delete
322
                        merger.do_merge()
1551.21.7 by Aaron Bentley
Fix progress warning
323
                    else:
324
                        self.show_changes(merger)
325
                finally:
326
                    task.finished()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
327
            if self.delete_shelf:
328
                self.manager.delete_shelf(self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
329
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
330
            for cleanup in reversed(cleanups):
331
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
332
333
    def show_changes(self, merger):
0.16.98 by Aaron Bentley
Update docs and prompting
334
        """Show the changes that this operation specifies."""
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
335
        tree_merger = merger.make_merger()
336
        # This implicitly shows the changes via the reporter, so we're done...
337
        tt = tree_merger.make_preview_transform()
338
        tt.finalize()