/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4902.1.8 by John Arbash Meinel
Delay grabbing an output stream until we actually go to show a diff.
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
0.16.101 by Aaron Bentley
Update GPL formatting and copyright
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.16.1 by Aaron Bentley
Begin implementing UI
16
6379.6.3 by Jelmer Vernooij
Use absolute_import.
17
from __future__ import absolute_import
0.16.1 by Aaron Bentley
Begin implementing UI
18
7290.14.1 by Jelmer Vernooij
Use external patiencediff.
19
import patiencediff
0.16.5 by Aaron Bentley
Get text shelving working
20
import shutil
0.16.1 by Aaron Bentley
Begin implementing UI
21
import sys
0.16.5 by Aaron Bentley
Get text shelving working
22
import tempfile
0.16.1 by Aaron Bentley
Begin implementing UI
23
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
24
from io import BytesIO
25
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
26
from . import (
0.16.25 by Aaron Bentley
Show selected changes before shelving
27
    builtins,
28
    delta,
29
    diff,
30
    errors,
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
31
    osutils,
0.16.25 by Aaron Bentley
Show selected changes before shelving
32
    patches,
0.16.74 by Aaron Bentley
Merge with shelf-manager
33
    shelf,
0.16.72 by Aaron Bentley
Allow shelving binary changes
34
    textfile,
0.16.54 by Aaron Bentley
Inform user about shelf ids.
35
    trace,
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
36
    ui,
0.16.102 by Aaron Bentley
Minor updates
37
    workingtree,
38
)
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
39
from .i18n import gettext
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
40
3835.2.6 by Aaron Bentley
Restore vila's colordiff change
41
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
42
class UseEditor(Exception):
43
    """Use an editor instead of selecting hunks."""
44
45
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
46
class ShelfReporter(object):
4526.7.2 by Aaron Bentley
Update docs.
47
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
48
    vocab = {'add file': gettext('Shelve adding file "%(path)s"?'),
49
             'binary': gettext('Shelve binary changes?'),
50
             'change kind': gettext('Shelve changing "%s" from %(other)s'
7143.15.2 by Jelmer Vernooij
Run autopep8.
51
                                    ' to %(this)s?'),
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
52
             'delete file': gettext('Shelve removing file "%(path)s"?'),
53
             'final': gettext('Shelve %d change(s)?'),
54
             'hunk': gettext('Shelve?'),
55
             'modify target': gettext('Shelve changing target of'
7143.15.2 by Jelmer Vernooij
Run autopep8.
56
                                      ' "%(path)s" from "%(other)s" to "%(this)s"?'),
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
57
             'rename': gettext('Shelve renaming "%(other)s" =>'
7143.15.2 by Jelmer Vernooij
Run autopep8.
58
                               ' "%(this)s"?')
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
59
             }
60
61
    invert_diff = False
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
62
63
    def __init__(self):
64
        self.delta_reporter = delta._ChangeReporter()
65
66
    def no_changes(self):
4526.7.2 by Aaron Bentley
Update docs.
67
        """Report that no changes were selected to apply."""
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
68
        trace.warning('No changes to shelve.')
69
70
    def shelved_id(self, shelf_id):
4526.7.2 by Aaron Bentley
Update docs.
71
        """Report the id changes were shelved to."""
6138.3.4 by Jonathan Riddell
add gettext() to uses of trace.note()
72
        trace.note(gettext('Changes shelved with id "%d".') % shelf_id)
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
73
4526.6.4 by Aaron Bentley
Remove changes_destroyed message.
74
    def changes_destroyed(self):
4526.7.2 by Aaron Bentley
Update docs.
75
        """Report that changes were made without shelving."""
6138.3.4 by Jonathan Riddell
add gettext() to uses of trace.note()
76
        trace.note(gettext('Selected changes destroyed.'))
4526.6.4 by Aaron Bentley
Remove changes_destroyed message.
77
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
78
    def selected_changes(self, transform):
4526.7.2 by Aaron Bentley
Update docs.
79
        """Report the changes that were selected."""
6138.3.4 by Jonathan Riddell
add gettext() to uses of trace.note()
80
        trace.note(gettext("Selected changes:"))
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
81
        changes = transform.iter_changes()
82
        delta.report_changes(changes, self.delta_reporter)
83
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
84
    def prompt_change(self, change):
4526.7.2 by Aaron Bentley
Update docs.
85
        """Determine the prompt for a change to apply."""
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
86
        if change[0] == 'rename':
87
            vals = {'this': change[3], 'other': change[2]}
88
        elif change[0] == 'change kind':
89
            vals = {'path': change[4], 'other': change[2], 'this': change[3]}
90
        elif change[0] == 'modify target':
91
            vals = {'path': change[2], 'other': change[3], 'this': change[4]}
92
        else:
93
            vals = {'path': change[3]}
94
        prompt = self.vocab[change[0]] % vals
95
        return prompt
96
97
98
class ApplyReporter(ShelfReporter):
99
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
100
    vocab = {'add file': gettext('Delete file "%(path)s"?'),
101
             'binary': gettext('Apply binary changes?'),
102
             'change kind': gettext('Change "%(path)s" from %(this)s'
7143.15.2 by Jelmer Vernooij
Run autopep8.
103
                                    ' to %(other)s?'),
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
104
             'delete file': gettext('Add file "%(path)s"?'),
105
             'final': gettext('Apply %d change(s)?'),
106
             'hunk': gettext('Apply change?'),
107
             'modify target': gettext('Change target of'
7143.15.2 by Jelmer Vernooij
Run autopep8.
108
                                      ' "%(path)s" from "%(this)s" to "%(other)s"?'),
6143.1.2 by Jonathan Riddell
gettext() shelf_ui.py
109
             'rename': gettext('Rename "%(this)s" => "%(other)s"?'),
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
110
             }
111
112
    invert_diff = True
113
114
    def changes_destroyed(self):
115
        pass
116
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
117
0.16.1 by Aaron Bentley
Begin implementing UI
118
class Shelver(object):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
119
    """Interactively shelve the changes in a working tree."""
0.16.1 by Aaron Bentley
Begin implementing UI
120
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
121
    def __init__(self, work_tree, target_tree, diff_writer=None, auto=False,
4100.3.1 by Aaron Bentley
Implement shelve --destroy
122
                 auto_apply=False, file_list=None, message=None,
4603.1.9 by Aaron Bentley
Misc cleanup.
123
                 destroy=False, manager=None, reporter=None):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
124
        """Constructor.
125
126
        :param work_tree: The working tree to shelve changes from.
127
        :param target_tree: The "unchanged" / old tree to compare the
128
            work_tree to.
129
        :param auto: If True, shelve each possible change.
130
        :param auto_apply: If True, shelve changes with no final prompt.
0.16.102 by Aaron Bentley
Minor updates
131
        :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.
132
        :param message: The message to associate with the shelved changes.
4100.3.2 by Aaron Bentley
Update docs
133
        :param destroy: Change the working tree without storing the shelved
134
            changes.
4465.1.2 by Aaron Bentley
Accept manager as a parameter to Shelver()
135
        :param manager: The shelf manager to use.
4526.7.2 by Aaron Bentley
Update docs.
136
        :param reporter: Object for reporting changes to user.
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
137
        """
0.16.1 by Aaron Bentley
Begin implementing UI
138
        self.work_tree = work_tree
139
        self.target_tree = target_tree
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
140
        self.diff_writer = diff_writer
141
        if self.diff_writer is None:
0.16.79 by Aaron Bentley
Remove dependencies on bzrtools
142
            self.diff_writer = sys.stdout
4465.1.2 by Aaron Bentley
Accept manager as a parameter to Shelver()
143
        if manager is None:
144
            manager = work_tree.get_shelf_manager()
145
        self.manager = manager
0.16.15 by Aaron Bentley
Implement auto mode
146
        self.auto = auto
0.16.23 by Aaron Bentley
Improve prompting
147
        self.auto_apply = auto_apply
0.16.47 by Aaron Bentley
Support selecting files to shelve
148
        self.file_list = file_list
0.16.57 by Aaron Bentley
Expose messages in the UI
149
        self.message = message
4100.3.1 by Aaron Bentley
Implement shelve --destroy
150
        self.destroy = destroy
4459.4.1 by Aaron Bentley
Provide control over switch and shelver messaging.
151
        if reporter is None:
152
            reporter = ShelfReporter()
153
        self.reporter = reporter
4603.1.14 by Aaron Bentley
Make change editor mandatory
154
        config = self.work_tree.branch.get_config()
155
        self.change_editor = config.get_change_editor(target_tree, work_tree)
4603.2.1 by Benoît Pierre
Lock the work tree in Shelver only after everything else has been setup.
156
        self.work_tree.lock_tree_write()
0.16.1 by Aaron Bentley
Begin implementing UI
157
158
    @classmethod
0.16.108 by Aaron Bentley
Shelf supports multiple diff writers.
159
    def from_args(klass, diff_writer, revision=None, all=False, file_list=None,
5521.1.1 by Vincent Ladeuil
Handle --directory when paths are also provided to shelve and restore.
160
                  message=None, directory=None, destroy=False):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
161
        """Create a shelver from commandline arguments.
162
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
163
        The returned shelver wil have a work_tree that is locked and should
164
        be unlocked.
165
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
166
        :param revision: RevisionSpec of the revision to compare to.
167
        :param all: If True, shelve all changes without prompting.
168
        :param file_list: If supplied, only files in this list may be  shelved.
169
        :param message: The message to associate with the shelved changes.
170
        :param directory: The directory containing the working tree.
4100.3.1 by Aaron Bentley
Implement shelve --destroy
171
        :param destroy: Change the working tree without storing the shelved
172
            changes.
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
173
        """
5521.1.1 by Vincent Ladeuil
Handle --directory when paths are also provided to shelve and restore.
174
        if directory is None:
175
            directory = u'.'
176
        elif file_list:
177
            file_list = [osutils.pathjoin(directory, f) for f in file_list]
0.16.94 by Aaron Bentley
Add unshelve tests
178
        tree, path = workingtree.WorkingTree.open_containing(directory)
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
179
        # Ensure that tree is locked for the lifetime of target_tree, as
180
        # target tree may be reading from the same dirstate.
181
        tree.lock_tree_write()
182
        try:
183
            target_tree = builtins._get_one_revision_tree('shelf2', revision,
7143.15.2 by Jelmer Vernooij
Run autopep8.
184
                                                          tree.branch, tree)
5346.4.2 by Martin Pool
Move internal_tree_files and safe_relpath_files onto WorkingTree
185
            files = tree.safe_relpath_files(file_list)
4603.1.17 by Aaron Bentley
Fix shelf_ui tests to finalize.
186
            return klass(tree, target_tree, diff_writer, all, all, files,
187
                         message, destroy)
188
        finally:
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
189
            tree.unlock()
0.16.1 by Aaron Bentley
Begin implementing UI
190
191
    def run(self):
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
192
        """Interactively shelve the changes."""
0.16.47 by Aaron Bentley
Support selecting files to shelve
193
        creator = shelf.ShelfCreator(self.work_tree, self.target_tree,
194
                                     self.file_list)
0.16.5 by Aaron Bentley
Get text shelving working
195
        self.tempdir = tempfile.mkdtemp()
0.16.22 by Aaron Bentley
Only prompt when there are changes to shelve.
196
        changes_shelved = 0
0.16.1 by Aaron Bentley
Begin implementing UI
197
        try:
4603.1.7 by Aaron Bentley
Allow configuring change editor.
198
            for change in creator.iter_shelvable():
199
                if change[0] == 'modify text':
200
                    try:
4603.1.9 by Aaron Bentley
Misc cleanup.
201
                        changes_shelved += self.handle_modify_text(creator,
202
                                                                   change[1])
4603.1.7 by Aaron Bentley
Allow configuring change editor.
203
                    except errors.BinaryFile:
204
                        if self.prompt_bool(self.reporter.vocab['binary']):
0.16.72 by Aaron Bentley
Allow shelving binary changes
205
                            changes_shelved += 1
4603.1.7 by Aaron Bentley
Allow configuring change editor.
206
                            creator.shelve_content_change(change[1])
4526.6.1 by Aaron Bentley
Reverse the way changes are described by Shelver.
207
                else:
4603.1.7 by Aaron Bentley
Allow configuring change editor.
208
                    if self.prompt_bool(self.reporter.prompt_change(change)):
209
                        creator.shelve_change(change)
210
                        changes_shelved += 1
211
            if changes_shelved > 0:
212
                self.reporter.selected_changes(creator.work_transform)
213
                if (self.auto_apply or self.prompt_bool(
7143.15.2 by Jelmer Vernooij
Run autopep8.
214
                        self.reporter.vocab['final'] % changes_shelved)):
4603.1.7 by Aaron Bentley
Allow configuring change editor.
215
                    if self.destroy:
216
                        creator.transform()
217
                        self.reporter.changes_destroyed()
218
                    else:
219
                        shelf_id = self.manager.shelve_changes(creator,
220
                                                               self.message)
221
                        self.reporter.shelved_id(shelf_id)
222
            else:
223
                self.reporter.no_changes()
0.16.1 by Aaron Bentley
Begin implementing UI
224
        finally:
0.16.5 by Aaron Bentley
Get text shelving working
225
            shutil.rmtree(self.tempdir)
0.16.1 by Aaron Bentley
Begin implementing UI
226
            creator.finalize()
227
4603.1.11 by Aaron Bentley
Implement shelver.finalize
228
    def finalize(self):
4603.1.17 by Aaron Bentley
Fix shelf_ui tests to finalize.
229
        if self.change_editor is not None:
230
            self.change_editor.finish()
4603.1.14 by Aaron Bentley
Make change editor mandatory
231
        self.work_tree.unlock()
232
6883.5.11 by Jelmer Vernooij
Fix tests.
233
    def get_parsed_patch(self, file_id, invert=False):
0.16.98 by Aaron Bentley
Update docs and prompting
234
        """Return a parsed version of a file's patch.
235
236
        :param file_id: The id of the file to generate a patch for.
4526.7.2 by Aaron Bentley
Update docs.
237
        :param invert: If True, provide an inverted patch (insertions displayed
238
            as removals, removals displayed as insertions).
0.16.98 by Aaron Bentley
Update docs and prompting
239
        :return: A patches.Patch.
240
        """
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
241
        diff_file = BytesIO()
4526.6.2 by Aaron Bentley
Fix display of diffs for apply mode
242
        if invert:
243
            old_tree = self.work_tree
244
            new_tree = self.target_tree
245
        else:
246
            old_tree = self.target_tree
247
            new_tree = self.work_tree
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
248
        old_path = old_tree.id2path(file_id)
249
        new_path = new_tree.id2path(file_id)
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
250
        path_encoding = osutils.get_terminal_encoding()
4797.57.8 by Alexander Belchenko
using appropriate encoing for diff in shelve/unshelve.
251
        text_differ = diff.DiffText(old_tree, new_tree, diff_file,
7143.15.2 by Jelmer Vernooij
Run autopep8.
252
                                    path_encoding=path_encoding)
7206.6.7 by Jelmer Vernooij
Fix tests.
253
        patch = text_differ.diff(old_path, new_path, 'file', 'file')
0.16.97 by Aaron Bentley
Turn diff_file and text_differ into instance variables.
254
        diff_file.seek(0)
255
        return patches.parse_patch(diff_file)
0.16.1 by Aaron Bentley
Begin implementing UI
256
6182.2.7 by Benoît Pierre
Update shelf UI to use ui.confirm.
257
    def prompt(self, message, choices, default):
6182.2.13 by Benoît Pierre
Rename ui.confirm to ui.choose.
258
        return ui.ui_factory.choose(message, choices, default=default)
6182.2.7 by Benoît Pierre
Update shelf UI to use ui.confirm.
259
260
    def prompt_bool(self, question, allow_editor=False):
0.16.98 by Aaron Bentley
Update docs and prompting
261
        """Prompt the user with a yes/no question.
262
0.16.102 by Aaron Bentley
Minor updates
263
        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
264
        may also raise UserAbort.
0.16.98 by Aaron Bentley
Update docs and prompting
265
        :param question: The question to ask the user.
266
        :return: True or False
267
        """
268
        if self.auto:
0.16.23 by Aaron Bentley
Improve prompting
269
            return True
6182.2.7 by Benoît Pierre
Update shelf UI to use ui.confirm.
270
        alternatives_chars = 'yn'
271
        alternatives = '&yes\n&No'
272
        if allow_editor:
273
            alternatives_chars += 'e'
274
            alternatives += '\n&edit manually'
275
        alternatives_chars += 'fq'
276
        alternatives += '\n&finish\n&quit'
277
        choice = self.prompt(question, alternatives, 1)
278
        if choice is None:
279
            # EOF.
280
            char = 'n'
3990.4.3 by Daniel Watkins
Added help option to shelve prompt.
281
        else:
6182.2.7 by Benoît Pierre
Update shelf UI to use ui.confirm.
282
            char = alternatives_chars[choice]
0.16.23 by Aaron Bentley
Improve prompting
283
        if char == 'y':
284
            return True
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
285
        elif char == 'e' and allow_editor:
286
            raise UseEditor
0.16.23 by Aaron Bentley
Improve prompting
287
        elif char == 'f':
288
            self.auto = True
289
            return True
0.16.24 by Aaron Bentley
Regularize prompts
290
        if char == 'q':
0.16.103 by Aaron Bentley
raise UserAbort instead of doing sys.exit
291
            raise errors.UserAbort()
0.16.23 by Aaron Bentley
Improve prompting
292
        else:
293
            return False
0.16.1 by Aaron Bentley
Begin implementing UI
294
4603.1.7 by Aaron Bentley
Allow configuring change editor.
295
    def handle_modify_text(self, creator, file_id):
4603.1.9 by Aaron Bentley
Misc cleanup.
296
        """Handle modified text, by using hunk selection or file editing.
297
298
        :param creator: A ShelfCreator.
299
        :param file_id: The id of the file that was modified.
300
        :return: The number of changes.
301
        """
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
302
        path = self.work_tree.id2path(file_id)
303
        work_tree_lines = self.work_tree.get_file_lines(path, file_id)
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
304
        try:
4603.1.9 by Aaron Bentley
Misc cleanup.
305
            lines, change_count = self._select_hunks(creator, file_id,
306
                                                     work_tree_lines)
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
307
        except UseEditor:
4603.1.9 by Aaron Bentley
Misc cleanup.
308
            lines, change_count = self._edit_file(file_id, work_tree_lines)
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
309
        if change_count != 0:
310
            creator.shelve_lines(file_id, lines)
311
        return change_count
312
4603.1.9 by Aaron Bentley
Misc cleanup.
313
    def _select_hunks(self, creator, file_id, work_tree_lines):
0.16.98 by Aaron Bentley
Update docs and prompting
314
        """Provide diff hunk selection for modified text.
315
4526.7.2 by Aaron Bentley
Update docs.
316
        If self.reporter.invert_diff is True, the diff is inverted so that
317
        insertions are displayed as removals and vice versa.
318
0.16.98 by Aaron Bentley
Update docs and prompting
319
        :param creator: a ShelfCreator
320
        :param file_id: The id of the file to shelve.
4603.1.9 by Aaron Bentley
Misc cleanup.
321
        :param work_tree_lines: Line contents of the file in the working tree.
0.16.98 by Aaron Bentley
Update docs and prompting
322
        :return: number of shelved hunks.
323
        """
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
324
        if self.reporter.invert_diff:
4603.1.9 by Aaron Bentley
Misc cleanup.
325
            target_lines = work_tree_lines
4526.6.2 by Aaron Bentley
Fix display of diffs for apply mode
326
        else:
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
327
            path = self.target_tree.id2path(file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
328
            target_lines = self.target_tree.get_file_lines(path)
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
329
        textfile.check_text_lines(work_tree_lines)
0.16.72 by Aaron Bentley
Allow shelving binary changes
330
        textfile.check_text_lines(target_lines)
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
331
        parsed = self.get_parsed_patch(file_id, self.reporter.invert_diff)
0.16.43 by Aaron Bentley
Reduce API friction.
332
        final_hunks = []
0.16.15 by Aaron Bentley
Implement auto mode
333
        if not self.auto:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
334
            offset = 0
0.16.61 by Aaron Bentley
Show file name when shelving
335
            self.diff_writer.write(parsed.get_header())
0.16.15 by Aaron Bentley
Implement auto mode
336
            for hunk in parsed.hunks:
7116.2.1 by Jelmer Vernooij
Fix displaying of patch hunks in shelf.
337
                self.diff_writer.write(hunk.as_bytes())
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
338
                selected = self.prompt_bool(self.reporter.vocab['hunk'],
4603.1.7 by Aaron Bentley
Allow configuring change editor.
339
                                            allow_editor=(self.change_editor
340
                                                          is not None))
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
341
                if not self.reporter.invert_diff:
4526.6.2 by Aaron Bentley
Fix display of diffs for apply mode
342
                    selected = (not selected)
343
                if selected:
0.16.41 by Aaron Bentley
Implement shelving with internal patch
344
                    hunk.mod_pos += offset
0.16.43 by Aaron Bentley
Reduce API friction.
345
                    final_hunks.append(hunk)
0.16.41 by Aaron Bentley
Implement shelving with internal patch
346
                else:
347
                    offset -= (hunk.mod_range - hunk.orig_range)
0.16.68 by Aaron Bentley
Avoid having escape codes affect the wrong text.
348
        sys.stdout.flush()
4526.7.1 by Aaron Bentley
Make vocabulary part of reporter.
349
        if self.reporter.invert_diff:
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
350
            change_count = len(final_hunks)
351
        else:
352
            change_count = len(parsed.hunks) - len(final_hunks)
4603.1.2 by Aaron Bentley
Simplify unchanged case.
353
        patched = patches.iter_patched_from_hunks(target_lines,
354
                                                  final_hunks)
355
        lines = list(patched)
4603.1.1 by Aaron Bentley
Initial pass at shelve-via-editor.
356
        return lines, change_count
357
4603.1.9 by Aaron Bentley
Misc cleanup.
358
    def _edit_file(self, file_id, work_tree_lines):
359
        """
360
        :param file_id: id of the file to edit.
361
        :param work_tree_lines: Line contents of the file in the working tree.
362
        :return: (lines, change_region_count), where lines is the new line
363
            content of the file, and change_region_count is the number of
364
            changed regions.
365
        """
6809.4.20 by Jelmer Vernooij
Fix tests.
366
        lines = osutils.split_lines(self.change_editor.edit_file(
367
            self.change_editor.old_tree.id2path(file_id),
7206.6.2 by Jelmer Vernooij
Remove file_id from diff API.
368
            self.change_editor.new_tree.id2path(file_id)))
4603.1.6 by Aaron Bentley
Provide a reasonable count of changes when file edited.
369
        return lines, self._count_changed_regions(work_tree_lines, lines)
370
371
    @staticmethod
372
    def _count_changed_regions(old_lines, new_lines):
373
        matcher = patiencediff.PatienceSequenceMatcher(None, old_lines,
374
                                                       new_lines)
375
        blocks = matcher.get_matching_blocks()
376
        return len(blocks) - 2
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
377
378
379
class Unshelver(object):
0.16.98 by Aaron Bentley
Update docs and prompting
380
    """Unshelve changes into a working tree."""
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
381
382
    @classmethod
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
383
    def from_args(klass, shelf_id=None, action='apply', directory='.',
384
                  write_diff_to=None):
0.16.98 by Aaron Bentley
Update docs and prompting
385
        """Create an unshelver from commandline arguments.
386
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
387
        The returned shelver will have a tree that is locked and should
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
388
        be unlocked.
389
0.16.98 by Aaron Bentley
Update docs and prompting
390
        :param shelf_id: Integer id of the shelf, as a string.
391
        :param action: action to perform.  May be 'apply', 'dry-run',
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
392
            'delete', 'preview'.
0.16.98 by Aaron Bentley
Update docs and prompting
393
        :param directory: The directory to unshelve changes into.
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
394
        :param write_diff_to: See Unshelver.__init__().
0.16.98 by Aaron Bentley
Update docs and prompting
395
        """
0.16.94 by Aaron Bentley
Add unshelve tests
396
        tree, path = workingtree.WorkingTree.open_containing(directory)
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
397
        tree.lock_tree_write()
398
        try:
399
            manager = tree.get_shelf_manager()
400
            if shelf_id is not None:
401
                try:
402
                    shelf_id = int(shelf_id)
403
                except ValueError:
6734.1.1 by Jelmer Vernooij
Fix more imports.
404
                    raise shelf.InvalidShelfId(shelf_id)
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
405
            else:
406
                shelf_id = manager.last_shelf()
407
                if shelf_id is None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
408
                    raise errors.BzrCommandError(
409
                        gettext('No changes are shelved.'))
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
410
            apply_changes = True
411
            delete_shelf = True
412
            read_shelf = True
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
413
            show_diff = False
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
414
            if action == 'dry-run':
415
                apply_changes = False
416
                delete_shelf = False
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
417
            elif action == 'preview':
418
                apply_changes = False
419
                delete_shelf = False
420
                show_diff = True
4889.1.3 by Martin Pool
New option unshelve --keep
421
            elif action == 'delete-only':
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
422
                apply_changes = False
423
                read_shelf = False
4889.1.3 by Martin Pool
New option unshelve --keep
424
            elif action == 'keep':
425
                apply_changes = True
426
                delete_shelf = False
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
427
        except:
428
            tree.unlock()
429
            raise
0.16.65 by Aaron Bentley
Implement unshelve --delete
430
        return klass(tree, manager, shelf_id, apply_changes, delete_shelf,
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
431
                     read_shelf, show_diff, write_diff_to)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
432
0.16.94 by Aaron Bentley
Add unshelve tests
433
    def __init__(self, tree, manager, shelf_id, apply_changes=True,
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
434
                 delete_shelf=True, read_shelf=True, show_diff=False,
435
                 write_diff_to=None):
0.16.98 by Aaron Bentley
Update docs and prompting
436
        """Constructor.
437
438
        :param tree: The working tree to unshelve into.
439
        :param manager: The ShelveManager containing the shelved changes.
440
        :param shelf_id:
441
        :param apply_changes: If True, apply the shelved changes to the
442
            working tree.
443
        :param delete_shelf: If True, delete the changes from the shelf.
444
        :param read_shelf: If True, read the changes from the shelf.
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
445
        :param show_diff: If True, show the diff that would result from
446
            unshelving the changes.
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
447
        :param write_diff_to: A file-like object where the diff will be
448
            written to. If None, ui.ui_factory.make_output_stream() will
449
            be used.
0.16.98 by Aaron Bentley
Update docs and prompting
450
        """
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
451
        self.tree = tree
0.16.98 by Aaron Bentley
Update docs and prompting
452
        manager = tree.get_shelf_manager()
0.16.13 by Aaron Bentley
Appy shelve-management updates to shelver
453
        self.manager = manager
454
        self.shelf_id = shelf_id
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
455
        self.apply_changes = apply_changes
456
        self.delete_shelf = delete_shelf
0.16.65 by Aaron Bentley
Implement unshelve --delete
457
        self.read_shelf = read_shelf
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
458
        self.show_diff = show_diff
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
459
        self.write_diff_to = write_diff_to
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
460
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
461
    def run(self):
0.16.98 by Aaron Bentley
Update docs and prompting
462
        """Perform the unshelving operation."""
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
463
        self.tree.lock_tree_write()
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
464
        cleanups = [self.tree.unlock]
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
465
        try:
0.16.65 by Aaron Bentley
Implement unshelve --delete
466
            if self.read_shelf:
7143.15.2 by Jelmer Vernooij
Run autopep8.
467
                trace.note(gettext('Using changes with id "%d".') %
468
                           self.shelf_id)
0.16.65 by Aaron Bentley
Implement unshelve --delete
469
                unshelver = self.manager.get_unshelver(self.shelf_id)
470
                cleanups.append(unshelver.finalize)
471
                if unshelver.message is not None:
6138.3.4 by Jonathan Riddell
add gettext() to uses of trace.note()
472
                    trace.note(gettext('Message: %s') % unshelver.message)
0.16.65 by Aaron Bentley
Implement unshelve --delete
473
                change_reporter = delta._ChangeReporter()
6719.1.2 by Jelmer Vernooij
Fix some tests.
474
                merger = unshelver.make_merger()
4961.2.13 by Martin Pool
Further progress bar string-pulling
475
                merger.change_reporter = change_reporter
476
                if self.apply_changes:
477
                    merger.do_merge()
478
                elif self.show_diff:
479
                    self.write_diff(merger)
480
                else:
481
                    self.show_changes(merger)
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
482
            if self.delete_shelf:
483
                self.manager.delete_shelf(self.shelf_id)
7143.15.2 by Jelmer Vernooij
Run autopep8.
484
                trace.note(gettext('Deleted changes with id "%d".') %
485
                           self.shelf_id)
0.16.8 by Aaron Bentley
Implement unshelve2, tidy shelve2
486
        finally:
0.16.37 by Aaron Bentley
Use cleanups list to reduce nested try blocks
487
            for cleanup in reversed(cleanups):
488
                cleanup()
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
489
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
490
    def write_diff(self, merger):
491
        """Write this operation's diff to self.write_diff_to."""
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
492
        tree_merger = merger.make_merger()
493
        tt = tree_merger.make_preview_transform()
494
        new_tree = tt.get_preview_tree()
4902.1.8 by John Arbash Meinel
Delay grabbing an output stream until we actually go to show a diff.
495
        if self.write_diff_to is None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
496
            self.write_diff_to = ui.ui_factory.make_output_stream(
497
                encoding_type='exact')
4797.57.10 by Alexander Belchenko
path_encoding selection logic extracted as helper function
498
        path_encoding = osutils.get_diff_header_encoding()
4797.57.8 by Alexander Belchenko
using appropriate encoing for diff in shelve/unshelve.
499
        diff.show_diff_trees(merger.this_tree, new_tree, self.write_diff_to,
7143.15.2 by Jelmer Vernooij
Run autopep8.
500
                             path_encoding=path_encoding)
4902.1.2 by Guilherme Salgado
First round of the new approach, using a new action (--preview) on the unshelve command
501
        tt.finalize()
502
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
503
    def show_changes(self, merger):
0.16.98 by Aaron Bentley
Update docs and prompting
504
        """Show the changes that this operation specifies."""
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
505
        tree_merger = merger.make_merger()
4902.1.3 by Guilherme Salgado
A few tweaks as per John's review
506
        # This implicitly shows the changes via the reporter, so we're done...
0.16.64 by Aaron Bentley
Implement dry-run option for Unshelve
507
        tt = tree_merger.make_preview_transform()
508
        tt.finalize()