~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2006-06-20 05:32:16 UTC
  • mfrom: (1797 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1798.
  • Revision ID: mbp@sourcefrog.net-20060620053216-817857d7ca3e9d1f
[merge] bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd.
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
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
import os
 
19
import subprocess
 
20
import sys
 
21
import tempfile
17
22
import time
18
23
 
19
24
from bzrlib.delta import compare_trees
20
25
from bzrlib.errors import BzrError
21
26
import bzrlib.errors as errors
 
27
import bzrlib.osutils
22
28
from bzrlib.patiencediff import unified_diff
23
29
import bzrlib.patiencediff
24
30
from bzrlib.symbol_versioning import (deprecated_function,
25
31
        zero_eight)
26
32
from bzrlib.textfile import check_text_lines
27
 
from bzrlib.trace import mutter
 
33
from bzrlib.trace import mutter, warning
28
34
 
29
35
 
30
36
# TODO: Rather than building a changeset object, we should probably
82
88
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
83
89
                  diff_opts):
84
90
    """Display a diff by calling out to the external diff program."""
85
 
    import sys
 
91
    if hasattr(to_file, 'fileno'):
 
92
        out_file = to_file
 
93
        have_fileno = True
 
94
    else:
 
95
        out_file = subprocess.PIPE
 
96
        have_fileno = False
86
97
    
87
 
    if to_file != sys.stdout:
88
 
        raise NotImplementedError("sorry, can't send external diff other than to stdout yet",
89
 
                                  to_file)
90
 
 
91
98
    # make sure our own output is properly ordered before the diff
92
99
    to_file.flush()
93
100
 
94
 
    from tempfile import NamedTemporaryFile
95
 
    import os
96
 
 
97
 
    oldtmpf = NamedTemporaryFile()
98
 
    newtmpf = NamedTemporaryFile()
 
101
    oldtmp_fd, old_abspath = tempfile.mkstemp(prefix='bzr-diff-old-')
 
102
    newtmp_fd, new_abspath = tempfile.mkstemp(prefix='bzr-diff-new-')
 
103
    oldtmpf = os.fdopen(oldtmp_fd, 'wb')
 
104
    newtmpf = os.fdopen(newtmp_fd, 'wb')
99
105
 
100
106
    try:
101
107
        # TODO: perhaps a special case for comparing to or from the empty
108
114
        oldtmpf.writelines(oldlines)
109
115
        newtmpf.writelines(newlines)
110
116
 
111
 
        oldtmpf.flush()
112
 
        newtmpf.flush()
 
117
        oldtmpf.close()
 
118
        newtmpf.close()
113
119
 
114
120
        if not diff_opts:
115
121
            diff_opts = []
116
122
        diffcmd = ['diff',
117
123
                   '--label', old_filename,
118
 
                   oldtmpf.name,
 
124
                   old_abspath,
119
125
                   '--label', new_filename,
120
 
                   newtmpf.name]
 
126
                   new_abspath,
 
127
                   '--binary',
 
128
                  ]
121
129
 
122
130
        # diff only allows one style to be specified; they don't override.
123
131
        # note that some of these take optargs, and the optargs can be
143
151
        if diff_opts:
144
152
            diffcmd.extend(diff_opts)
145
153
 
146
 
        rc = os.spawnvp(os.P_WAIT, 'diff', diffcmd)
 
154
        try:
 
155
            pipe = subprocess.Popen(diffcmd,
 
156
                                    stdin=subprocess.PIPE,
 
157
                                    stdout=out_file)
 
158
        except OSError, e:
 
159
            if e.errno == errno.ENOENT:
 
160
                raise errors.NoDiff(str(e))
 
161
            raise
 
162
        pipe.stdin.close()
 
163
 
 
164
        if not have_fileno:
 
165
            bzrlib.osutils.pumpfile(pipe.stdout, to_file)
 
166
        rc = pipe.wait()
147
167
        
148
168
        if rc != 0 and rc != 1:
149
169
            # returns 1 if files differ; that's OK
156
176
    finally:
157
177
        oldtmpf.close()                 # and delete
158
178
        newtmpf.close()
 
179
        # Clean up. Warn in case the files couldn't be deleted
 
180
        # (in case windows still holds the file open, but not
 
181
        # if the files have already been deleted)
 
182
        try:
 
183
            os.remove(old_abspath)
 
184
        except OSError, e:
 
185
            if e.errno not in (errno.ENOENT,):
 
186
                warning('Failed to delete temporary file: %s %s',
 
187
                        old_abspath, e)
 
188
        try:
 
189
            os.remove(new_abspath)
 
190
        except OSError:
 
191
            if e.errno not in (errno.ENOENT,):
 
192
                warning('Failed to delete temporary file: %s %s',
 
193
                        new_abspath, e)
159
194
 
160
195
 
161
196
@deprecated_function(zero_eight)
175
210
    supplies any two trees.
176
211
    """
177
212
    if output is None:
178
 
        import sys
179
213
        output = sys.stdout
180
214
 
181
215
    if from_spec is None:
222
256
    The more general form is show_diff_trees(), where the caller
223
257
    supplies any two trees.
224
258
    """
225
 
    import sys
226
259
    output = sys.stdout
227
260
    def spec_tree(spec):
228
261
        revision_id = spec.in_store(tree.branch).rev_id