#!/usr/bin/env python
"""
Calculates the diffs between two directory hierarchies without looking at the
contents of the files, just by comparing the file sizes.
"""

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


def main():
    import optparse
    parser = optparse.OptionParser(__doc__.strip())

    parser.add_option('-v', '--verbose', action='store_true',
                      help="Use verbose output on progress")

    parser.add_option('-O', '--original', action='store_true',
                      help="Use original output format of diff")

    opts, args = parser.parse_args()

    # Validate the arguments.
    if len(args) != 2 or not isdir(args[0]) or not isdir(args[1]):
        parser.error("You must specify two directories.")
    dir1, dir2 = args

    out, err = sys.stdout, sys.stderr

    if opts.original:
        onlyfmt = "Only in %s: %s\n"
        differfmt = "Files %s and %s differ\n"
    else:
        onlyfmt = "only: %s/%s\n"
        differfmt = "differ: %s : %s\n"
        
    dopretty = False
    for root1, dirs1, files1 in os.walk(dir1):
        # Get the second's root and create sets.
        root2 = dir2 + root1[len(dir1):]
        if opts.verbose:
            err.write('\n%s\n%s\n' % (root1, root2))

        # Create sets of the first names
        sdirs1, sfiles1 = set(dirs1), set(files1)

        # Create sets of the second names
        sdirs2, sfiles2 = set(), set()
        for name in os.listdir(root2):
            if isdir(join(root2, name)):
                sdirs2.add(name)
            else:
                sfiles2.add(name)
                
        # Compute differences of directories
        if sdirs1 != sdirs2:
            dopretty = True
            for dn in sdirs1 - sdirs2:
                out.write(onlyfmt % (root1, dn))
            for dn in sdirs2 - sdirs1:
                out.write(onlyfmt % (root2, dn))

            # Make sure we iterate only in the common directories.
            dirs1[:] = list(sdirs1 & sdirs2)
            
        # Compute differences of files
        if sfiles1 != sfiles2:
            dopretty = True
            for dn in sfiles1 - sfiles2:
                out.write(onlyfmt % (root1, dn))
            for dn in sfiles2 - sfiles1:
                out.write(onlyfmt % (root2, dn))

        # For the common files, compare the sizes.
        for fn in sfiles1 & sfiles2:
            fn1, fn2 = [join(r, fn) for r in (root1, root2)]
            try:
                s1 = os.path.getsize(fn1)
            except OSError:
                s1 = -1

            try:
                s2 = os.path.getsize(fn2)
            except OSError:
                s2 = -1

            if s1 != s2:
                dopretty = True
                out.write(differfmt % (fn1, fn2))

        if not opts.original and dopretty:
            out.write('\n')
            dopretty = False

if __name__ == '__main__':
    main()

