1c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien#!/usr/bin/env python
2c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
3c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chienimport os
4c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chienimport shutil
5c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chienimport sys
6c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
7c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan ChienBUFFER_SIZE = 1024
8c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
9c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chiendef is_file_different(a, b):
10c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if os.path.getsize(a) != os.path.getsize(b):
11c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        # If the file size is different, the content must be different.
12c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        return True
13c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
14c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    # Read the content of the files, and compare them.
152010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    result = False
162010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao
172010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    fa = open(a, 'rb')
182010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    fb = open(b, 'rb')
192010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao
202010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    while True:
212010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        buff_a = fa.read(BUFFER_SIZE)
222010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        buff_b = fb.read(BUFFER_SIZE)
232010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao
242010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        if buff_a != buff_b:
252010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            # File is different in this block.
262010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            result = True
272010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            break
28c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
292010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        if len(buff_a) < BUFFER_SIZE:
302010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            # Finished
312010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            break
32c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
332010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    fa.close()
342010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    fb.close()
35c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
36c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    # File is the same.
372010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao    return result
38c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
39c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chiendef copyfile(src, dest):
40c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if not os.path.exists(src):
41c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        raise ValueError('Source file not found')
42c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
43c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    # Make parent directory (if necessary)
44c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    destdir = os.path.dirname(dest)
45c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if not os.path.exists(destdir):
46c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        try:
47c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien            os.makedirs(destdir)
4812c27e38e875ae53f47e4a1b1c00a601457c20f2Shih-wei Liao        except os.error, e:
49c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien            raise ValueError('Unable to create directory ' + destdir)
50c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    elif not os.path.isdir(destdir):
51c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        raise ValueError(destdir + ' is not a directory')
52c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
53c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if not os.path.exists(dest) or is_file_different(src, dest):
54c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        # If the destination file does not exist or the source file is
55c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        # different from the destination file, then we copy the file.
56c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        shutil.copyfile(src, dest)
57c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
58c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chiendef main():
59c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if len(sys.argv) < 3:
602010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        print >> sys.stderr, 'USAGE:', sys.argv[0], '<srcfile> <destfile>'
61c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        sys.exit(1)
62c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
63c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    srcfile = os.path.abspath(sys.argv[1])
64c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    destfile = os.path.abspath(sys.argv[2])
65c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
66c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    if srcfile == destfile:
672010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao        print >> sys.stderr, 'WARNING: <srcfile> is equal to <destfile>'
68c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    else:
69c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien        try:
70c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien            copyfile(srcfile, destfile)
7112c27e38e875ae53f47e4a1b1c00a601457c20f2Shih-wei Liao        except ValueError, e:
722010bbd9e389c9745a03a21d1cfa87acacda6abbShih-wei Liao            print >> sys.stderr, 'ERROR: ', e
73c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien            sys.exit(1)
74c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien
75c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chienif __name__ == '__main__':
76c0a87ab7907e88efa4a5d7cba27e876f0dab1f5bLogan Chien    main()
77