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