-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnpk-backup.py
178 lines (141 loc) · 6.07 KB
/
npk-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
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python3
# encoding: utf-8
"""
Um pequeno utilitário para automatizar a cópia de segurança de uma determinada
pasta (por exemplo, cópias de segurança locais de uma base de dados Filemaker,
uma coleção de scripts e aplicações do Pythonista, etc.), criando arquivos
*zip* individuais a partir de cada pasta principal na localização especificada
e fazendo *upload* dos mesmos para a Dropbox. O programa mantém um registo
simples, por forma a não repetir as tarefas de compressão e upload já
realizadas. Em cada execução, são efetuadas cópias individuais de cada pasta
nova, que ainda não conste nas cópias anteriores. Não são contudo copiadas
pastas nem ficheiros previamente copiados, que possam ter sido alterados
entretanto.
© 2017 Victor Domingos (http://victordomingos.com)
Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
"""
import shutil
import datetime
import os
import os.path
import pickle
import logging
import logging.handlers
from pprint import pformat
import dropbox
from app_settings_Mac import INPUT_FOLDER, ARCHIVE_PATH
from app_settings_Mac import REMOTE_PATH, BACKUP_LOG_FILE, TOKEN, LOGS_PATH
logger = logging.getLogger()
def setup_logging():
log_path = os.path.expanduser(LOGS_PATH)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
# Write log messages to a file
file = logging.FileHandler(log_path)
file.setLevel(logging.DEBUG)
file.setFormatter(formatter)
logger.addHandler(file)
# Show log messages also on screen
screen = logging.StreamHandler()
screen.setLevel(logging.DEBUG)
screen.setFormatter(formatter)
logger.addHandler(screen)
def obter_lista_de_pastas(register_file_path):
""" Obtém do ficheiro de registo a lista das pastas já copiadas e compara
essa lista com as pastas existentes no computador local. A função
devolve a lista das pastas a arquivar e copiar.
"""
logger.debug('A obter lista de pastas existentes no armazenamento local...')
# Lista todas as subpastas na pasta principal (aqui designada como "raiz")
raiz = os.path.expanduser(INPUT_FOLDER)
pastas_locais = ["{}{}".format(raiz, pasta)
for pasta in next(os.walk(raiz))[1]]
# Obter do ficheiro a lista das pastas já tratadas e gerar lista sem essas
logger.debug('A obter lista de pastas ja arquivadas...')
try:
with open(register_file_path, 'rb') as f:
pastas_arquivadas = pickle.load(f)
except Exception as e:
pastas_arquivadas = []
logger.debug('>>> Ocorreu um erro durante a leitura do registo:')
logger.debug(str(e))
lista_final = [pasta for pasta in pastas_locais
if pasta not in pastas_arquivadas]
return lista_final
def adiciona_registo(register_file_path, path):
""" Adiciona o caminho especificado ao ficheiro de registo. """
logger.debug("Adicionando registo...")
try:
with open(register_file_path, 'rb') as f:
pastas = pickle.load(f)
except Exception as e:
pastas = []
logger.debug('>>> Ocorreu um erro durante a leitura do registo:')
logger.debug(str(e))
pastas.append(path)
logger.debug(pformat(pastas))
try:
with open(register_file_path, 'wb') as f:
pickle.dump(pastas, f)
except Exception as e:
logger.debug('>>> Ocorreu um erro durante a atualização do ficheiro de registo:')
logger.debug(str(e))
def comprimir_pasta(origem, destino):
""" Comprime a pasta de origem para o destino especificado. """
try:
logger.debug("A comprimir a copia local...")
arq = shutil.make_archive(destino, 'zip', root_dir=origem)
return arq
except Exception as e:
logger.debug('>>> Ocorreu um erro durante a compressao:')
logger.debug(str(e))
return None
def upload_dropbox(archive, dropbox_path, token):
""" Faz upload do ficheiro especificado para a Dropbox. """
try:
logger.debug("A fazer upload para a Dropbox...")
logger.debug(str(dropbox_path))
dbx = dropbox.Dropbox(token)
with open(archive, 'rb') as f:
dbx.files_upload(f.read(), dropbox_path)
return True
except Exception as e:
logger.debug('>>> Ocorreu um erro durante o upload para a Dropbox:')
logger.debug(str(e))
return None
def apagar_arquivo(archive):
""" Apaga o ficheiro especificado no sistema de ficheiros local. """
try:
logger.debug("A apagar o ficheiro temporario local...")
os.remove(archive)
except Exception as e:
logger.debug('>>> Ocorreu um erro ao apagar o arquivo zip:')
logger.debug(str(e))
def main():
backup_log_path = os.path.expanduser(BACKUP_LOG_FILE)
dropbox_token = TOKEN
setup_logging()
lista_pastas_novas = obter_lista_de_pastas(backup_log_path)
if lista_pastas_novas == []:
logger.debug("Não ha pastas novas! A terminar a operacao.\n")
return
logger.debug("A iniciar procedimento de arquivo...\n======================")
for path in lista_pastas_novas:
logger.debug("--------- Pasta atual: ---------")
logger.debug(path)
timestamp = str(datetime.datetime.now())
input_path = os.path.expanduser(path)
hoje = datetime.datetime.now()
ano, mes, dia = hoje.year, hoje.month, hoje.day
archive_file_name = os.path.basename(os.path.normpath(os.path.expanduser(path)))
archive_path = os.path.expanduser(ARCHIVE_PATH + archive_file_name + "____" + timestamp)
dropbox_archive_path = "{}/{}/{}/{}/{}.zip".format(REMOTE_PATH,
ano, mes, dia,
archive_file_name + "____" + timestamp)
arquivo = comprimir_pasta(input_path, archive_path)
if arquivo:
if upload_dropbox(arquivo, dropbox_archive_path, dropbox_token):
adiciona_registo(backup_log_path, path)
apagar_arquivo(arquivo)
if __name__ == "__main__":
main()