/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()
133
                    else:
134
                        shelf_id = self.manager.shelve_changes(creator,
135
                                                               self.message)
136
                        trace.note('Changes shelved with id "%d".' % shelf_id)
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
137
            else:
0.16.60 by Aaron Bentley
Clean up I/O handling
138
                trace.warning('No changes to shelve.')
0.16.1 by Aaron Bentley
Begin implementing UI
139
        finally:
0.16.5 by Aaron Bentley
Get text shelving working
140
            shutil.rmtree(self.tempdir)
0.16.1 by Aaron Bentley
Begin implementing UI
141
            creator.finalize()
142
143
    def get_parsed_patch(self, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
144
        """Return a parsed version of a file's patch.
145
146
        :param file_id: The id of the file to generate a patch for.
147
        :return: A patches.Patch.
148
        """
0.16.96 by Aaron Bentley
Fix shelving with renames
149
        old_path = self.target_tree.id2path(file_id)
150
        new_path = self.work_tree.id2path(file_id)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
151
        diff_file = StringIO()
152
        text_differ = diff.DiffText(self.target_tree, self.work_tree,
153
                                    diff_file)
154
        patch = text_differ.diff(file_id, old_path, new_path, 'file', 'file')
155
        diff_file.seek(0)
156
        return patches.parse_patch(diff_file)
0.16.1 by Aaron Bentley
Begin implementing UI
157
0.16.89 by Aaron Bentley
Add tests for Shelver
158
    def prompt(self, message):
0.16.98 by Aaron Bentley
Update docs and prompting
159
        """Prompt the user for a character.
160
161
        :param message: The message to prompt a user with.
162
        :return: A character.
163
        """
0.16.89 by Aaron Bentley
Add tests for Shelver
164
        sys.stdout.write(message)
165
        char = osutils.getchar()
166
        sys.stdout.write("\r" + ' ' * len(message) + '\r')
167
        sys.stdout.flush()
168
        return char
169
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
170
    def prompt_bool(self, question, long=False):
0.16.98 by Aaron Bentley
Update docs and prompting
171
        """Prompt the user with a yes/no question.
172
0.16.102 by Aaron Bentley
Minor updates
173
        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
174
        may also raise UserAbort.
0.16.98 by Aaron Bentley
Update docs and prompting
175
        :param question: The question to ask the user.
176
        :return: True or False
177
        """
178
        if self.auto:
0.16.23 by Aaron Bentley
Improve prompting
179
            return True
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
180
        if long:
181
            prompt = ' [(y)es, (N)o, (f)inish, or (q)uit]'
182
        else:
183
            prompt = ' [yNfq?]'
184
        char = self.prompt(question + prompt)
0.16.23 by Aaron Bentley
Improve prompting
185
        if char == 'y':
186
            return True
187
        elif char == 'f':
188
            self.auto = True
189
            return True
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
190
        elif char == '?':
191
            return self.prompt_bool(question, long=True)
0.16.24 by Aaron Bentley
Regularize prompts
192
        if char == 'q':
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
193
            raise errors.UserAbort()
0.16.23 by Aaron Bentley
Improve prompting
194
        else:
195
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
196
0.16.5 by Aaron Bentley
Get text shelving working
197
    def handle_modify_text(self, creator, file_id):
0.16.98 by Aaron Bentley
Update docs and prompting
198
        """Provide diff hunk selection for modified text.
199
200
        :param creator: a ShelfCreator
201
        :param file_id: The id of the file to shelve.
202
        :return: number of shelved hunks.
203
        """
0.16.72 by Aaron Bentley
Allow shelving binary changes
204
        target_lines = self.target_tree.get_file_lines(file_id)
0.16.102 by Aaron Bentley
Minor updates
205
        textfile.check_text_lines(self.work_tree.get_file_lines(file_id))
0.16.72 by Aaron Bentley
Allow shelving binary changes
206
        textfile.check_text_lines(target_lines)
0.16.1 by Aaron Bentley
Begin implementing UI
207
        parsed = self.get_parsed_patch(file_id)
0.16.43 by Aaron Bentley
Reduce API friction.
208
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
209
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
210
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
211
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
212
            for hunk in parsed.hunks:
213
                self.diff_writer.write(str(hunk))
0.16.24 by Aaron Bentley
Regularize prompts
214
                if not self.prompt_bool('Shelve?'):
0.16.41 by Aaron Bentley
Implement shelving with internal patch
215
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
216
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
217
                else:
218
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
219
        sys.stdout.flush()
0.16.62 by Aaron Bentley
Make status nicer by not shelving lines for files not being changed
220
        if len(parsed.hunks) == len(final_hunks):
221
            return 0
0.16.43 by Aaron Bentley
Reduce API friction.
222
        patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
0.16.45 by Aaron Bentley
switch to shelve_lines
223
        creator.shelve_lines(file_id, list(patched))
0.16.43 by Aaron Bentley
Reduce API friction.
224
        return len(parsed.hunks) - len(final_hunks)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
225
226
227
class Unshelver(object):
0.16.98 by Aaron Bentley
Update docs and prompting
228
    """Unshelve changes into a working tree."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
229
230
    @classmethod
0.16.94 by Aaron Bentley
Add unshelve tests
231
    def from_args(klass, shelf_id=None, action='apply', directory='.'):
0.16.98 by Aaron Bentley
Update docs and prompting
232
        """Create an unshelver from commandline arguments.
233
234
        :param shelf_id: Integer id of the shelf, as a string.
235
        :param action: action to perform.  May be 'apply', 'dry-run',
236
            'delete'.
237
        :param directory: The directory to unshelve changes into.
238
        """
0.16.94 by Aaron Bentley
Add unshelve tests
239
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
240
        manager = tree.get_shelf_manager()
0.16.52 by Aaron Bentley
Allow user-specified shelves
241
        if shelf_id is not None:
3990.2.4 by Daniel Watkins
Don't stack trace with an invalid shelf id.
242
            try:
243
                shelf_id = int(shelf_id)
244
            except ValueError:
245
                raise errors.InvalidShelfId(shelf_id)
0.16.52 by Aaron Bentley
Allow user-specified shelves
246
        else:
247
            shelf_id = manager.last_shelf()
248
            if shelf_id is None:
249
                raise errors.BzrCommandError('No changes are shelved.')
0.16.54 by Aaron Bentley
Inform user about shelf ids.
250
            trace.note('Unshelving changes with id "%d".' % shelf_id)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
251
        apply_changes = True
252
        delete_shelf = True
0.16.65 by Aaron Bentley
Implement unshelve --delete
253
        read_shelf = True
254
        if action == 'dry-run':
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
255
            apply_changes = False
256
            delete_shelf = False
0.16.65 by Aaron Bentley
Implement unshelve --delete
257
        if action == 'delete-only':
258
            apply_changes = False
259
            read_shelf = False
260
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
261
                     read_shelf)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
262
0.16.94 by Aaron Bentley
Add unshelve tests
263
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
264
                 delete_shelf=True, read_shelf=True):
0.16.98 by Aaron Bentley
Update docs and prompting
265
        """Constructor.
266
267
        :param tree: The working tree to unshelve into.
268
        :param manager: The ShelveManager containing the shelved changes.
269
        :param shelf_id:
270
        :param apply_changes: If True, apply the shelved changes to the
271
            working tree.
272
        :param delete_shelf: If True, delete the changes from the shelf.
273
        :param read_shelf: If True, read the changes from the shelf.
274
        """
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
275
        self.tree = tree
0.16.98 by Aaron Bentley
Update docs and prompting
276
        manager = tree.get_shelf_manager()
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
277
        self.manager = manager
278
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
279
        self.apply_changes = apply_changes
280
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
281
        self.read_shelf = read_shelf
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
282
283
    def run(self):
0.16.98 by Aaron Bentley
Update docs and prompting
284
        """Perform the unshelving operation."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
285
        self.tree.lock_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
286
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
287
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
288
            if self.read_shelf:
289
                unshelver = self.manager.get_unshelver(self.shelf_id)
290
                cleanups.append(unshelver.finalize)
291
                if unshelver.message is not None:
292
                    trace.note('Message: %s' % unshelver.message)
293
                change_reporter = delta._ChangeReporter()
1551.21.7 by Aaron Bentley
Fix progress warning
294
                task = ui.ui_factory.nested_progress_bar()
295
                try:
296
                    merger = unshelver.make_merger(task)
297
                    merger.change_reporter = change_reporter
298
                    if self.apply_changes:
0.16.65 by Aaron Bentley
Implement unshelve --delete
299
                        merger.do_merge()
1551.21.7 by Aaron Bentley
Fix progress warning
300
                    else:
301
                        self.show_changes(merger)
302
                finally:
303
                    task.finished()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
304
            if self.delete_shelf:
305
                self.manager.delete_shelf(self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
306
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
307
            for cleanup in reversed(cleanups):
308
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
309
310
    def show_changes(self, merger):
0.16.98 by Aaron Bentley
Update docs and prompting
311
        """Show the changes that this operation specifies."""
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
312
        tree_merger = merger.make_merger()
313
        # This implicitly shows the changes via the reporter, so we're done...
314
        tt = tree_merger.make_preview_transform()
315
        tt.finalize()