|
5 | 5 | ##
|
6 | 6 | ## This file provides utility functions to the adjacent python scripts
|
7 | 7 |
|
8 |
| -from filecmp import dircmp |
9 | 8 | from hashlib import sha256
|
10 | 9 | from io import StringIO
|
| 10 | +import filecmp |
11 | 11 | import shutil
|
12 | 12 | import sys
|
13 | 13 | import os
|
@@ -68,48 +68,55 @@ def __exit__(self, exc_type, exc_value, traceback):
|
68 | 68 | def open_for_update(filename):
|
69 | 69 | return UpdateFileWriter(filename)
|
70 | 70 |
|
71 |
| -def walk_recursively_and_update(dcmp): |
72 |
| - #for different Files Copy from right to left |
73 |
| - for name in dcmp.diff_files: |
74 |
| - srcpath = dcmp.right + "/" + name |
75 |
| - destpath = dcmp.left + "/" + name |
76 |
| - print("Updating %s" % (destpath)) |
77 |
| - if os.path.isfile(srcpath): |
78 |
| - shutil.copyfile(srcpath, destpath) |
79 |
| - else : |
80 |
| - raise Exception("path: " + srcpath + "is neither a file or folder") |
81 |
| - |
82 |
| - #copy right only files |
83 |
| - for name in dcmp.right_only: |
84 |
| - srcpath = dcmp.right + "/" + name |
85 |
| - destpath = dcmp.left + "/" + name |
86 |
| - print("Updating %s" % (destpath)) |
87 |
| - if os.path.isfile(srcpath): |
88 |
| - shutil.copyfile(srcpath, destpath) |
89 |
| - elif os.path.isdir(srcpath): |
90 |
| - shutil.copytree(srcpath, destpath) |
91 |
| - else : |
92 |
| - raise Exception("path: " + srcpath + "is neither a file or folder") |
93 |
| - |
94 |
| - #delete left only files |
95 |
| - for name in dcmp.left_only: |
96 |
| - path = dcmp.left + "/" + name |
97 |
| - print("Deleting %s" % (path)) |
98 |
| - if os.path.isfile(path): |
99 |
| - os.remove(path) |
100 |
| - elif os.path.isdir(path): |
101 |
| - shutil.rmtree(path) |
102 |
| - else : |
103 |
| - raise Exception("path: " + path + "is neither a file or folder") |
104 |
| - |
105 |
| - #call recursively |
106 |
| - for sub_dcmp in dcmp.subdirs.values(): |
107 |
| - walk_recursively_and_update(sub_dcmp) |
108 |
| - |
109 |
| -def UpdateDirectory(destpath,srcpath): |
110 |
| - |
111 |
| - print("Updating %s with %s" % (destpath,srcpath)) |
112 |
| - if not os.path.exists(destpath): |
113 |
| - os.makedirs(destpath) |
114 |
| - dcmp = dircmp(destpath,srcpath) |
115 |
| - walk_recursively_and_update(dcmp) |
| 71 | +def split_entries(entries, directory): |
| 72 | + """Given a list of entries in a directory, listing return a set of file and a set of dirs""" |
| 73 | + files = set([entry for entry in entries if os.path.isfile(os.path.join(directory, entry))]) |
| 74 | + dirs = set([entry for entry in entries if os.path.isdir(os.path.join(directory, entry))]) |
| 75 | + |
| 76 | + return files, dirs |
| 77 | + |
| 78 | +def update_directory(srcpath, dstpath, recursive=True, destructive=True, shallow=False): |
| 79 | + """Updates dest directory with files from src directory |
| 80 | +
|
| 81 | + Args: |
| 82 | + destpath (str): The destination path to sync with the source |
| 83 | + srcpath (str): The source path to sync to the destination |
| 84 | + recursive(boolean): If True, descend into and update subdirectories (default: True) |
| 85 | + destructive(boolean): If True, delete files in the destination which do not exist in the source (default: True) |
| 86 | + shallow(boolean): If True, only use os.stat to diff files. Do not examine contents (default: False) |
| 87 | + """ |
| 88 | + srcfiles, srcdirs = split_entries(os.listdir(srcpath), srcpath) |
| 89 | + dstfiles, dstdirs = split_entries(os.listdir(dstpath), dstpath) |
| 90 | + |
| 91 | + |
| 92 | + # Update files in both src and destination which are different in destination |
| 93 | + commonfiles = srcfiles.intersection(dstfiles) |
| 94 | + _, mismatches, errors = filecmp.cmpfiles(srcpath, dstpath, commonfiles, shallow=shallow) |
| 95 | + |
| 96 | + if errors: |
| 97 | + raise RuntimeError("Comparison failed for the following files(s): {}".format(errors)) |
| 98 | + |
| 99 | + for mismatch in mismatches: |
| 100 | + shutil.copyfile(os.path.join(srcpath, mismatch), os.path.join(dstpath, mismatch)) |
| 101 | + |
| 102 | + # Copy over files from source which do not exist in the destination |
| 103 | + for missingfile in srcfiles.difference(dstfiles): |
| 104 | + shutil.copyfile(os.path.join(srcpath, missingfile), os.path.join(dstpath, missingfile)) |
| 105 | + |
| 106 | + #If destructive, delete files in destination which do not exist in sourc |
| 107 | + if destructive: |
| 108 | + for deadfile in dstfiles.difference(srcfiles): |
| 109 | + print(deadfile) |
| 110 | + os.remove(os.path.join(dstpath, deadfile)) |
| 111 | + |
| 112 | + for deaddir in dstdirs.difference(srcdirs): |
| 113 | + print(deaddir) |
| 114 | + shutil.rmtree(os.path.join(dstpath, deaddir)) |
| 115 | + |
| 116 | + #If recursive, do this again for each source directory |
| 117 | + if recursive: |
| 118 | + for dirname in srcdirs: |
| 119 | + dstdir, srcdir = os.path.join(dstpath, dirname), os.path.join(srcpath, dirname) |
| 120 | + if not os.path.exists(dstdir): |
| 121 | + os.makedirs(dstdir) |
| 122 | + update_directory(srcdir, dstdir, recursive, destructive, shallow) |
0 commit comments