~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-31 16:12:57 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060731161257-91a231523255332c
new official bzr.ico

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import errno
18
18
import os
19
 
import re
20
19
import subprocess
21
20
import sys
22
21
import tempfile
88
87
    print >>to_file
89
88
 
90
89
 
91
 
def _set_lang_C():
92
 
    """Set the env var LANG=C"""
93
 
    os.environ['LANG'] = 'C'
94
 
 
95
 
 
96
 
def _spawn_external_diff(diffcmd, capture_errors=True):
97
 
    """Spawn the externall diff process, and return the child handle.
98
 
 
99
 
    :param diffcmd: The command list to spawn
100
 
    :param capture_errors: Capture stderr as well as setting LANG=C.
101
 
        This lets us read and understand the output of diff, and respond 
102
 
        to any errors.
103
 
    :return: A Popen object.
104
 
    """
105
 
    if capture_errors:
106
 
        preexec_fn = _set_lang_C
107
 
        stderr = subprocess.PIPE
108
 
    else:
109
 
        preexec_fn = None
110
 
        stderr = None
111
 
 
112
 
    try:
113
 
        pipe = subprocess.Popen(diffcmd,
114
 
                                stdin=subprocess.PIPE,
115
 
                                stdout=subprocess.PIPE,
116
 
                                stderr=stderr,
117
 
                                preexec_fn=preexec_fn)
118
 
    except OSError, e:
119
 
        if e.errno == errno.ENOENT:
120
 
            raise errors.NoDiff(str(e))
121
 
        raise
122
 
 
123
 
    return pipe
124
 
 
125
 
 
126
90
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
127
91
                  diff_opts):
128
92
    """Display a diff by calling out to the external diff program."""
 
93
    if hasattr(to_file, 'fileno'):
 
94
        out_file = to_file
 
95
        have_fileno = True
 
96
    else:
 
97
        out_file = subprocess.PIPE
 
98
        have_fileno = False
 
99
    
129
100
    # make sure our own output is properly ordered before the diff
130
101
    to_file.flush()
131
102
 
182
153
        if diff_opts:
183
154
            diffcmd.extend(diff_opts)
184
155
 
185
 
        pipe = _spawn_external_diff(diffcmd, capture_errors=True)
186
 
        out,err = pipe.communicate()
187
 
        rc = pipe.returncode
 
156
        try:
 
157
            pipe = subprocess.Popen(diffcmd,
 
158
                                    stdin=subprocess.PIPE,
 
159
                                    stdout=out_file)
 
160
        except OSError, e:
 
161
            if e.errno == errno.ENOENT:
 
162
                raise errors.NoDiff(str(e))
 
163
            raise
 
164
        pipe.stdin.close()
 
165
 
 
166
        if not have_fileno:
 
167
            bzrlib.osutils.pumpfile(pipe.stdout, to_file)
 
168
        rc = pipe.wait()
188
169
        
189
 
        # internal_diff() adds a trailing newline, add one here for consistency
190
 
        out += '\n'
191
 
        if rc == 2:
192
 
            # 'diff' gives retcode == 2 for all sorts of errors
193
 
            # one of those is 'Binary files differ'.
194
 
            # Bad options could also be the problem.
195
 
            # 'Binary files' is not a real error, so we suppress that error.
196
 
            lang_c_out = out
197
 
 
198
 
            # Since we got here, we want to make sure to give an i18n error
199
 
            pipe = _spawn_external_diff(diffcmd, capture_errors=False)
200
 
            out, err = pipe.communicate()
201
 
 
202
 
            # Write out the new i18n diff response
203
 
            to_file.write(out+'\n')
204
 
            if pipe.returncode != 2:
205
 
                raise BzrError('external diff failed with exit code 2'
206
 
                               ' when run with LANG=C, but not when run'
207
 
                               ' natively: %r' % (diffcmd,))
208
 
 
209
 
            first_line = lang_c_out.split('\n', 1)[0]
210
 
            # Starting with diffutils 2.8.4 the word "binary" was dropped.
211
 
            m = re.match('^(binary )?files.*differ$', first_line, re.I)
212
 
            if m is None:
213
 
                raise BzrError('external diff failed with exit code 2;'
214
 
                               ' command: %r' % (diffcmd,))
215
 
            else:
216
 
                # Binary files differ, just return
217
 
                return
218
 
 
219
 
        # If we got to here, we haven't written out the output of diff
220
 
        # do so now
221
 
        to_file.write(out)
222
 
        if rc not in (0, 1):
 
170
        if rc != 0 and rc != 1:
223
171
            # returns 1 if files differ; that's OK
224
172
            if rc < 0:
225
173
                msg = 'signal %d' % (-rc)
226
174
            else:
227
175
                msg = 'exit code %d' % rc
228
176
                
229
 
            raise BzrError('external diff failed with %s; command: %r' 
230
 
                           % (rc, diffcmd))
231
 
 
232
 
 
 
177
            raise BzrError('external diff failed with %s; command: %r' % (rc, diffcmd))
233
178
    finally:
234
179
        oldtmpf.close()                 # and delete
235
180
        newtmpf.close()