contrib/hgdiff
author Brendan Cully <brendan@kublai.com>
Fri, 22 Sep 2006 08:19:25 -0700
changeset 3144 8342ad5abe0b
parent 1644 e7e6504c4989
child 3398 0f308690bda8
permissions -rwxr-xr-x
Make filectx lazier - some users never use filenode
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1636
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
#!/usr/bin/env python
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
import os, sys, struct, stat
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
import difflib
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
import re
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     6
from optparse import OptionParser
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
from mercurial.bdiff import bdiff, blocks
1644
e7e6504c4989 Remove duplicate bunidiff code from hgdiff, importing from mdiff.py instead
mason@suse.com
parents: 1636
diff changeset
     8
from mercurial.mdiff import bunidiff
1636
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     9
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    10
VERSION="0.2"
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
usage = "usage: %prog [options] file1 file2"
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
parser = OptionParser(usage=usage)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
parser.add_option("-d", "--difflib", action="store_true", default=False)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    15
parser.add_option('-x', '--count', default=1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    16
parser.add_option('-c', '--context', type="int", default=3)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    17
parser.add_option('-p', '--show-c-function', action="store_true", default=False)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
parser.add_option('-w', '--ignore-all-space', action="store_true", 
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    19
                  default=False)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
(options, args) = parser.parse_args()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    23
if not args:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
    parser.print_help()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
    sys.exit(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
# simple utility function to put all the
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
# files from a directory tree into a dict
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
def buildlist(names, top):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
    tlen = len(top)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
    for root, dirs, files in os.walk(top):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
        l = root[tlen + 1:]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    33
        for x in files:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
            p = os.path.join(root, x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
            st = os.lstat(p)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
            if stat.S_ISREG(st.st_mode):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
                names[os.path.join(l, x)] = (st.st_dev, st.st_ino)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
def diff_files(file1, file2):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
    if file1 == None:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
        b = file(file2).read().splitlines(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
        l1 = "--- %s\n" % (file2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    43
        l2 = "+++ %s\n" % (file2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
        l3 = "@@ -0,0 +1,%d @@\n" % len(b)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    45
        l = [l1, l2, l3] + ["+" + e for e in b]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    46
    elif file2 == None:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
        a = file(file1).read().splitlines(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    48
        l1 = "--- %s\n" % (file1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
        l2 = "+++ %s\n" % (file1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
        l3 = "@@ -1,%d +0,0 @@\n" % len(a)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
        l = [l1, l2, l3] + ["-" + e for e in a]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
    else:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
        t1 = file(file1).read()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
        t2 = file(file2).read()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
        l1 = t1.splitlines(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
        l2 = t2.splitlines(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
        if options.difflib:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
            l = difflib.unified_diff(l1, l2, file1, file2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
        else:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
            l = bunidiff(t1, t2, l1, l2, file1, file2, context=options.context,
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
                     showfunc=options.show_c_function,
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
                     ignorews=options.ignore_all_space)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
    for x in l:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
        if x[-1] != '\n':
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
            x += "\n\ No newline at end of file\n"
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
        print x,
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
file1 = args[0]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
file2 = args[1]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
if os.path.isfile(file1) and os.path.isfile(file2):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
    diff_files(file1, file2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
elif os.path.isdir(file1):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
    if not os.path.isdir(file2):
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
        sys.stderr.write("file types don't match\n")
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
        sys.exit(1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    78
    d1 = {}
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
    d2 = {}
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
    buildlist(d1, file1)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
    buildlist(d2, file2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
    keys = d1.keys()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
    keys.sort()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    85
    for x in keys:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    86
        if x not in d2:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
            f2 = None
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
        else:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
            f2 = os.path.join(file2, x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    90
            st1 = d1[x]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
            st2 = d2[x]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
            del d2[x]
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
            if st1[0] == st2[0] and st1[1] == st2[1]:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
                sys.stderr.write("%s is a hard link\n" % x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
                continue
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
        x = os.path.join(file1, x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
        diff_files(x, f2)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
    keys = d2.keys()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    99
    keys.sort()
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   100
    for x in keys:
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
        f1 = None
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
        x = os.path.join(file2, x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
        diff_files(f1, x)
7da32bb3d1d3 contrib: add Chris Mason's stand-alone diff tool
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104