-
Notifications
You must be signed in to change notification settings - Fork 98
/
rsync.py
135 lines (114 loc) · 4.54 KB
/
rsync.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Rsync in Python: argument from_folder is assumed to be the master,
# its contents are reflected in to_folder. If --delete flag is used
# extra files under to_folder will be deleted after copy sync, so
# from_folder will be reflected *exactly* under to_folder. For file
# equality test file size is used, if same file name with same file
# size exists under to_folder, it will not be copied again.
# python rsync.py c:\some\source\folder c:\some\destination\folder
import sys, glob, os, shutil, re, argparse
def deleteDir(path):
"""deletes the path entirely"""
mswindows = (sys.platform == "win32")
if mswindows:
cmd = "RMDIR "+ path +" /s /q"
else:
cmd = "rm -rf "+path
result = getstatusoutput(cmd)
if(result[0]!=0):
raise RuntimeError(result[1])
def deleteFile(path):
"""deletes the path entirely"""
print (path)
mswindows = (sys.platform == "win32")
if mswindows:
cmd = 'DEL /F /S /Q "%s"' % path
else:
cmd = 'rm -rf "' + path + '"'
result = getstatusoutput(cmd)
if(result[0]!=0):
raise RuntimeError(result[1])
def getstatusoutput(cmd):
"""Return (status, output) of executing cmd in a shell."""
pipe = os.popen(cmd + ' 2>&1', 'r')
text = pipe.read()
sts = pipe.close()
if sts is None: sts = 0
if text[-1:] == '\n': text = text[:-1]
return sts, text
def ls(d,ignore_list=[]):
print ('ls ignore lst', ignore_list)
dirs = []; files = []
for root, directories, filenames in os.walk(d):
for directory in directories:
path = os.path.join(root, directory)
do_add = True
for ignore in ignore_list:
if ignore in path:
print ('ignoring', path); do_add = False
if do_add: dirs.append(path)
for filename in filenames:
path = os.path.join(root,filename)
do_add = True
for ignore in ignore_list:
if ignore in path: do_add = False
if do_add: files.append((path, os.path.getsize(path)))
return dirs, files
def purge(dir, pattern, inclusive=True):
regexObj = re.compile(pattern)
for root, dirs, files in os.walk(dir, topdown=False):
for name in files:
path = os.path.join(root, name)
if bool(regexObj.search(path)) == bool(inclusive):
os.remove(path)
def copy_files_and_dirs(fr,to,ignore_list):
if ignore_list == None:
ignore_list = []
else:
ignore_list = ignore_list.split(',')
frdirs,frfiles = ls(fr,ignore_list)
todirs,tofiles = ls(to)
tofilesdict = dict(tofiles)
print ('create dirs')
todirs_tmp = dict([(x.replace(fr,to),0) for x in todirs])
diff = [x for x in frdirs if x.replace(fr,to) not in todirs_tmp]
for x in diff:
x=x.replace(fr,to)
if os.path.exists(x) == False:
os.mkdir(x)
print ('a files not in b')
for (x,size) in frfiles:
x_to=x.replace(fr,to)
if x_to in tofilesdict and tofilesdict[x_to] != size:
print ('copying %s %s' % (x,x_to))
shutil.copy(x,x_to)
elif x_to not in tofilesdict:
print ('copying %s %s' % (x,x_to))
shutil.copy(x,x_to)
return frdirs, todirs
def del_not_in_from(fr, to, frdirs, todirs):
print ('b files not in a')
frdirs_tmp = dict([(x.replace(to,fr),0) for x in frdirs])
diff = [x for x in todirs if x.replace(to,fr) not in frdirs_tmp]
for x in diff:
print ('deleting directory %s' % x)
if os.path.isdir(x): deleteDir("'%s'" % x)
frdirs,frfiles = ls(fr)
todirs,tofiles = ls(to)
frfilesdict = dict(frfiles)
for (x,size) in tofiles:
x_fr=x.replace(to,fr)
if x_fr not in frfilesdict:
print ('deleting %s' % x)
deleteFile(x)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='rsync')
parser.add_argument('fr', type=str, help='xx.')
parser.add_argument('to', type=str, help='xx.')
parser.add_argument('--delete', type=bool, nargs="?", help='delete the target subdir if it does not exist in source.')
parser.add_argument('--ignore-list', type=str, nargs="?", help='do not copy this pattern, comma seperated list')
args = parser.parse_args()
print (args.fr)
print (args.to)
is_delete = args.delete
frdirs, todirs = copy_files_and_dirs(args.fr, args.to, args.ignore_list)
if is_delete: del_not_in_from(args.fr, args.to, frdirs, todirs)