/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.16.1 by Aaron Bentley
Begin implementing UI
1
# Copyright (C) 2008 Aaron Bentley <aaron@aaronbentley.com>
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
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.25 by Aaron Bentley
Show selected changes before shelving
34
    workingtree)
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
35
try:
36
    from bzrlib.plugins.bzrtools import colordiff
37
except ImportError:
38
    colordiff = None
0.16.1 by Aaron Bentley
Begin implementing UI
39
40
41
class Shelver(object):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
42
    """Interactively shelve the changes in a working tree."""
0.16.1 by Aaron Bentley
Begin implementing UI
43
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
44
    def __init__(self, work_tree, target_tree, auto=False,
0.16.57 by Aaron Bentley
Expose messages in the UI
45
                 auto_apply=False, file_list=None, message=None):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
46
        """Constructor.
47
48
        :param work_tree: The working tree to shelve changes from.
49
        :param target_tree: The "unchanged" / old tree to compare the
50
            work_tree to.
51
        :param auto: If True, shelve each possible change.
52
        :param auto_apply: If True, shelve changes with no final prompt.
53
        :param file_list: If supplied, only files in this list may be  shelved.
54
        :param message: The message to associate with the shelved changes.
55
        """
0.16.1 by Aaron Bentley
Begin implementing UI
56
        self.work_tree = work_tree
57
        self.target_tree = target_tree
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
58
        if colordiff is not None:
59
            self.diff_writer = colordiff.DiffWriter(sys.stdout, False)
60
        else:
61
            self.diff_writer = sys.stdout
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
62
        self.manager = work_tree.get_shelf_manager()
0.16.15 by Aaron Bentley
Implement auto mode
63
        self.auto = auto
0.16.23 by Aaron Bentley
Improve prompting
64
        self.auto_apply = auto_apply
0.16.47 by Aaron Bentley
Support selecting files to shelve
65
        self.file_list = file_list
0.16.57 by Aaron Bentley
Expose messages in the UI
66
        self.message = message
0.16.1 by Aaron Bentley
Begin implementing UI
67
68
    @classmethod
0.16.57 by Aaron Bentley
Expose messages in the UI
69
    def from_args(klass, revision=None, all=False, file_list=None,
0.16.94 by Aaron Bentley
Add unshelve tests
70
                  message=None, directory='.'):
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.
78
        """
0.16.94 by Aaron Bentley
Add unshelve tests
79
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
80
        target_tree = builtins._get_one_revision_tree('shelf2', revision,
81
            tree.branch, tree)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
82
        return klass(tree, target_tree, all, all, file_list, message)
0.16.1 by Aaron Bentley
Begin implementing UI
83
84
    def run(self):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
85
        """Interactively shelve the changes."""
0.16.47 by Aaron Bentley
Support selecting files to shelve
86
        creator = shelf.ShelfCreator(self.work_tree, self.target_tree,
87
                                     self.file_list)
0.16.5 by Aaron Bentley
Get text shelving working
88
        self.tempdir = tempfile.mkdtemp()
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
89
        changes_shelved = 0
0.16.1 by Aaron Bentley
Begin implementing UI
90
        try:
0.16.86 by Aaron Bentley
Switch to iter_shelvable
91
            for change in creator.iter_shelvable():
0.16.5 by Aaron Bentley
Get text shelving working
92
                if change[0] == 'modify text':
0.16.72 by Aaron Bentley
Allow shelving binary changes
93
                    try:
94
                        changes_shelved += self.handle_modify_text(creator,
95
                                                                   change[1])
96
                    except errors.BinaryFile:
97
                        if self.prompt_bool('Shelve binary changes?'):
98
                            changes_shelved += 1
99
                            creator.shelve_content_change(change[1])
0.16.16 by Aaron Bentley
Allow shelving renames and creation
100
                if change[0] == 'add file':
0.16.36 by Aaron Bentley
Better prompts on add/delete
101
                    if self.prompt_bool('Shelve adding file "%s"?'
102
                                        % change[3]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
103
                        creator.shelve_creation(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
104
                        changes_shelved += 1
0.16.19 by Aaron Bentley
Implement shelving deletion
105
                if change[0] == 'delete file':
0.16.36 by Aaron Bentley
Better prompts on add/delete
106
                    if self.prompt_bool('Shelve removing file "%s"? '
107
                                        % change[3]):
0.16.19 by Aaron Bentley
Implement shelving deletion
108
                        creator.shelve_deletion(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
109
                        changes_shelved += 1
0.16.72 by Aaron Bentley
Allow shelving binary changes
110
                if change[0] == 'change kind':
111
                    if self.prompt_bool('Shelve changing "%s" from %s to %s? '
112
                                        % (change[4], change[2], change[3])):
113
                        creator.shelve_content_change(change[1])
114
                        changes_shelved += 1
0.16.16 by Aaron Bentley
Allow shelving renames and creation
115
                if change[0] == 'rename':
0.16.23 by Aaron Bentley
Improve prompting
116
                    if self.prompt_bool('Shelve renaming %s => %s?' %
117
                                   change[2:]):
0.16.16 by Aaron Bentley
Allow shelving renames and creation
118
                        creator.shelve_rename(change[1])
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
119
                        changes_shelved += 1
120
            if changes_shelved > 0:
0.16.60 by Aaron Bentley
Clean up I/O handling
121
                trace.note("Selected changes:")
0.16.25 by Aaron Bentley
Show selected changes before shelving
122
                changes = creator.work_transform.iter_changes()
0.16.60 by Aaron Bentley
Clean up I/O handling
123
                reporter = delta._ChangeReporter()
0.16.25 by Aaron Bentley
Show selected changes before shelving
124
                delta.report_changes(changes, reporter)
0.16.24 by Aaron Bentley
Regularize prompts
125
                if (self.prompt_bool('Shelve %d change(s)?' %
0.16.23 by Aaron Bentley
Improve prompting
126
                    changes_shelved, auto=self.auto_apply)):
0.16.57 by Aaron Bentley
Expose messages in the UI
127
                    shelf_id = self.manager.shelve_changes(creator,
128
                                                           self.message)
0.16.54 by Aaron Bentley
Inform user about shelf ids.
129
                    trace.note('Changes shelved with id "%d".' % shelf_id)
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
130
            else:
0.16.60 by Aaron Bentley
Clean up I/O handling
131
                trace.warning('No changes to shelve.')
0.16.1 by Aaron Bentley
Begin implementing UI
132
        finally:
0.16.5 by Aaron Bentley
Get text shelving working
133
            shutil.rmtree(self.tempdir)
0.16.1 by Aaron Bentley
Begin implementing UI
134
            creator.finalize()
135
136
    def get_parsed_patch(self, file_id):
0.16.96 by Aaron Bentley
Fix shelving with renames
137
        old_path = self.target_tree.id2path(file_id)
138
        new_path = self.work_tree.id2path(file_id)
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
139
        diff_file = StringIO()
140
        text_differ = diff.DiffText(self.target_tree, self.work_tree,
141
                                    diff_file)
142
        patch = text_differ.diff(file_id, old_path, new_path, 'file', 'file')
143
        diff_file.seek(0)
144
        return patches.parse_patch(diff_file)
0.16.1 by Aaron Bentley
Begin implementing UI
145
0.16.89 by Aaron Bentley
Add tests for Shelver
146
    def prompt(self, message):
147
        sys.stdout.write(message)
148
        char = osutils.getchar()
149
        sys.stdout.write("\r" + ' ' * len(message) + '\r')
150
        sys.stdout.flush()
151
        return char
152
0.16.23 by Aaron Bentley
Improve prompting
153
    def prompt_bool(self, question, auto=None):
0.16.44 by Aaron Bentley
Fix bogosity
154
        if auto is None:
0.16.23 by Aaron Bentley
Improve prompting
155
            auto = self.auto
156
        if auto:
157
            return True
0.16.89 by Aaron Bentley
Add tests for Shelver
158
        char = self.prompt(question + ' [yNfq]')
0.16.23 by Aaron Bentley
Improve prompting
159
        if char == 'y':
160
            return True
161
        elif char == 'f':
162
            self.auto = True
163
            return True
0.16.24 by Aaron Bentley
Regularize prompts
164
        if char == 'q':
165
            sys.exit(0)
0.16.23 by Aaron Bentley
Improve prompting
166
        else:
167
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
168
0.16.5 by Aaron Bentley
Get text shelving working
169
    def handle_modify_text(self, creator, file_id):
0.16.72 by Aaron Bentley
Allow shelving binary changes
170
        target_lines = self.target_tree.get_file_lines(file_id)
171
        work_file = self.work_tree.get_file(file_id)
172
        try:
173
            textfile.text_file(work_file)
174
        finally:
175
            work_file.close()
176
        textfile.check_text_lines(target_lines)
0.16.1 by Aaron Bentley
Begin implementing UI
177
        parsed = self.get_parsed_patch(file_id)
0.16.43 by Aaron Bentley
Reduce API friction.
178
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
179
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
180
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
181
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
182
            for hunk in parsed.hunks:
183
                self.diff_writer.write(str(hunk))
0.16.24 by Aaron Bentley
Regularize prompts
184
                if not self.prompt_bool('Shelve?'):
0.16.41 by Aaron Bentley
Implement shelving with internal patch
185
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
186
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
187
                else:
188
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
189
        sys.stdout.flush()
0.16.62 by Aaron Bentley
Make status nicer by not shelving lines for files not being changed
190
        if len(parsed.hunks) == len(final_hunks):
191
            return 0
0.16.43 by Aaron Bentley
Reduce API friction.
192
        patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
0.16.45 by Aaron Bentley
switch to shelve_lines
193
        creator.shelve_lines(file_id, list(patched))
0.16.43 by Aaron Bentley
Reduce API friction.
194
        return len(parsed.hunks) - len(final_hunks)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
195
196
197
class Unshelver(object):
198
199
    @classmethod
0.16.94 by Aaron Bentley
Add unshelve tests
200
    def from_args(klass, shelf_id=None, action='apply', directory='.'):
201
        tree, path = workingtree.WorkingTree.open_containing(directory)
0.16.40 by Aaron Bentley
Update for ShelfManager API changes
202
        manager = tree.get_shelf_manager()
0.16.52 by Aaron Bentley
Allow user-specified shelves
203
        if shelf_id is not None:
204
            shelf_id = int(shelf_id)
205
        else:
206
            shelf_id = manager.last_shelf()
207
            if shelf_id is None:
208
                raise errors.BzrCommandError('No changes are shelved.')
0.16.54 by Aaron Bentley
Inform user about shelf ids.
209
            trace.note('Unshelving changes with id "%d".' % shelf_id)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
210
        apply_changes = True
211
        delete_shelf = True
0.16.65 by Aaron Bentley
Implement unshelve --delete
212
        read_shelf = True
213
        if action == 'dry-run':
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
214
            apply_changes = False
215
            delete_shelf = False
0.16.65 by Aaron Bentley
Implement unshelve --delete
216
        if action == 'delete-only':
217
            apply_changes = False
218
            read_shelf = False
219
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
220
                     read_shelf)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
221
0.16.94 by Aaron Bentley
Add unshelve tests
222
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
223
                 delete_shelf=True, read_shelf=True):
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
224
        self.tree = tree
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
225
        self.manager = manager
226
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
227
        self.apply_changes = apply_changes
228
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
229
        self.read_shelf = read_shelf
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
230
231
    def run(self):
232
        self.tree.lock_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
233
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
234
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
235
            if self.read_shelf:
236
                unshelver = self.manager.get_unshelver(self.shelf_id)
237
                cleanups.append(unshelver.finalize)
238
                if unshelver.message is not None:
239
                    trace.note('Message: %s' % unshelver.message)
240
                change_reporter = delta._ChangeReporter()
0.16.78 by Aaron Bentley
Update for name change
241
                merger = unshelver.make_merger()
0.16.65 by Aaron Bentley
Implement unshelve --delete
242
                merger.change_reporter = change_reporter
243
                if self.apply_changes:
244
                    pb = ui.ui_factory.nested_progress_bar()
245
                    try:
246
                        merger.do_merge()
247
                    finally:
248
                        pb.finished()
249
                else:
250
                    self.show_changes(merger)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
251
            if self.delete_shelf:
252
                self.manager.delete_shelf(self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
253
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
254
            for cleanup in reversed(cleanups):
255
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
256
257
    def show_changes(self, merger):
258
        tree_merger = merger.make_merger()
259
        # This implicitly shows the changes via the reporter, so we're done...
260
        tt = tree_merger.make_preview_transform()
261
        tt.finalize()