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

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

    Я не зря указывал, что скрипт берёт файлы из текущей папки. Благодаря этому делать разные «профили» очень просто — достаточно создать новую папку, создать там файл 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. Новая версия тут.
    Поделиться публикацией

    Комментарии 8

      +2
      Меня тут явно не хватает.
        0
        Поместил, спасибо :)
        0
        Добавил в избранное=)

        Буду признателен, если сделаете подсветку синтаксиса. К примеру, здесь.
          0
          Ммм… Этот расцветильщик сделал неправильную расцветку :(
          0
          А почему всё не на питоне? Там же есть в стандартной библиотеке модули для работы с архивами. Тогда и копировать в папочку дропбокса можно было бы тоже питоном и получился бы более самостоятельный скрипт=) ну а запуск по расписанию через Windows Sheduler или cron =)
            0
            Ага, тоже так думал… Но внешний архиватор по-проще будет :) Ты ему список файлов, он тебе архив. Можно взять какой-нибудь бесплатный, немного поменяв ключи в скрипте.
              0
              Вы всё-таки почитайте про gzip или zipfile — они весьма простые в использовании… да и малоли где еще в будущем пригодятся =)

              PS: тоже в последнее время всё задумывался как-бы мне делать резервные копии попроще. с подачи статьи теперь тоже попробую такой способ =)
                0
                Хорошо, в следующий раз заскучаю — научу скрипт архивировать :)

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое