/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
0.16.98 by Aaron Bentley
Update docs and prompting
160
    def prompt_bool(self, question):
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
0.16.89 by Aaron Bentley
Add tests for Shelver
170
        char = self.prompt(question + ' [yNfq]')
0.16.23 by Aaron Bentley
Improve prompting
171
        if char == 'y':
172
            return True
173
        elif char == 'f':
174
            self.auto = True
175
            return True
0.16.24 by Aaron Bentley
Regularize prompts
176
        if char == 'q':
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
177
            raise errors.UserAbort()
0.16.23 by Aaron Bentley
Improve prompting
178
        else:
179
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
180
0.16.5 by Aaron Bentley
Get text shelving working
181
    def handle_modify_text(self, creator, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
182
        """Provide diff hunk selection for modified text.
183
184
        :param creator: a ShelfCreator
185
        :param file_id: The id of the file to shelve.
186
        :return: number of shelved hunks.
187
        """
0.16.72 by Aaron Bentley
Allow shelving binary changes
188
        target_lines = self.target_tree.get_file_lines(file_id)
0.16.102 by Aaron Bentley
Minor updates
189
        textfile.check_text_lines(self.work_tree.get_file_lines(file_id))
0.16.72 by Aaron Bentley
Allow shelving binary changes
190
        textfile.check_text_lines(target_lines)
0.16.1 by Aaron Bentley
Begin implementing UI
191
        parsed = self.get_parsed_patch(file_id)
0.16.43 by Aaron Bentley
Reduce API friction.
192
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
193
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
194
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
195
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
196
            for hunk in parsed.hunks:
197
                self.diff_writer.write(str(hunk))
0.16.24 by Aaron Bentley
Regularize prompts
198
                if not self.prompt_bool('Shelve?'):
0.16.41 by Aaron Bentley
Implement shelving with internal patch
199
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
200
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
201
                else:
202
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
203
        sys.stdout.flush()
0.16.62 by Aaron Bentley
Make status nicer by not shelving lines for files not being changed
204
        if len(parsed.hunks) == len(final_hunks):
205
            return 0
0.16.43 by Aaron Bentley
Reduce API friction.
206
        patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
0.16.45 by Aaron Bentley
switch to shelve_lines
207
        creator.shelve_lines(file_id, list(patched))
0.16.43 by Aaron Bentley
Reduce API friction.
208
        return len(parsed.hunks) - len(final_hunks)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
209
210
211
class Unshelver(object):
0.16.98 by Aaron Bentley
Update docs and prompting
212
    """Unshelve changes into a working tree."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
213
214
    @classmethod
0.16.94 by Aaron Bentley
Add unshelve tests
215
    def from_args(klass, shelf_id=None, action='apply', directory='.'):
0.16.98 by Aaron Bentley
Update docs and prompting
216
        """Create an unshelver from commandline arguments.
217
218
        :param shelf_id: Integer id of the shelf, as a string.
219
        :param action: action to perform.  May be 'apply', 'dry-run',
220
            'delete'.
221
        :param directory: The directory to unshelve changes into.
222
        """
0.16.94 by Aaron Bentley
Add unshelve tests
223
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
224
        manager = tree.get_shelf_manager()
0.16.52 by Aaron Bentley
Allow user-specified shelves
225
        if shelf_id is not None:
3990.2.4 by Daniel Watkins
Don't stack trace with an invalid shelf id.
226
            try:
227
                shelf_id = int(shelf_id)
228
            except ValueError:
229
                raise errors.InvalidShelfId(shelf_id)
0.16.52 by Aaron Bentley
Allow user-specified shelves
230
        else:
231
            shelf_id = manager.last_shelf()
232
            if shelf_id is None:
233
                raise errors.BzrCommandError('No changes are shelved.')
0.16.54 by Aaron Bentley
Inform user about shelf ids.
234
            trace.note('Unshelving changes with id "%d".' % shelf_id)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
235
        apply_changes = True
236
        delete_shelf = True
0.16.65 by Aaron Bentley
Implement unshelve --delete
237
        read_shelf = True
238
        if action == 'dry-run':
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
239
            apply_changes = False
240
            delete_shelf = False
0.16.65 by Aaron Bentley
Implement unshelve --delete
241
        if action == 'delete-only':
242
            apply_changes = False
243
            read_shelf = False
244
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
245
                     read_shelf)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
246
0.16.94 by Aaron Bentley
Add unshelve tests
247
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
248
                 delete_shelf=True, read_shelf=True):
0.16.98 by Aaron Bentley
Update docs and prompting
249
        """Constructor.
250
251
        :param tree: The working tree to unshelve into.
252
        :param manager: The ShelveManager containing the shelved changes.
253
        :param shelf_id:
254
        :param apply_changes: If True, apply the shelved changes to the
255
            working tree.
256
        :param delete_shelf: If True, delete the changes from the shelf.
257
        :param read_shelf: If True, read the changes from the shelf.
258
        """
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
259
        self.tree = tree
0.16.98 by Aaron Bentley
Update docs and prompting
260
        manager = tree.get_shelf_manager()
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
261
        self.manager = manager
262
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
263
        self.apply_changes = apply_changes
264
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
265
        self.read_shelf = read_shelf
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
266
267
    def run(self):
0.16.98 by Aaron Bentley
Update docs and prompting
268
        """Perform the unshelving operation."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
269
        self.tree.lock_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
270
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
271
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
272
            if self.read_shelf:
273
                unshelver = self.manager.get_unshelver(self.shelf_id)
274
                cleanups.append(unshelver.finalize)
275
                if unshelver.message is not None:
276
                    trace.note('Message: %s' % unshelver.message)
277
                change_reporter = delta._ChangeReporter()
0.16.78 by Aaron Bentley
Update for name change
278
                merger = unshelver.make_merger()
0.16.65 by Aaron Bentley
Implement unshelve --delete
279
                merger.change_reporter = change_reporter
280
                if self.apply_changes:
281
                    pb = ui.ui_factory.nested_progress_bar()
282
                    try:
283
                        merger.do_merge()
284
                    finally:
285
                        pb.finished()
286
                else:
287
                    self.show_changes(merger)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
288
            if self.delete_shelf:
289
                self.manager.delete_shelf(self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
290
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
291
            for cleanup in reversed(cleanups):
292
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
293
294
    def show_changes(self, merger):
0.16.98 by Aaron Bentley
Update docs and prompting
295
        """Show the changes that this operation specifies."""
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
296
        tree_merger = merger.make_merger()
297
        # This implicitly shows the changes via the reporter, so we're done...
298
        tt = tree_merger.make_preview_transform()
299
        tt.finalize()