-
Notifications
You must be signed in to change notification settings - Fork 0
/
backup.py
125 lines (103 loc) · 4.35 KB
/
backup.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
import os
import pathlib
# Interactive backup-script for copying backup_src to backup_dest.
# Obviously backup_dest must not be anywhere inside backup_src.
# For all files >= MIN_SIZE, the user is prompted [include / exclude / step into]
# All smaller files are copied anyway. The list of files to be excluded will be here:
# /tmp/exclude_dirs.txt. Before the final rsync it will ask you again for confirmation.
# Parameters, use absolute paths
MIN_SIZE = 5000000 # (=5MB)
backup_src = "" # e.g. /home/schmina
backup_dest = "" # e.g. /media/external_harddrive/backup_june20
# ================================================
def print_bytes_human(fileSize):
for count in ['B', 'KB', 'MB', 'GB']:
if fileSize > -1024.0 and fileSize < 1024.0:
return "%3.1f%s" % (fileSize, count)
fileSize /= 1024.0
return "%3.1f%s" % (fileSize, 'TB')
def get_directory_size(directory): # in bytes
total = 0
try:
for entry in os.scandir(directory):
if os.path.islink(directory):
continue
elif entry.is_dir():
total += get_directory_size(entry.path)
elif entry.is_file():
total += entry.stat().st_size
except NotADirectoryError:
return os.path.getsize(directory)
except PermissionError:
return 0
return total
def interactive_loop(curr_dir, excludelist):
def abs_to_rel_path(somePath):
prefix = len(backup_src)+1
return somePath[prefix:]
# get list of files (and their size) in current directory
filelist = [elem.as_posix() for elem in pathlib.Path(curr_dir).glob('./*')]
sorted_filelist = []
for filename in filelist:
if os.path.islink(filename):
continue
elif os.path.isdir(filename):
sorted_filelist.append((filename, get_directory_size(filename)))
else:
sorted_filelist.append((filename, os.path.getsize(filename)))
# Sort entries by size
sorted_filelist.sort(key=lambda x: x[1], reverse=True)
# only need manual approval if file has certain size
sorted_filelist = [x for x in sorted_filelist if x[1] >= MIN_SIZE]
# let user decide
for filename in sorted_filelist:
if os.path.isdir(filename[0]):
while True:
answer = input("{} {} ( /n/r) ".format(filename[0], print_bytes_human(filename[1])))
if answer == "n":
excludelist.write(abs_to_rel_path(filename[0]) + "\n")
break
elif answer == "r":
interactive_loop(filename[0], excludelist)
break
elif answer == "":
break
else:
print("invalid input, try again")
else:
while True:
answer = input("{} {} ( /n) ".format(filename[0], print_bytes_human(filename[1])))
if answer == "n":
excludelist.write(abs_to_rel_path(filename[0]) + "\n")
break
elif answer == "":
break
else:
print("invalid input, try again")
print("backup script\n" + 20*"-")
if (not os.path.exists(backup_src)) or (not os.path.exists(backup_dest)):
raise Exception("Error, source or target directory does not exist")
# remove potential trailing slash
backup_src = backup_src[:-1] if backup_src[-1] == "/" else backup_src
backup_dest = backup_dest[:-1] if backup_dest[-1] == "/" else backup_dest
exclude_file = "/tmp/exclude_dirs.txt"
file = open(exclude_file, "w").close() # clear potential existing content
file = open(exclude_file, "a")
print("usage:\n pressing just enter will include the file in the backup")
print(" character n will exclude a file/dir from the backup")
print(" character r steps into a directory and allows continuation from there")
print(20*"-")
interactive_loop(backup_src, file)
file.close()
print(20*"-")
print("first few lines of the file that contains files/dirs to be excluded:")
os.system("head -n 5 {} | sed 's/^/ /'".format(exclude_file))
print(20*"-")
command = """ sudo rsync -arv --exclude-from='{}' {} {}""".format(
exclude_file, backup_src, backup_dest)
print("command to backup your files:\n", command)
print(20*"-")
if input("run the command now (y/n)? ") == "y":
os.system(command)
else:
print("aborted")