-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsloppycopy.py
99 lines (78 loc) · 3.44 KB
/
sloppycopy.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
# sloppycopy - cats <3
import os, zlib, shutil, sys, time
# stat variable & func
total_changes = 0
# function to check files using crc32
def crc32(path):
checksum = 0
with open(path, "rb") as file:
for chunk in iter(lambda: file.read(4069), b""):
checksum = zlib.crc32(chunk, checksum)
return checksum
# function to get total bytes of folder
def folder_size(path):
return sum(
os.path.getsize(os.path.join(root, file))
for root, _, files in os.walk(path)
for file in files
)
# function to skip based on bytes
def should_skip(source, target):
return os.path.exists(target) and folder_size(source) == folder_size(target)
# function to copy files
def copy(source_dir, target_dir):
# this will save you from having your target folder get NUKED! <3
if not os.path.exists(source_dir) or not os.path.exists(target_dir):
print("Source or Target directory does not exist.")
sys.exit()
start_time = time.time()
global total_changes
print("Adding & updating files & folders:")
for root, _, files in os.walk(source_dir):
target_root = os.path.join(target_dir, os.path.relpath(root, source_dir))
if should_skip(root, target_root):
print(f"Skipping directory: {root}")
continue
if not os.path.exists(target_root):
os.makedirs(target_root)
print(f"Added folder: {target_root}")
total_changes += 1
for file_name in files:
source_file = os.path.join(root, file_name)
target_file = os.path.join(target_root, file_name)
if os.path.exists(target_file):
if crc32(source_file) != crc32(target_file):
shutil.copy2(source_file, target_file)
print(f"Updated file: {source_file} -> {target_file}")
total_changes += 1
else:
shutil.copy2(source_file, target_file)
print(f"Added file: {source_file} -> {target_file}")
total_changes += 1
print("Removing files & folders:")
for root, directories, files in os.walk(target_dir):
source_root = os.path.join(source_dir, os.path.relpath(root, target_dir))
for file_name in files:
if not os.path.exists(os.path.join(source_root, file_name)):
os.remove(os.path.join(root, file_name))
print(f"Removed file: {os.path.join(root, file_name)}")
total_changes += 1
for dir_name in directories:
if not os.path.exists(os.path.join(source_root, dir_name)):
shutil.rmtree(os.path.join(root, dir_name))
print(f"Removed folder: {os.path.join(root, dir_name)}")
total_changes += 1
end_time = time.time()
print(f"Copying done | total changes: {total_changes} | time taken: {end_time - start_time}")
# simple cli
if __name__ == "__main__":
import argparse
# argparse support
parser = argparse.ArgumentParser(description="SloppyCopy - A simple file synchronization tool.")
parser.add_argument("source", nargs="?", help="Source directory path")
parser.add_argument("target", nargs="?", help="Target directory path")
args = parser.parse_args()
# use args or input
source_dir = args.source or input("Source directory path: ")
target_dir = args.target or input("Target directory path: ")
copy(source_dir, target_dir)