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