mercurial/mdiff.py
author mpm@selenic.com
Tue, 16 Aug 2005 14:53:47 -0800
changeset 917 7f3f55903496
parent 582 df8a5a0098d4
child 1015 22571b8d35d3
permissions -rw-r--r--
Fix hg clone race with writer Most read operations in hg don't need locks because we order reads and writes for consistency. Clone is an exception to this as we're copying entire file histories and could end up with more file history copied than we have commits. For now, make clone take a lock on the source repo. Non-hardlinked clone should eventually be changed to use lockless pull.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
239
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     1
# mdiff.py - diff and patch routines for mercurial
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     2
#
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     3
# Copyright 2005 Matt Mackall <mpm@selenic.com>
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     4
#
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     5
# This software may be used and distributed according to the terms
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
75840796e8e2 mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents: 184
diff changeset
     7
432
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
     8
import difflib, struct, bdiff
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
     9
from mpatch import *
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    10
396
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    11
def unidiff(a, ad, b, bd, fn, r=None):
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    12
35
9197c26a414b unidiff: punt on comparing empty files
mpm@selenic.com
parents: 0
diff changeset
    13
    if not a and not b: return ""
264
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    14
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    15
    if a == None:
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    16
        b = b.splitlines(1)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    17
        l1 = "--- %s\t%s\n" % ("/dev/null", ad)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    18
        l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    19
        l3 = "@@ -0,0 +1,%d @@\n" % len(b)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    20
        l = [l1, l2, l3] + ["+" + e for e in b]
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    21
    elif b == None:
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    22
        a = a.splitlines(1)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    23
        l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    24
        l2 = "+++ %s\t%s\n" % ("/dev/null", bd)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    25
        l3 = "@@ -1,%d +0,0 @@\n" % len(a)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    26
        l = [l1, l2, l3] + ["-" + e for e in a]
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    27
    else:
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    28
        a = a.splitlines(1)
4c1d7072d5cd Attempt to make diff deal with null sources properly
mpm@selenic.com
parents: 249
diff changeset
    29
        b = b.splitlines(1)
272
467cea2bf2d8 diff: use tab to separate date from filename
mpm@selenic.com
parents: 264
diff changeset
    30
        l = list(difflib.unified_diff(a, b, "a/" + fn, "b/" + fn))
278
777e388c06d6 unidiff: handle empty diffs more gracefully
mpm@selenic.com
parents: 272
diff changeset
    31
        if not l: return ""
272
467cea2bf2d8 diff: use tab to separate date from filename
mpm@selenic.com
parents: 264
diff changeset
    32
        # difflib uses a space, rather than a tab
467cea2bf2d8 diff: use tab to separate date from filename
mpm@selenic.com
parents: 264
diff changeset
    33
        l[0] = l[0][:-2] + "\t" + ad + "\n"
467cea2bf2d8 diff: use tab to separate date from filename
mpm@selenic.com
parents: 264
diff changeset
    34
        l[1] = l[1][:-2] + "\t" + bd + "\n"
170
e6c621a825f2 hg diff: fix missing final newline bug
mpm@selenic.com
parents: 127
diff changeset
    35
e6c621a825f2 hg diff: fix missing final newline bug
mpm@selenic.com
parents: 127
diff changeset
    36
    for ln in xrange(len(l)):
e6c621a825f2 hg diff: fix missing final newline bug
mpm@selenic.com
parents: 127
diff changeset
    37
        if l[ln][-1] != '\n':
e6c621a825f2 hg diff: fix missing final newline bug
mpm@selenic.com
parents: 127
diff changeset
    38
            l[ln] += "\n\ No newline at end of file\n"
e6c621a825f2 hg diff: fix missing final newline bug
mpm@selenic.com
parents: 127
diff changeset
    39
396
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    40
    if r:
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    41
        l.insert(0, "diff %s %s\n" %
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    42
                    (' '.join(["-r %s" % rev for rev in r]), fn))
8f8bb77d560e Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 361
diff changeset
    43
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    44
    return "".join(l)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    45
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    46
def sortdiff(a, b):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    47
    la = lb = 0
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    48
    lena = len(a)
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    49
    lenb = len(b)
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 432
diff changeset
    50
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    51
    while 1:
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    52
        am, bm, = la, lb
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    53
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    54
        # walk over matching lines
326
235443668bea mdiff: fix the fix
mpm@selenic.com
parents: 325
diff changeset
    55
        while lb < lenb and la < lena and a[la] == b[lb] :
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    56
            la += 1
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    57
            lb += 1
318
2819f63b16bf mdiff: revert grouping optimization for the time being
mpm@selenic.com
parents: 317
diff changeset
    58
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    59
        if la > am:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    60
            yield (am, bm, la - am) # return a match
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    61
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    62
        # skip mismatched lines from b
361
88268aa2b8d2 Fix another sortdiff cornercase
mpm@selenic.com
parents: 330
diff changeset
    63
        while la < lena and lb < lenb and b[lb] < a[la]:
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    64
            lb += 1
318
2819f63b16bf mdiff: revert grouping optimization for the time being
mpm@selenic.com
parents: 317
diff changeset
    65
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    66
        if lb >= lenb:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    67
            break
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 432
diff changeset
    68
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    69
        # skip mismatched lines from a
361
88268aa2b8d2 Fix another sortdiff cornercase
mpm@selenic.com
parents: 330
diff changeset
    70
        while la < lena and lb < lenb and b[lb] > a[la]:
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    71
            la += 1
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    72
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    73
        if la >= lena:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    74
            break
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 432
diff changeset
    75
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    76
    yield (lena, lenb, 0)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    77
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    78
def diff(a, b, sorted=0):
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    79
    if not a:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    80
        s = "".join(b)
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    81
        return s and (struct.pack(">lll", 0, 0, len(s)) + s)
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    82
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    83
    bin = []
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    84
    p = [0]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    85
    for i in a: p.append(p[-1] + len(i))
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    86
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    87
    if sorted:
317
b18ce742566a hg commit: user and date options
mpm@selenic.com
parents: 278
diff changeset
    88
        try:
b18ce742566a hg commit: user and date options
mpm@selenic.com
parents: 278
diff changeset
    89
            d = sortdiff(a, b)
b18ce742566a hg commit: user and date options
mpm@selenic.com
parents: 278
diff changeset
    90
        except:
b18ce742566a hg commit: user and date options
mpm@selenic.com
parents: 278
diff changeset
    91
            raise
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    92
    else:
325
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    93
        d = difflib.SequenceMatcher(None, a, b).get_matching_blocks()
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    94
    la = 0
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    95
    lb = 0
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    96
    for am, bm, size in d:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    97
        s = "".join(b[lb:bm])
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    98
        if am > la or s:
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
    99
            bin.append(struct.pack(">lll", p[la], p[am], len(s)) + s)
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
   100
        la = am + size
ad87e19854a6 mdiff: reinstate new algorithm
mpm@selenic.com
parents: 318
diff changeset
   101
        lb = bm + size
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 432
diff changeset
   102
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   103
    return "".join(bin)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   104
120
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   105
def patchtext(bin):
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   106
    pos = 0
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   107
    t = []
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   108
    while pos < len(bin):
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   109
        p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   110
        pos += 12
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   111
        t.append(bin[pos:pos + l])
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   112
        pos += l
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   113
    return "".join(t)
bae6f0328f63 Add a function to return the new text from a binary diff
mpm@selenic.com
parents: 75
diff changeset
   114
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   115
def patch(a, bin):
72
4a6ab4d80dc4 Add an O(m + nlog n) patching extension
mpm@selenic.com
parents: 71
diff changeset
   116
    return patches(a, [bin])
432
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
   117
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
   118
textdiff = bdiff.bdiff
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
   119
3b9e3d3d2810 Start using bdiff for generating deltas
mpm@selenic.com
parents: 396
diff changeset
   120