Как стать автором
Обновить

Простой самодельный бэкап данных (Python + DropBox)

Время на прочтение 6 мин
Количество просмотров 9.9K
Бэкапы я не делал давно. Было лень, да и данные я не терял уже несколько лет. Но недавно задумался об этом и решил-таки сделать что-то такое, что резервно сохраняло бы то, что не очень хочется потерять. Просто что бы скучно не было, и немного попрактиковаться.

Для начала нужно определиться где хранить копии файлов. По-моему DropBox это очень хороший выбор — это сервис для синхронизации данных на разных компьютерах. Бесплатно дают 2 Гб, плюс программу, которая отображает выбранную локальную папку на ихнее онлайн хранилище. Добавил файл в эту специальную папку — он добавился на всех компьютерх, на которых стоит специальная программа, настроенная на тот же аккаунт. Плюс доступ через веб-интерфейс. Для бэкапа это очень удобно — не надо заморчиваться как скопировать файлы на FTP, а просто копируем их в специальную папку. Всё работу по заливке/синхронизации сделает DropBox клиент.

Дальше нужно собственно скопировать необходимые файлы. Для этого был написан крохотульный скрипт на питоне, backup.py. Этот скрипт создаёт текстовый список файлов, которые нужно скопировать, и передаёт его WinRar'у, который создаёт архив с указанным именем.

Сначала я хотел полностью поручить WinRar'у создание бэкапа, написав немного кода в батниках, но к сожалению он не умеет пропускать заданные папки (только файлы). Поэтому пришлось писать промежуточный скрипт, который создаёт список файлов. Ну и хорошо, так даже веселее.

У скрипта есть единственный параметр — имя выходного файла-архива со скопированными файлами.

Алгоритм работы скрипта:
  1. Читает из текущей папки файл tobackup.lst — там хранится список папок, которые нужно скопировать. Каждая строка — отдельная папка. Например:
    d:\projects
    d:\www
  2. Читает список папок, которые нужно исключить из бэкапа. Это опциональный файл igonre.lst в текущей папке. Это либо полный путь (d:\projects\old), либо просто имя папки (.svn). Например:
    .svn
    d:\projects\old
  3. Создаёт текстовый список файлов для копирования list.lst (в текущей папке). После этого добавляет в конец файла-списка опциональный файл extra.lst (из текущей папки). Там содержится список файлов, а не папок, для включения. Например, мы хотим сохранить настройки php, но из всей папки d:\programs\php нам нужен только один файл php.ini. Поэтому вместо добавления папки с php мы добавляем только один файл php.ini в extra.lst.
  4. Вызывает архиватор, который создаёт архив с файлами из списка. Параметры архиватора — сохранять полный путь файлов (вместе с диском) и создать архив без сжатия.

В итоге, после работы скрипта мы будем иметь архив с указанными папками.

Я не зря указывал, что скрипт берёт файлы из текущей папки. Благодаря этому делать разные «профили» очень просто — достаточно создать новую папку, создать там файл tobackup.lst, опциональные ignore.lst и extra.lst, и новый профиль готов! Для удобства можно сделать батник, который будет вызывать backup.py и передавать ему имя файла-архива который должен получиться.

Сейчас, например, у меня есть две папки-профиля, projects (для бэкапа текущих проектов) и other (для бэкапа настроек программ). Сам скрипт лежит в папке core (на том же уровне что и папки профилей), вместе с WinRar'ом.

Папка core:
Rar.exe
WinRAR.exe
rarreg.key
backup.py

Папка projects:
tobackup.lst:
d:\projects
d:\svn

ignore.lst:
.svn
d:\projects\old

backup.bat:
..\core\backup.py «d:\dropbox\my dropbox\backup\dev.rar»

Батник backup.bat вызывает скрипт, передеаёт ему имя получающегося файла-архива, который будет создан в папке, связанной с DropBox. Скрипт берёт файлы-списки из текущей папки (projects в данном случае). Один запуск батника — новый бэкап готов, и DropBox грузит его на сервер.

Осталось прикрутить запуск по расписанию, но меня устроит и ручной запуск несколько раз в месяц.

backup.py:
Copy Source | Copy HTML
  1. import subprocess
  2. import sys
  3. import os.path
  4. import os
  5.  
  6. if __name__ == "__main__":
  7.     if (len(sys.argv) < 2):
  8.         print("Usage: backup.py <output archive file>")
  9.         print("E.g.: \"backup.py d:\\dropbox\\my dropbox\\backup.rar\"")
  10.         exit(1)
  11.  
  12.     scriptFolder = os.path.dirname(sys.argv[ 0])
  13.     ArchiverFile = scriptFolder + "\\winrar.exe"
  14.     RootFoldersFile = "tobackup.lst"
  15.     IgnoreFoldersFile = "ignore.lst"
  16.     ExtraFile = "extra.lst"
  17.     FilelistFile = "list.lst"
  18.     OutputArchive = sys.argv[1]
  19.  
  20.     # Only mandatory file is RootFoldersFile, check that it exists
  21.     if (not os.path.isfile(RootFoldersFile)):
  22.         print("%s doesn't exist" % RootFoldersFile)
  23.         exit(1)
  24.  
  25.     # Archiver file also should exist
  26.     if (not os.path.isfile(ArchiverFile)):
  27.         print("%s doesn't exist" % ArchiverFile)
  28.         exit(1)
  29.  
  30.     # Read root folders from file
  31.     rootFolders = [i.strip() for i in open(RootFoldersFile, "r").readlines()]
  32.  
  33.     # Read list of folders that need to be igonred (if specified)
  34.     ignoreList = []
  35.     if (os.path.isfile(IgnoreFoldersFile)):
  36.         ignoreList = [i.strip().lower() for i in open(IgnoreFoldersFile, "r").readlines()]
  37.  
  38.     # Open filelist file for writing list of files
  39.     out = open(FilelistFile, "w")
  40.     filesCount =  0
  41.  
  42.     for rootFolder in rootFolders:
  43.         for root, dirs, files in os.walk(rootFolder):
  44.             for file in files:
  45.                 out.write(root + "\\" + file + "\n")<br/>                filesCount += 1<br/><br/>            for dir in dirs:<br/>                # Skip ignored folders<br/>                if (dir.lower() in ignoreList or ("%s\%s" % (root, dir)).lower() in ignoreList):<br/>                    dirs.remove(dir)<br/><br/>    # Append some files from extra files list<br/>    if (os.path.isfile(ExtraFile)):<br/>        out.writelines(open(ExtraFile, "r").readlines())<br/>        <br/>    out.close()<br/><br/>    print("Added %d file(s)" % (filesCount))<br/><br/>    # Delete old archive if exists<br/>    if (os.path.isfile(OutputArchive)):<br/>        os.unlink(OutputArchive)<br/><br/>    # Call archiver (winrar)<br/>    subprocess.call(ArchiverFile + " a -m0 -ep3 \"" + OutputArchive + "\" @list.lst")
  46.  
  47.     os.unlink(FilelistFile)
  48.  
  49.     print("Done")


UPD. Новая версия тут.
Теги:
Хабы:
+7
Комментарии 8
Комментарии Комментарии 8

Публикации

Истории

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн