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