~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

[merge] bzr.dev 2255

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
import errno
18
17
import os
19
18
import re
 
19
import sys
 
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
 
23
import errno
20
24
import subprocess
21
 
import sys
22
25
import tempfile
23
26
import time
24
27
 
25
28
from bzrlib import (
26
29
    errors,
27
30
    osutils,
 
31
    patiencediff,
 
32
    textfile,
28
33
    )
 
34
""")
 
35
 
29
36
# compatability - plugins import compare_trees from diff!!!
30
37
# deprecated as of 0.10
31
38
from bzrlib.delta import compare_trees
32
 
from bzrlib.errors import BzrError
33
 
from bzrlib.patiencediff import unified_diff
34
 
import bzrlib.patiencediff
35
 
from bzrlib.symbol_versioning import (deprecated_function,
36
 
        zero_eight)
37
 
from bzrlib.textfile import check_text_lines
 
39
from bzrlib.symbol_versioning import (
 
40
        deprecated_function,
 
41
        zero_eight,
 
42
        )
38
43
from bzrlib.trace import mutter, warning
39
44
 
40
45
 
62
67
        return
63
68
    
64
69
    if allow_binary is False:
65
 
        check_text_lines(oldlines)
66
 
        check_text_lines(newlines)
 
70
        textfile.check_text_lines(oldlines)
 
71
        textfile.check_text_lines(newlines)
67
72
 
68
73
    if sequence_matcher is None:
69
 
        sequence_matcher = bzrlib.patiencediff.PatienceSequenceMatcher
70
 
    ud = unified_diff(oldlines, newlines,
 
74
        sequence_matcher = patiencediff.PatienceSequenceMatcher
 
75
    ud = patiencediff.unified_diff(oldlines, newlines,
71
76
                      fromfile=old_filename.encode(path_encoding),
72
77
                      tofile=new_filename.encode(path_encoding),
73
78
                      sequencematcher=sequence_matcher)
91
96
 
92
97
 
93
98
def _set_lang_C():
94
 
    """Set the env var LANG=C"""
 
99
    """Set the env vars LANG=C and LC_ALL=C."""
95
100
    osutils.set_or_unset_env('LANG', 'C')
96
 
    osutils.set_or_unset_env('LC_ALL', None)
 
101
    osutils.set_or_unset_env('LC_ALL', 'C')
97
102
    osutils.set_or_unset_env('LC_CTYPE', None)
98
103
    osutils.set_or_unset_env('LANGUAGE', None)
99
104
 
102
107
    """Spawn the externall diff process, and return the child handle.
103
108
 
104
109
    :param diffcmd: The command list to spawn
105
 
    :param capture_errors: Capture stderr as well as setting LANG=C.
106
 
        This lets us read and understand the output of diff, and respond 
107
 
        to any errors.
 
110
    :param capture_errors: Capture stderr as well as setting LANG=C
 
111
        and LC_ALL=C. This lets us read and understand the output of diff,
 
112
        and respond to any errors.
108
113
    :return: A Popen object.
109
114
    """
110
115
    if capture_errors:
111
116
        if sys.platform == 'win32':
112
117
            # Win32 doesn't support preexec_fn, but that is
113
 
            # okay, because it doesn't support LANG either.
 
118
            # okay, because it doesn't support LANG and LC_ALL either.
114
119
            preexec_fn = None
115
120
        else:
116
121
            preexec_fn = _set_lang_C
212
217
            # Write out the new i18n diff response
213
218
            to_file.write(out+'\n')
214
219
            if pipe.returncode != 2:
215
 
                raise BzrError('external diff failed with exit code 2'
216
 
                               ' when run with LANG=C, but not when run'
217
 
                               ' natively: %r' % (diffcmd,))
 
220
                raise errors.BzrError(
 
221
                               'external diff failed with exit code 2'
 
222
                               ' when run with LANG=C and LC_ALL=C,'
 
223
                               ' but not when run natively: %r' % (diffcmd,))
218
224
 
219
225
            first_line = lang_c_out.split('\n', 1)[0]
220
226
            # Starting with diffutils 2.8.4 the word "binary" was dropped.
221
227
            m = re.match('^(binary )?files.*differ$', first_line, re.I)
222
228
            if m is None:
223
 
                raise BzrError('external diff failed with exit code 2;'
224
 
                               ' command: %r' % (diffcmd,))
 
229
                raise errors.BzrError('external diff failed with exit code 2;'
 
230
                                      ' command: %r' % (diffcmd,))
225
231
            else:
226
232
                # Binary files differ, just return
227
233
                return
236
242
            else:
237
243
                msg = 'exit code %d' % rc
238
244
                
239
 
            raise BzrError('external diff failed with %s; command: %r' 
240
 
                           % (rc, diffcmd))
 
245
            raise errors.BzrError('external diff failed with %s; command: %r' 
 
246
                                  % (rc, diffcmd))
241
247
 
242
248
 
243
249
    finally:
300
306
 
301
307
def diff_cmd_helper(tree, specific_files, external_diff_options, 
302
308
                    old_revision_spec=None, new_revision_spec=None,
 
309
                    revision_specs=None,
303
310
                    old_label='a/', new_label='b/'):
304
311
    """Helper for cmd_diff.
305
312
 
306
 
   tree 
 
313
    :param tree:
307
314
        A WorkingTree
308
315
 
309
 
    specific_files
 
316
    :param specific_files:
310
317
        The specific files to compare, or None
311
318
 
312
 
    external_diff_options
 
319
    :param external_diff_options:
313
320
        If non-None, run an external diff, and pass it these options
314
321
 
315
 
    old_revision_spec
 
322
    :param old_revision_spec:
316
323
        If None, use basis tree as old revision, otherwise use the tree for
317
324
        the specified revision. 
318
325
 
319
 
    new_revision_spec
 
326
    :param new_revision_spec:
320
327
        If None, use working tree as new revision, otherwise use the tree for
321
328
        the specified revision.
322
329
    
 
330
    :param revision_specs: 
 
331
        Zero, one or two RevisionSpecs from the command line, saying what revisions 
 
332
        to compare.  This can be passed as an alternative to the old_revision_spec 
 
333
        and new_revision_spec parameters.
 
334
 
323
335
    The more general form is show_diff_trees(), where the caller
324
336
    supplies any two trees.
325
337
    """
 
338
 
 
339
    # TODO: perhaps remove the old parameters old_revision_spec and
 
340
    # new_revision_spec, since this is only really for use from cmd_diff and
 
341
    # it now always passes through a sequence of revision_specs -- mbp
 
342
    # 20061221
 
343
 
326
344
    def spec_tree(spec):
327
345
        if tree:
328
346
            revision = spec.in_store(tree.branch)
331
349
        revision_id = revision.rev_id
332
350
        branch = revision.branch
333
351
        return branch.repository.revision_tree(revision_id)
 
352
 
 
353
    if revision_specs is not None:
 
354
        assert (old_revision_spec is None
 
355
                and new_revision_spec is None)
 
356
        if len(revision_specs) > 0:
 
357
            old_revision_spec = revision_specs[0]
 
358
        if len(revision_specs) > 1:
 
359
            new_revision_spec = revision_specs[1]
 
360
 
334
361
    if old_revision_spec is None:
335
362
        old_tree = tree.basis_tree()
336
363
    else:
337
364
        old_tree = spec_tree(old_revision_spec)
338
365
 
339
 
    if new_revision_spec is None:
 
366
    if (new_revision_spec is None
 
367
        or new_revision_spec.spec is None):
340
368
        new_tree = tree
341
369
    else:
342
370
        new_tree = spec_tree(new_revision_spec)
 
371
 
343
372
    if new_tree is not tree:
344
373
        extra_trees = (tree,)
345
374
    else: