9 сентября 2009 г.

Простой бэкап, Python + DropBox

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

Для начала нужно определиться где хранить копии файлов. По-моему 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. Вызывает архиватор, который создаёт архив с файлами из списка. Параметры архиватора - сохранять полный путь файлов (вместе с диском) и создать архив без сжатия.

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

Я не зря указывал, что скрипт берёт файлы из текущей папки. Благодаря этому делать разные "профили" очень просто - достаточно создать новую папку, создать там файл 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:
import subprocess
import sys
import os.path
import os

__author__="race1"
__date__ ="$09.09.2009 19:55:06$"

if __name__ == "__main__":
    if (len(sys.argv) < 2):
        print("Usage: backup.py ")
        print("E.g.: \"backup.py d:\\dropbox\\my dropbox\\backup.rar\"")
        exit(1)

    ScriptFolder = os.path.dirname(sys.argv[0])
    ArchiverFile = ScriptFolder + "\\winrar.exe"
    RootFoldersFile = "tobackup.lst"
    IgnoreFoldersFile = "ignore.lst"
    ExtraFile = "extra.lst"
    FilelistFile = "list.lst"
    OutputArchive = sys.argv[1]

    # Only mandatory file is RootFoldersFile, check that it exists
    if (not os.path.isfile(RootFoldersFile)):
        print("%s doesn't exist" % RootFoldersFile)
        exit(1)

    # Archiver file also should exist
    if (not os.path.isfile(ArchiverFile)):
        print("%s doesn't exist" % ArchiverFile)
        exit(1)

    # Read root folders from file
    rootFolders = [i.strip() for i in open(RootFoldersFile, "r").readlines()]

    # Read list of folders that need to be igonred (if specified)
    ignoreList = []
    if (os.path.isfile(IgnoreFoldersFile)):
        ignoreList = [i.strip().lower() for i in open(IgnoreFoldersFile, "r").readlines()]

    # Open filelist file for writing list of files
    out = open(FilelistFile, "w")
    filesCount = 0

    for rootFolder in rootFolders:
        for root, dirs, files in os.walk(rootFolder):
            for file in files:
                out.write(root + "\\" + file + "\n")
                filesCount += 1

            for dir in dirs:
                # Skip ignored folders
                if (dir.lower() in ignoreList or ("%s\%s" % (root, dir)).lower() in ignoreList):
                    dirs.remove(dir)

    # Append some files from extra files list
    if (os.path.isfile(ExtraFile)):
        out.writelines(open(ExtraFile, "r").readlines())
        
    out.close()

    print("Added %d file(s)" % (filesCount))

    # Delete old archive if exists
    if (os.path.isfile(OutputArchive)):
        os.unlink(OutputArchive)

    # Call archiver (winrar)
    subprocess.call(ArchiverFile + " a -m0 -ep3 \"" + OutputArchive + "\" @list.lst")

    os.unlink(FilelistFile)

    print("Done")

Комментариев нет:

Отправить комментарий