This file is indexed.

/usr/lib/python2.7/dist-packages/xxdiff/scripts/svndiff.py is in xxdiff-scripts 1:4.0.1+hg487+dfsg-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# This file is part of the xxdiff package.  See xxdiff for license and details.

"""xx-svn-diff [<options>] <file> <file> [<file>]

Script that invokes xxdiff for all modified files in the given Subversion
checkout area. Optionally replace the output file by decision mode.
"""

__author__ = "Martin Blais <blais@furius.ca>"
__depends__ = ['xxdiff', 'Python-2.4', 'Subversion']


# stdlib imports.
import sys, os, tempfile, datetime
from os.path import *

# xxdiff imports.
import xxdiff.scripts
import xxdiff.invoke
from xxdiff.invoke import title_opts
import xxdiff.editor
import xxdiff.resilient
import xxdiff.utils
from xxdiff.utils import makedirs
import xxdiff.history
import xxdiff.condrepl
from xxdiff.scripts import tmpprefix, script_name
from xxdiff.scm import subversion
from xxdiff.scripts.svnforeign import query_unregistered_svn_files


def review_file(sobj, opts):
    """
    Check the given status object and if necessary, spawn xxdiff on it.

    Return a pair of ((file type description, action) waiter-object).
    """
    msg = ('normal', 'display')
    dopts = []
    merged = sobj.filename
    try:
        # Ignore unmodified files if there are any.
        if sobj.status in (' ', '?'):
            msg = ('unmodified', 'ignored')
            return msg, None

        # Diff modified files
        if sobj.status in ('M', 'C'):
            tmpf = subversion.cat_revision_temp(sobj.filename, 'BASE')
            left, right = tmpf.name, sobj.filename

            dopts.extend(title_opts('%s (BASE)' % sobj.filename))

        # Diff added files
        elif sobj.status == 'A':
            # Check if it is a directory.
            if not isfile(sobj.filename):
                msg = ('directory', 'skip')
                return msg, None

            if sobj.withhist == '+':
                # Get the source filename from the history.
                info = subversion.getinfo(sobj.filename)
                from_url, from_rev = [info.get('Copied From %s' % x, None)
                                      for x in 'URL', 'Rev']

                tmpf = subversion.cat_revision_temp(sobj.filename, 'BASE')
                dopts.extend(title_opts('%s (%s)' % (from_url, from_rev)))
            else:
                tmpf = tempfile.NamedTemporaryFile('w', prefix=tmpprefix)
                dopts.extend(title_opts('(NON-EXISTING)'))

            left, right = tmpf.name, sobj.filename

        # Diff deleted files
        elif sobj.status == 'D':
            tmpf = subversion.cat_revision_temp(sobj.filename, 'BASE')
            tmpf_empty = tempfile.NamedTemporaryFile('w', prefix=tmpprefix)

            dopts.extend(title_opts('%s (BASE)' % sobj.filename,
                                    '(DELETED)'))

            left, right = tmpf.name, tmpf_empty.name

        # We don't know what to do with the rest yet.
        else:
            msg = ('unknown', 'ignored')
            print >> sys.stderr, (
                "Error: Action for status '%s' on file '%s' "
                "is not implemented yet") % (sobj.status, sobj.filename)
            return msg, None
    finally:
        pass

    # Check for non-text files.
    if not xxdiff.utils.istextfile(left) or not xxdiff.utils.istextfile(right):
        return ('non-text', 'skip'), None

    # Run xxdiff on the files.
    if opts.review:
        dopts.extend(['--decision'])
        opts.no_confirm = False
        opts.dry_run = False
        decision = xxdiff.condrepl.cond_replace(left, right, opts, sys.stdout,
                                                False, replfn=right)
        waiter = None
    else:
        waiter = xxdiff.invoke.xxdiff_display(opts, left, right, nowait=1, *dopts)

    return msg, waiter

def parse_options():
    """
    Parse the options.
    """
    import optparse
    parser = optparse.OptionParser(__doc__.strip())

    parser.add_option('-r', '--review', '--replace', action='store_true',
                      help="Review/replace mode: diff the file and replace"
                      "the target file by the output of the diff. Runs in "
                      "decision mode. This is useful in order to remove "
                      "selected changes before committing in.")

    parser.add_option('-c', '--commit', '--commit-with-comments',
                      action='store_true',
                      help="Spawns an editor window for adding comments and "
                      "starts the review, then commits the files with the "
                      "given comment.  NOTE: you editor is taken from the "
                      "environment variables XXDIFF_EDITOR, SVN_EDITOR, and "
                      "then EDITOR.  This program *MUST* open a new window "
                      "(for example, you cannot use just 'vi' but rather "
                      "something like: xterm -e 'vi %s').")

    o = parser.add_option('-C', '--comments-file', action='store',
                          default=None,
                          help="Specified the comments file to use.  This file "
                          "is left behind and its contents reused if it is "
                          "specified.")

    parser.add_option('-f', '--foreign', '--consider-foreign-files',
                      action='store_true',
                      help="Before starting the review/diffs, check all the "
                      "unregistered files and ask the user one by one about "
                      "what to do with them.")

    for mod in xxdiff.invoke, xxdiff.history:
        mod.options_graft(parser)
    xxdiff.backup.options_graft(parser,
                                "These options affect automatic backup of "
                                "deleted files, if enabled.")

    xxdiff.scripts.install_autocomplete(parser)

    opts, args = parser.parse_args()

    for mod in xxdiff.backup, xxdiff.invoke, xxdiff.history:
        mod.options_validate(opts, parser)

    if opts.comments_file and not opts.commit:
        print >> sys.stderr, "(Option '%s' ignored.) " % o.dest

    # Add a verbose option for svnforeign to use.
    opts.verbose = True

    return opts, args


def svndiff_main():
    """
    Main program for svn-diff script.
    """
    opts, args = parse_options()

    # Compute the location of the resilient directory for the comments and
    # history files (and maybe more stuff later on).
    resildir = xxdiff.resilient.resilient_for_paths(args)
    hist = xxdiff.history.History(opts, resildir)

    # Compute a list of files to ignore (e.g. if the comments or history file is
    # located in the checkout, we want to ignore them and then associated
    # swap/temp files).
    ignofiles = []
    if opts.commit and opts.comments_file:
        comfn = abspath(opts.comments_file)
        ignofiles.extend([comfn, '%s.swp' % comfn])
    if opts.history and opts.history_file:
        histfn = abspath(opts.history_file)
        ignofiles.extend([histfn, '%s.swp' % histfn])

    if opts.foreign:
        # Consider the unregistered files.
        if query_unregistered_svn_files(
            args, opts, sys.stdout, ignore=ignofiles) is not True:
            # The user has quit, don't continue.
            sys.exit(0)
        print
        print

    # Get the status of the working copy.
    statii = subversion.status(args)

    # Ignore the comments file from the svn status output.
    statii = [s for s in statii if abspath(s.filename) not in ignofiles]

    if not statii:
        print '(Nothing to do, exiting.)'
        hist.delete()
        return

    # First print out the status to a string.
    renstatus = os.linesep.join(x.parsed_line for x in statii)

    if opts.commit:
        # File to delete after a successful commit.
        if opts.comments_file:
            comfn = abspath(opts.comments_file)
        else:
            # Select a comments file and make sure that it exists.
            comfn = join(resildir, 'comments')

            makedirs(resildir, False)
            if not exists(comfn):
                open(comfn, 'w')

    # Spawn an editor if requested before starting the review.
    if opts.commit:
        m = {'date': datetime.datetime.now()}
        comments = None # renstatus
        edit_waiter = xxdiff.editor.spawn_editor(comments, filename=comfn)

    # First print out the status to the user.
    print 'Status Of Files To Be Diffed'
    print '----------------------------'
    print renstatus

    # Then we start printing each file and the associated decision.
    msgfmt = '  %-10s | %-10s | %s'
    print
    print msgfmt % ('Type', 'Action', 'Status')
    print msgfmt % ('-'*10, '-'*10, '-'*40)

    # Main loop for graphical diffs, over each of the files reported by status.
    for s in statii:
        kind, action = 'unknown', 'exception' # Initialize for in case of an
                                              # exception.
        try:
            # Skip directories.
            if isdir(s.filename):
                kind, action = 'directory', 'skip'
                continue
            elif islink(s.filename):
                kind, action = 'symlink', 'skip'
                continue

            # Compute unique string for history recorder.  We use the size, last
            # modification time, and status info to hash on this.
            if exists(s.filename):
                fstat = os.lstat(s.filename)
                sz, mtime = fstat.st_size, fstat.st_mtime
            else:
                # Deal with files that have been deleted.
                sz, mtime = 0, 0
            histitem = ' '.join((str(sz), str(mtime), s.parsed_line))

            # If the file has already been reviewed in the history, skip it.
            if hist.check(histitem):
                kind, action = 'seen', 'skip'
                continue

            # Review the file.
            (kind, action), waiter = review_file(s, opts)
        finally:
            print msgfmt % (kind, action, s.parsed_line)

        if waiter is not None:
            waiter()

        # We have succesfully finished viewing the file, add it to the history.
        hist.append(histitem)

    # Commit the files if requested.
    if opts.commit:
        print "\nWaiting for editor '%s' to complete..." % edit_waiter.command,
        sys.stdout.flush()
        comments = edit_waiter()
        print 'Done.\n'
        print 'Recorded Merge Comments: ',
        if comments == '':
            print '(None)'
            comments = None
        else:
            print
            print '-' * 70
            print comments
            print '-' * 70

        subversion.commit(args, comments=comments)

        # Delete temporary comments flie if we created it.
        if not opts.comments_file:
            xxdiff.resilient.resilient_remove(comfn)

    # The entire list of files has been reviewed (and possibly committed), clear
    # the history file.
    if opts.history:
        print
        print '(Review complete, history cleared)'
        hist.delete()


def main():
    xxdiff.scripts.interruptible_main(svndiff_main)

if __name__ == '__main__':
    main()