-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptimized.py
163 lines (142 loc) · 6.76 KB
/
optimized.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import concurrent
import datetime
import filecmp
import shutil
import sys
import os
import sched
import time
import pathlib
import stat
import concurrent.futures
def context_cracking():
if sys.platform != 'win32':
print('WARNING - This script was designed and tested only on Windows')
if sys.version_info.major != 3 and sys.version_info.minor != 12:
print('WARNING - This script was designed and tested only on Python 3.12')
def command_line_parsing_safety():
if len(sys.argv) != 5:
sys.exit('ERROR - NUMBER OF ARGUMENTS INCORRECT')
if not os.path.isdir(sys.argv[1]) and not os.path.isabs(sys.argv[1]):
sys.exit('ERROR - SOURCE PATH NOT UP TO REQS')
if not os.path.isdir(sys.argv[2]) and not os.path.isabs(sys.argv[2]):
sys.exit('ERROR - REPLICA PATH NOT UP TO REQS')
try:
int(sys.argv[3]) # This is limited by 4300 digits the default.
except ValueError as e:
print(e)
sys.exit('ERROR - INTERVAL DEFINITION NOT UP TO REQS')
if not os.path.isfile(sys.argv[4]) and not os.path.isabs(sys.argv[4]):
sys.exit('ERROR - LOG FILE PATH NOT UP TO REQS')
try:
open(sys.argv[4], 'a') # Check if file is possible to open in write mode.
except PermissionError:
sys.exit('ERROR - YOU DO NOT HAVE PERMISSION TO WRITE TO LOG FILE')
def logs_manager(s):
# maybe delete last file if write to log failed? to avoid missmatch?
print(s) # log to stdout
try:
with open(sys.argv[4], 'a') as f:
f.write(str(s + '\n')) # log to log file
except PermissionError:
sys.exit('ERROR - PERMISSION ERROR OCCURRED ON LOG FILE')
def directory_comparison_object_exists_on_source_only(dir_cmp):
try:
for name in dir_cmp.left_only:
path_source = os.path.join(sys.argv[1], dir_cmp.left, name)
path_replica = os.path.join(sys.argv[2], dir_cmp.right, name)
if os.path.isdir(path_source):
try:
os.chmod(path_source, stat.S_IWRITE)
shutil.copytree(path_source, path_replica)
logLine = "{} INFO - COPIED DIR {} FROM {} TO {}".format(datetime.datetime.now(), name, path_source,
path_replica)
logs_manager(logLine)
except shutil.Error:
# pass
print('WARNING - COPY FN RETURNED A ERROR WILL RETRY NEXT SYNC') # file is in use most likely
else:
try:
os.chmod(path_source, stat.S_IWRITE) # Platform dependant.
shutil.copy2(path_source, path_replica)
logLine = "{} INFO - COPIED FILE {} FROM {} TO {}".format(datetime.datetime.now(), name, path_source,
path_replica)
logs_manager(logLine)
except PermissionError as e:
# pass
print('WARNING - {}'.format(e))
for sub in dir_cmp.subdirs.values():
directory_comparison_object_exists_on_source_only(sub)
except FileNotFoundError as e:
# pass
print('WARNING - {}'.format(e))
def redo_with_write(redo_func, path, err): # Fixes error with readonly directories.
os.chmod(path, stat.S_IWRITE) # this is platform dependant. (https://docs.python.org/3/library/os.html#os.chmod)
redo_func(path)
def directory_comparison_object_exists_on_replica_only(dir_cmp):
try:
for name in dir_cmp.right_only:
path_replica = os.path.join(sys.argv[2], dir_cmp.right, name)
if os.path.isdir(path_replica):
shutil.rmtree(path_replica, onerror=redo_with_write)
logLine = "{} INFO - DELETED DIR {} FROM {}".format(datetime.datetime.now(), name, path_replica)
else:
if not os.access(path_replica, os.W_OK):
os.chmod(path_replica, stat.S_IWRITE) # Handles if file is readonly.
pathlib.Path(path_replica).unlink()
logLine = "{} INFO - DELETED FILE {} FROM {}".format(datetime.datetime.now(), name, path_replica)
logs_manager(logLine)
for sub in dir_cmp.subdirs.values():
directory_comparison_object_exists_on_replica_only(sub)
except FileNotFoundError as e:
# pass
print('WARNING - {}'.format(e))
except PermissionError as e:
# pass
print('WARNING - {}'.format(e))
def file_comparison(path_source, path_replica, name):
try:
if filecmp.cmp(path_source, path_replica): # Shallow comparison.
return True
else:
if not filecmp.cmp(path_source, path_replica, shallow=False):
shutil.copy2(path_source, path_replica)
logLine = "{} INFO - UPDATED EXISTENT FILE {} FROM {} TO {}".format(datetime.datetime.now(), name,
path_source, path_replica)
logs_manager(logLine)
except FileNotFoundError as e:
# pass
print('WARNING - {}'.format(e)) # todo This could be better maybe say what happens.
def directory_comparison_object_exists_on_both(dir_cmp):
with concurrent.futures.ThreadPoolExecutor() as executor:
try:
for name in dir_cmp.common_files:
path_source = os.path.join(sys.argv[1], dir_cmp.left, name)
path_replica = os.path.join(sys.argv[2], dir_cmp.right, name)
executor.submit(file_comparison, path_source, path_replica, name)
for sub in dir_cmp.subdirs.values():
directory_comparison_object_exists_on_both(sub)
except FileNotFoundError as e:
# pass
print('WARNING - {}'.format(e))
def job():
log_line = "{} INFO - NEW SYNCHRONIZATION".format(datetime.datetime.now())
logs_manager(log_line)
filecmp.clear_cache()
fc = filecmp.dircmp(sys.argv[1], sys.argv[2])
directory_comparison_object_exists_on_replica_only(fc) # Delete files unique on replica.
fc = filecmp.dircmp(sys.argv[1], sys.argv[2])
directory_comparison_object_exists_on_source_only(fc) # Add files unique on source to replica.
fc = filecmp.dircmp(sys.argv[1], sys.argv[2])
directory_comparison_object_exists_on_both(fc) # Updates files that are similar but with different contents.
scheduler.enter(int(sys.argv[3]), 1, job, ())
if __name__ == '__main__':
print("INFO - STARTING TASK")
context_cracking()
command_line_parsing_safety()
scheduler = sched.scheduler(time.time, time.sleep)
scheduler.enter(2, 1, job, ())
try:
scheduler.run() # Infinite loop.
except KeyboardInterrupt:
sys.exit(0)