~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-17 13:53:36 UTC
  • mfrom: (1939 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1940.
  • Revision ID: john@arbash-meinel.com-20060817135336-100de82962355d3b
[merge] bzr.dev 1939

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
    print >>to_file
89
89
 
90
90
 
 
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
 
91
126
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
92
127
                  diff_opts):
93
128
    """Display a diff by calling out to the external diff program."""
147
182
        if diff_opts:
148
183
            diffcmd.extend(diff_opts)
149
184
 
150
 
        try:
151
 
            pipe = subprocess.Popen(diffcmd,
152
 
                                    stdin=subprocess.PIPE,
153
 
                                    stdout=subprocess.PIPE)
154
 
        except OSError, e:
155
 
            if e.errno == errno.ENOENT:
156
 
                raise errors.NoDiff(str(e))
157
 
            raise
158
 
        pipe.stdin.close()
159
 
 
160
 
        first_line = pipe.stdout.readline()
161
 
        to_file.write(first_line)
162
 
        bzrlib.osutils.pumpfile(pipe.stdout, to_file)
163
 
        rc = pipe.wait()
 
185
        pipe = _spawn_external_diff(diffcmd, capture_errors=True)
 
186
        out,err = pipe.communicate()
 
187
        rc = pipe.returncode
164
188
        
 
189
        # internal_diff() adds a trailing newline, add one here for consistency
 
190
        out += '\n'
165
191
        if rc == 2:
166
192
            # 'diff' gives retcode == 2 for all sorts of errors
167
193
            # one of those is 'Binary files differ'.
168
194
            # Bad options could also be the problem.
169
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]
170
210
            m = re.match('^binary files.*differ$', first_line, re.I)
171
 
            if not m:
 
211
            if m is None:
172
212
                raise BzrError('external diff failed with exit code 2;'
173
213
                               ' command: %r' % (diffcmd,))
174
 
        elif rc not in (0, 1):
 
214
            else:
 
215
                # Binary files differ, just return
 
216
                return
 
217
 
 
218
        # If we got to here, we haven't written out the output of diff
 
219
        # do so now
 
220
        to_file.write(out)
 
221
        if rc not in (0, 1):
175
222
            # returns 1 if files differ; that's OK
176
223
            if rc < 0:
177
224
                msg = 'signal %d' % (-rc)
181
228
            raise BzrError('external diff failed with %s; command: %r' 
182
229
                           % (rc, diffcmd))
183
230
 
184
 
        # internal_diff() adds a trailing newline, add one here for consistency
185
 
        to_file.write('\n')
186
231
 
187
232
    finally:
188
233
        oldtmpf.close()                 # and delete