diff --git a/.gitignore b/.gitignore
index dfe6f0e..fd73820 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
*.txt
-build/
+dist/
tests/helpers/*
src/backups/
src/clean
-plan.sh
+NOTE.todo
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..5b4f13c
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,8 @@
+CHANGELOG
+
+ All notable changes to this project will be documented in this file.
+ Version numbering uses Semantic Versioning 2.0.0
+
+0.1.0
+
+ Initial release.
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index ea50feb..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-Version numbering uses [Semantic Versioning 2.0.0](https://semver.org/).
-
-# 0.1.0
-
-Initial release.
diff --git a/Makefile b/Makefile
index af2a8e3..89a1867 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,28 @@
-SRC_DIR := ./src
-DOCS_DIR := ./docs
-TESTS_DIR := ./tests
-BUILD_DIR := ./build
-DOCS_BUILD_DIR := ./build/docs
+SRC_DIR := ./src
+DOCS_DIR := ./docs
+TESTS_DIR := ./tests
+BUILD_DIR := ./dist
-.PHONY: help tests docs man install uninstall
+.PHONY: help tests manpages install uninstall fixpath
-all: man
+all: manpages
help:
- @echo Usage: make TARGET
+ @echo 'Usage: make TARGET'
+ @echo ' make prefix=/path install'
+ @echo ' make prefix=/path uninstall'
@echo
@echo Available targets:
@echo
- @echo 'help print this help message'
- @echo 'tests run tests from $(TESTS_DIR)'
- @echo 'lint run shellcheck'
- @echo 'man build manual pages from $(DOCS_DIR)'
+ @echo ' help print this help message'
+ @echo ' tests run tests from $(TESTS_DIR)'
+ @echo ' lint run shellcheck'
+ @echo ' manpages build manual pages from $(DOCS_DIR)'
+ @echo ' install install boring-backup with prefix'
+ @echo ' uninstall uninstall boring-backup with prefix'
@echo
- @echo See README.md for more info.
+ @echo 'prefix examples: $$HOME/.local, /usr/local, /usr/bin'
+ @echo See README for more info.
tests:
# See bats(1), https://bats-core.readthedocs.io/en/latest/index.html
@@ -32,24 +36,63 @@ lint:
shellcheck $(SRC_DIR)/lib/handlers/sources/*.sh
shellcheck $(SRC_DIR)/lib/handlers/targets/*.sh
-man: build_dir
- # See rst2man(1), rst2html(1),
+manpages:
+ mkdir -pv $(BUILD_DIR)/share/man/ru/man1
+ # See rst2man(1)
# https://docutils.sourceforge.io/docs/index.html
- rst2man $(DOCS_DIR)/boring-backup.ru.1.rst \
- > $(DOCS_BUILD_DIR)/boring-backup.ru.1
+ rst2man -v $(DOCS_DIR)/manpages/boring-backup.ru.1.rst \
+ > $(BUILD_DIR)/share/man/ru/man1/boring-backup.1
sed -e 's/.SH NAME/.SH ИМЯ/' \
-e 's/.SH AUTHOR/.SH АВТОРЫ/' \
-e 's/.SH COPYRIGHT/.SH АВТОРСКИЕ ПРАВА/' \
- -i $(DOCS_BUILD_DIR)/boring-backup.ru.1
- gzip -9 $(DOCS_BUILD_DIR)/boring-backup.ru.1
+ -i $(BUILD_DIR)/share/man/ru/man1/boring-backup.1
+ gzip -vf9 $(BUILD_DIR)/share/man/ru/man1/boring-backup.1
-build_dir:
- mkdir -p $(BUILD_DIR)
- mkdir -p $(DOCS_BUILD_DIR)
+html: manpages
+ mkdir -p $(BUILD_DIR)/share/doc/boring-backup
+ zcat $(BUILD_DIR)/share/man/ru/man1/boring-backup.1.gz | \
+ groff -man -Kutf8 -Thtml \
+ > $(BUILD_DIR)/share/doc/boring-backup/boring-backup.1.html 2>/dev/null
+ rm -v grohtml-*.png
-install:
- # install
+install: manpages
+ @echo prefix: $$prefix
+ install -Dm755 $(SRC_DIR)/boring-backup $$prefix/bin/boring-backup
+ install -Dm644 $(SRC_DIR)/lib/lib.sh $$prefix/share/boring-backup/lib.sh
+ install -Dm644 $(SRC_DIR)/lib/backup.sh $$prefix/share/boring-backup/backup.sh
+ install -Dm644 $(SRC_DIR)/lib/common.sh $$prefix/share/boring-backup/common.sh
+ install -Dm644 $(SRC_DIR)/lib/source.sh $$prefix/share/boring-backup/source.sh
+ install -Dm644 $(SRC_DIR)/lib/uri.sh $$prefix/share/boring-backup/uri.sh
+ install -Dm644 $(SRC_DIR)/lib/handlers/sources/tar.sh $$prefix/share/boring-backup/handlers/sources/tar.sh
+ install -Dm644 $(SRC_DIR)/lib/handlers/sources/mysqldump.sh $$prefix/share/boring-backup/handlers/sources/mysqldump.sh
+ install -Dm644 $(SRC_DIR)/lib/handlers/sources/pg_dump.sh $$prefix/share/boring-backup/handlers/sources/pg_dump.sh
+ install -Dm644 $(SRC_DIR)/lib/handlers/targets/cp.sh $$prefix/share/boring-backup/handlers/targets/cp.sh
+ install -Dm644 $(SRC_DIR)/lib/handlers/targets/s3cmd.sh $$prefix/share/boring-backup/handlers/targets/s3cmd.sh
+ sed -e "s%LIBRARY=\"\$${LIBRARY:-.\/lib}\"%LIBRARY=\"\$${LIBRARY:-$$prefix\/share\/boring-backup}\"%" \
+ -i $$prefix/share/boring-backup/lib.sh \
+ -i $$prefix/bin/boring-backup
+ install -Dm664 $(BUILD_DIR)/share/man/ru/man1/boring-backup.1.gz $$prefix/share/man/ru/man1/boring-backup.1.gz
uninstall:
- # uninstall
+ @echo prefix: $$prefix
+ rm $$prefix/bin/boring-backup
+ rm $$prefix/share/boring-backup/lib.sh
+ rm $$prefix/share/boring-backup/backup.sh
+ rm $$prefix/share/boring-backup/common.sh
+ rm $$prefix/share/boring-backup/source.sh
+ rm $$prefix/share/boring-backup/uri.sh
+ rm $$prefix/share/boring-backup/handlers/sources/tar.sh
+ rm $$prefix/share/boring-backup/handlers/sources/mysqldump.sh
+ rm $$prefix/share/boring-backup/handlers/sources/pg_dump.sh
+ rm $$prefix/share/boring-backup/handlers/targets/cp.sh
+ rm $$prefix/share/boring-backup/handlers/targets/s3cmd.sh
+ rm -rv $$prefix/share/boring-backup
+ rm $$prefix/share/man/ru/man1/boring-backup.1.gz
+fixpath:
+ # Set boring-backup library path
+ @echo prefix: $$prefix
+ @echo path: $$path
+ sed -e "s%LIBRARY=\"\$${LIBRARY:-.\/lib}\"%LIBRARY=\"\$${LIBRARY:-$$path}\"%" \
+ -i $$prefix/share/boring-backup/lib.sh \
+ -i $$prefix/bin/boring-backup
diff --git a/README b/README
new file mode 100644
index 0000000..a15584b
--- /dev/null
+++ b/README
@@ -0,0 +1,28 @@
+BORING BACKUP
+
+ Bash powered backuping tool.
+
+INSTALLATION
+
+ Install for user locally:
+ make prefix=$HOME/.local install
+
+ Uninstall:
+ make prefix=$HOME/.local uninstall
+
+DEVELOPMENT
+
+ TESTING
+
+ BB uses amazing test suite: https://bats-core.readthedocs.io/
+
+ Install Bats:
+ git clone https://github.com/bats-core/bats-core.git
+ bash bats-core/install.sh ~/.local
+
+ Add some Bats extensions:
+ git clone https://github.com/bats-core/bats-assert.git tests/helpers/bats-assert
+ git clone https://github.com/bats-core/bats-support.git tests/helpers/bats-support
+
+ Run tests:
+ make test
diff --git a/README.md b/README.md
deleted file mode 100644
index a7ba869..0000000
--- a/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Boring Backup
-
-Bash powered backup tool.
-
-# Testing
-
-BB uses amazing test suite: https://bats-core.readthedocs.io/
-
-Install Bats:
-
- git clone https://github.com/bats-core/bats-core.git
- bash bats-core/install.sh ~/.local
-
-Add some Bats extensions:
-
- git clone https://github.com/bats-core/bats-assert.git tests/helpers/bats-assert
- git clone https://github.com/bats-core/bats-support.git tests/helpers/bats-support
-
-Run tests:
-
- make test
-
-# Linting
-
-Run shellcheck:
-
- make lint
-
-# Building
-
-Build manpages:
-
- make man
diff --git a/docs/boring-backup.ru.1.rst b/docs/boring-backup.ru.1.rst
deleted file mode 100644
index 6cc3277..0000000
--- a/docs/boring-backup.ru.1.rst
+++ /dev/null
@@ -1,509 +0,0 @@
-:Title: boring-backup
-:Title upper: BORING-BACKUP
-:Subtitle: backup files and databases
-:Author: ge
-:Copyright: \(C) 2022, ge , GPLv3+
-:Date: 2022 May 15
-:Manual section: 1
-:Version: boring-backup 0.1.0
-
-Синопсис
---------
-
-``boring-backup`` [-cvlphV] FILES..
-
-Описание
---------
-
-boring-backup - это расширяемая утилита для резервного копирования на основе
-сценариев Bash.
-
-Опции
------
-
--c, --config config file.
--v, --verbose verbose output.
--l, --log-file log file.
--p, --pid-file PID file.
--h, --help print this help messagea and exit.
--V, --version print version and exit.
-
-Быстрый старт
--------------
-
-boring-backup можно рассматривать как фреймворк или библиотеку для создания
-сценариев резервного копирования. Сценарии должны содержать валидный код на
-Bash. Сценарий импортируется в основной скрипт с помощью команды ``source``
-(см. ``bash``\(1) п. SHELL BUILTIN COMMANDS).
-
-Простейший сценарий резервного копирования выглядит следующим образом::
-
- sources=(file:/home/user)
- targets=(file:/var/backup)
-
-Здесь массивы `sources` и `targets` определяют точки, они же поинты (`points`)
-резервного копирования: источники (`sources`) и назначения (`targets`). Это
-основные сущности, с которыми работает boring-backup. Вот некоторые особенности
-поинтов:
-
-- Все поинты указываются в формате URI.
-- Поинты могут указывать как на локальные (размещённые на текущей машине), так
- и на удалённые (размещённые на удалённой машине) ресурсы.
-- Можно указать как несколько источников, так и несколько назначений.
-
-Для выполнения бэкапа директорий или отдельных файлов применяется схема URI
-`file`. В схеме `file` нельзя указать директорию, размещённую на удалённом
-хранилище (за исключением случая, когда удалённое хранилище примонтировано как
-файловая система), для этого используйте другие схемы. В примере выше будет
-выполнена резервная копия локальной директории /home/user в другую локальную
-директорию /var/backup. Поскольку в сценарии из примера нет ничего, кроме
-указания точек `sources` и `targets`, бэкап будет выполнен с параметрами по
-умолчанию: директория /home/user будет заархивирована с помощью утилиты
-``tar``\(1) и помещён в директорию /var/backup. Имя архива будет сложено по
-шаблону::
-
- ${name_prefix}${name}${name_date_fmt}${name_suffix}${name_ext}
-
-Описание переменных см. в разделе ПЕРЕМЕННЫЕ. Пример имени файла::
-
- example.sh_example_2022.05.15-0953.tar
-
-Обзор URI
----------
-
-Источники (`sources`) и назначения (`targets`) должны быть указаны в виде
-URI. Это позовляет наглядно в одной сроке видеть весь набор данных. Парсер
-реализует поддержку следующего синтаксиса URI::
-
- scheme:[//[username[:password]@]hostname[:port]]/[path]?[query]#[fragment]
-
-Парсер URI соответствует RFC 3986 не полностью - разбиение на составные части
-URI происходит верно, но интерпретация в отдельных ситуациях может отличаться.
-См. примеры URI и реузультаты их интерпретации парсером в файле
-`tests/parse_uri.bats`. На практике рекомендую придерживаться примеров, которые
-приведены ниже и в файле `tests/parse_uri.bats`. В случае, если изменение
-логики парсера необходимо, вы можете прислать правки в pull-реквесте или
-завести feature-реквест в репозитории проекта. На текущий момент компоненты
-`query` и `fragment` не используются.
-
-Примеры URI для массива `sources`::
-
- mysql://wordpress:1jobrRRjtLYs@localhost/wordpress
- postgres://django:9%3F2%3D%40gHW@localhost:5432:/django
- sqlite:///var/www/app/data/database.db
- file:///var/www/html/
-
-Примеры URI для `targets`::
-
- file:/var/backup
- ftp://jhon:%24t%D0%AFo%7C%5C%7C6@[fe80::5054:ff:fe24:382]:2021/backups/
- rsync://backup_user@192.168.3.12:2022/backups
- s3://my_bucket
-
-Пароли содержащие специальные символы недопустимые в URI (включая пробелы)
-необходимо закодировать в percent code. См. примеры кодирования строки на
-разных языках программирования ниже.
-
-Python 2::
-
- python2 -c "import urllib, sys; \
- print urllib.quote(sys.argv[1], safe='')" 'p@$$w0rd'
-
-Python 3::
-
- python3 -c "import urllib.parse, sys; \
- print(urllib.parse.quote(sys.argv[1], safe=''))" 'p@$$w0rd'
-
-Perl 5::
-
- echo 'p@$$w0rd' | perl -MURI::Escape -wlne 'print uri_escape $_'
-
-Поддерживаемые протоколы и схемы URI
-------------------------------------
-Схемы, которые могут быть использованы как sources
-``````````````````````````````````````````````````
-
-file
- Может содержать путь к локальному файлу или директории. Файлы
- архивируются при помощи ``tar`` и по умолчанию не сжимаются. Cжатие
- архива может быть включено через переменную `compression`. Примеры::
-
- /var/www/www-root/data
- file:/var/www/html
- file:///home/jhon/cool_stuff.txt
-
- Не используйте двойной слэш для этой схемы, используйте один или три
- слэша. Двойной слэш означает наличие компонента Authority, это приводит
- к неверной интерпретации адреса.
-
- См. также ``handler::tar``
-
-mysql
- URI содержит реквизиты для подключения к БД MySQL/MariaDB. Формат::
-
- mysql://[username[:password]@]hostname[:port]/database
-
- С помощью утилиты ``mysqldump``\(1) формируется дамп в формате SQL. Файл
- по умолчанию не сжимается, но сжатие может быть включено через переменную
- `compression`.
-
- См. также ``handler::mysqldump``
-
-postgres
- Аналогично `mysql`, но для PostgreSQL. Для создания дампа используется
- ``pg_dump``\(1) с расширением .psql. Файл по умолчанию не сжимается, но
- сжатие может быть включено через переменную `compression`.
-
- См. также ``handler::pg_dump``
-
-sqlite
- Схема для баз данных SQLite. Мало отличается от `file`, добавлена для
- наглядного обозначения, что источником является БД SQLite, а не иной файл.
-
- См. также ``handler::sqlite``
-
-Схемы, которые могут быть использованы как targets
-``````````````````````````````````````````````````
-
-file
- В контексте `targets` указывает директорию для сохранения бэкапов. В
- массиве `targets` обязательно должен быть хотя бы один поинт со схемой
- `file`. Этот поинт будет использован как основной и сохранён в переменные
- ``__main_target`` (содержит URI) и ``__main_target_path`` (содержит
- компонент URI path). Если в массиве присутствует несколько поинтов со
- схемой `file`, то в качестве основного будет выбран первый по порядку
- поинт. Все бэкапы первоначально будут сохраняться в директорию
- ``__main_target_path`` и затем копироваться в другой таргет с помощью
- соответствующего обработчика. В случае копировани из одной директории в
- другую используется утилита ``cp``\(1).
-
- Избегайте указания в одном сценарии таргетов, которые ведут одновременно на
- примонтированный к локальной машине сетевой диск и другое удалённое
- хранилище. В таком случае архивы будут создаваться на сетевом диске и далее
- снова копироваться по сети, что будет очень медленно.
-
- См. также ``handler::cp``
-
-ftp
- Не реализовано.
-
-sftp
- Не реализовано.
-
-rsync
- Не реализовано.
-
-s3
- Не реализовано.
-
-swift
- Не реализовано.
-
-sj
- Не реализовано.
-
-dav, davs
- Не реализовано.
-
-Создание резервных копий
-------------------------
-
-boring-backup предполагает, что для всех резервных копий необходимо создавать
-архивы. Поэтому вам нужно следить за тем, чтобы в локальном хранилище всегда
-хватало дискового пространства для создания новых архивов. boring-backup также
-не удаляет старые архивы и вам также надо позаботиться об удалении устаревших
-резервных копий. Изменить это поведение можно с помощью пользовательских
-функций в сценариях. В этом разделе речь пойдёт о поведении, которое
-установлено по умолчанию. См. функции ``builtin_backup``, ``process_sources``,
-``process_targets``.
-
-Базовая концепция строится на том, что существует несколько источников и
-несколько точек назначения. Создаётся резервная копия источника и копируется в
-точку назначения.
-
-Для всех источников в сценарии выполняется локальная резервная копия. После
-этого локальная копия переносится в удалённые точки назначения, если они
-заданы. Копирование локального бэкапа будет осуществлёно столько раз, сколько
-точек назначения задано. В каждом сценарии обязательно должен быть задан хотя
-бы один источник и одна точка назначения. При этом в списке точек назначения
-обязательно должна присутствовать точка со схемой `file`. Именно в неё будут
-сохранены архивы.
-
-Например, имеется следующий сценарий::
-
- sources=(
- mysql://wordpress:1jobrRRjtLYs@localhost/wordpress
- file:///var/www/wordpress
- )
- targets=(
- file:///var/backup
- ftp://jhon:%24t%D0%AFo%7C%5C%7C6@[fe80::5054:ff:fe24:382]:2021/backups/
- )
-
-Здесь будут созданы архивы файлов и базы данных и сохранены в локальную
-директорию /var/backup. Затем эти файлы будут переданы по протоколу FTP на
-сервер fe80::5054:ff:fe24:382 в директорию /backups. Файлы из директории
-/var/backup не будут удалены или перемещены. Если добавить дополнительную точку
-назначения, то файлы из /var/backup будут скопированы и туда. Обратите
-внимание, что boring-backup не выполняет повторного создания архивов для каждой
-точки назначения — архивы создаются один раз и далее распространяются по всем
-указанным назначениям. Если в массиве `targets` имеется несколько точек
-назначения со схемой `file`, то архивы будут сохранены в первую по порядку
-точку, а затем скопированы оттуда в остальные.
-
-Резервное копирование на удалённое хранилище
---------------------------------------------
-FTP
-```
-SFTP
-````
-Rsync over SSH
-``````````````
-Rsync with rsyncd
-`````````````````
-Amazon S3
-`````````
-S3 compatible storage
-`````````````````````
-OpenStack Swift
-```````````````
-Storj DCS
-`````````
-WebDAV
-``````
-Переменные
-----------
-
-``boring-backup`` условно разделяет переменные на "внутренние" ("защищённые") и
-"обычные". К "защищённым" переменным относятся все перемеменные, имена которых
-начинаются с двух знаков подчёркивания, например: ``__main_target``. Все
-остальные переменные считаются "обычными".
-
-Обычные переменные могут быть перезаписаны в пользовательском скрипте.
-Защищённые переменные технически ничем от них не отличаются, однако не нужно
-переопределять такие переменные в пользовательском скрипте, так как это может
-привести к неожиданным ошибкам во время выполнения скрипта. Точно также очень
-внимательно нужно относится к перезаписи обычных переменных — в обоих случаях
-есть риск что-то поломать.
-
-``backups``
- Массив со списком созданных бэкапов. Содержит абсолютные пути к файлам.
- Заполняется функциями-обработчиками `sources`.
-
- | Тип: массив
- | Умолчание: ()
-
-``errors``
- Массив с текстами ошибок. Заполняется функцией ``err`` с опцией ``-a``.
-
- | Тип: массив
- | Умолчание: ()
-
-``log_date_fmt``
- Формат даты в логе. См. ``date``\(1).
-
- | Тип: строка
- | Умолчание: %d/%b/%Y:%H:%M:%S %z
-
-``name_prefix``
- Префикс имени файла. Может быть задан в скрипте.
-
- | Тип: строка
- | Умолчание: имя_скрипта\_
-
-``name``
- Соответствует имени архивируемой директории/файла полученного из `path` с
- помощью утилиты ``basename``\(1).
-
- | Тип: строка
- | Умолчание: нет
-
-``name_date_fmt``
- Дата, интерпретируемая утилитой ``date``\(1).
-
- | Тип: строка
- | Умолчание: _%Y%m%d
-
-``name_suffix``
- Суффикс, добавляемый к имени файла перед расширением. Строка
- интерпретируется утилитой ``date``.
-
- | Тип: строка
- | Умолчание: -%H%M
-
-``name_ext``
- Расширение имени файла, соответствующее формату архива.
-
- | Тип: строка
- | Умолчание: .tar.gz
-
-``tar_options``
- Опции ``tar``. См. ``tar``\(1).
-
- | Тип: строка
- | Умолчание: -acf
-
-``tar_exclude``
- Список имён для опции ``tar`` ``--exclude``.
-
- | Тип: массив
- | Умолчание: нет
-
-``compression``
- В контексте ``tar`` работа этой фичи базируется на опции ``tar``
- ``--auto-compress``. Переменная может принимать значения, в соответствии с
- табилцей ниже. Если переменная имеет значение, отличное от перечисленныых,
- то будет использован ``gzip``. Если переменная пуста или не задана, то
- сжатие будет отключено.
-
- | Тип: строка
- | Умолчание: нет
-
- ==================== ================ ========
- Значение compression Расширение файла Утилита
- ==================== ================ ========
- gzip, gz .tar.gz gzip
- tgz .tgz gzip
- taz .taz gzip
- compress, Z .tar.Z compress
- taZ .taZ compress
- bzip2, bz2 .tar.bz2 bzip2
- tz2 .tz2 bzip2
- tbz2 .tbz2 bzip2
- tbz .tbz bzip2
- lzip, lz .tar.lz lzip
- lzma .tar.lzma lzma
- tlz .tlz lzma
- lzop, lzo .tar.lzo lzop
- xz .tar.xz xz
- zstd, zst .tar.zst zstd
- tzst .tzst zstd
- ==================== ================ ========
-
-Функции
--------
-
-``backup``
- Пользовательская функция резервного копирования. Если она задана в скрипте,
- то вызывается вместо ``builtin_backup``.
-
-``builtin_backup``
- Встроенная функция, запускает резервное копирвоание. Вызывает функции
- ``process_source`` и ``process_target``.
-
-``err [-eao] MESSAGE``
- Печатает сообщение об ошибке MESSAGE на экран и в лог и выполняет обработку
- ошибок.
-
- -e Выйти из скрипта с кодом выхода 1.
- -a Добавить сообщение MESSAGE в массив ``errors``.
- -o Вызвать функцию ``on_error``.
-
-``finalise``
- Пользовательская функция. Если задана, то запускается после функции
- ``backup`` или ``builtin_backup()``.
-
-``gen_backup_name FILE_EXT``
- Печатает полученное имя файла в STDOUT. Имя является выводом команды
- ``date`` и строки ``${prefix}${name}${date_fmt}${name_ext}``.
- См. переменные ``name_prefix``, ``name``, ``name_date_fmt``, ``name_ext``.
-
-``try COMMAND``
- Функция выполняет команду COMMAND и в случае ненулевого кода выхода
- вызывает ``err()`` с ключами ``-eao``. Ошибка при выполнении COMMAND
- приведёт к вызову функции ``on_error``. Рекомендуется для использования в
- качестве обёртки для команд правильное выполнение которых критично.
-
-``handler::tar URI``
- Архивация файлов с помощью ``tar``.
-
-``handler::mysqldump URI``
- Не реализовано.
-
-``handler::pg_dump URI``
- Не реализовано.
-
-``handler::sqlite URI``
- Не реализовано.
-
-``handler::cp URI``
- Копирует файлы в новое назначение с помощью ``cp``.
-
-``handler::ftp URI``
- Не реализовано.
-
-``handler::sftp URI``
- Не реализовано.
-
-``handler::rsync URI``
- Не реализовано.
-
-``handler::s3 URI``
- Не реализовано.
-
-``handler::sj URI``
- Не реализовано.
-
-``handler::swift URI``
- Не реализовано.
-
-``handler::dav URI``
- Не реализовано.
-
-``handler::davs URI``
- Не реализовано.
-
-``is_installed COMMAND``
- Проверяет установлена ли программа COMMAND.
-
-``is_function_set FUNCTION``
- Проверяет задана ли функция FUNCTION.
-
-``log [-p] MESSAGE``
- Печатает лог в файл ``__log_file`` (лог задаётся опцией --log-file) и на
- экран, если указана опция ``-p``. Формат даты в логе можно изменить с
- помощью переменной ``log_date_fmt``.
-
-``on_error``
- Пользовательская функция для обработки ошибок. Если задана, то запускается
- при обработке ошибки в функции ``err`` с опцией ``-o``.
-
-``parse_uri URI``
- Парсер URI. Задаёт переменные ``scheme``, ``username``, ``password``,
- ``hostname``, ``port``, ``path``, ``query``, ``fragment`` и выполняет
- декодинг пароля, если он закодирован в percent code.
-
-``prepare``
- Пользовательская функция. Если задана, то запускается до функции ``backup``
- или ``builtin_backup``.
-
-``process_source URI``
- На основе схемы запускает соответсвующую функцию-обработчик.
-
-``process_target URI``
- На основе схемы запускает соответсвующую функцию-обработчик.
-
-``source_script FILE``
- Выполняет ``source`` пользовательского скрипта и проверяет его
- корректность. Проверяется синтаксис Bash, наличие непустых массивов
- `sources` и `targets`, наличие поинта `file` в `targets`. Во
- вспомогательной функции ``validate_targets`` задаются значения переменных
- ``__main_target`` и ``__main_target_path``.
-
-Использование функций в сценариях
----------------------------------
-Переменные окружения
---------------------
-
-``LIBRARY``
- Путь до библиотеки функций boring-backup.
-
-Примеры
--------
-См. также
----------
-
-``bash``\(1), ``tar``\(1), ``cp``\(1), ``date``\(1), ``mysqldump``\(1),
-``pg_dump``\(1)
-
-RFC 3986 https://datatracker.ietf.org/doc/html/rfc3986
diff --git a/docs/manpages/boring-backup.ru.1.rst b/docs/manpages/boring-backup.ru.1.rst
new file mode 100644
index 0000000..e226308
--- /dev/null
+++ b/docs/manpages/boring-backup.ru.1.rst
@@ -0,0 +1,640 @@
+:Title: boring_backup
+:Title upper: BORING_BACKUP
+:Subtitle: бэкап файлов и баз данных
+:Author: ge
+:Copyright: \(C) 2022, ge , GPLv3+
+:Date: 2022 May 15
+:Manual section: 1
+:Version: boring_backup 0.1.0
+
+СИНТАКСИС
+---------
+
+**boring_backup** [-hVvs] [-c `файл`] [-l `файл`] [-p `файл`] файл ...
+
+ОПИСАНИЕ
+--------
+
+boring_backup - это расширяемая утилита для резервного копирования на основе
+сценариев Bash.
+
+ОПЦИИ
+-----
+
+-h, --help
+ Показать справку и выйти.
+
+-V, --version
+ Показать информацию о версии и выйти.
+
+-v, --verbose
+ Печатать подробный вывод.
+
+-c, --config=\ `файл`
+ Путь до файла конфигурации. См. **КОНФИГУРИРОВАНИЕ**.
+
+-l, --log-file=\ `файл`
+ Путь до файла лога.
+
+-s, --use-syslog
+ Записывать лог в syslog вместо файла. Эта опция несовместима с опцией
+ --log-file и переменной log_date_format.
+
+-p, --pid-file=\ `файл`
+ Путь до PID-файла.
+
+ОБЗОР
+-----
+
+**boring_backup** можно рассматривать как фреймворк или библиотеку для создания
+сценариев резервного копирования. Сценарии (скрипты) должны содержать валидный
+код на Bash.
+
+Скрипты передаются в качестве аргументов **boring_backup** и исполняются в
+цикле. Скрипты загружается с помощью команды ``source`` (см. ``bash``\(1)
+п. SHELL BUILTIN COMMANDS).
+
+Простейший сценарий резервного копирования выглядит следующим образом::
+
+ sources=(file:/home/john)
+ targets=(file:/var/backups)
+
+Массивы `sources` и `targets` определяют источники и назначения соответственно.
+Ресурсы из `sources` нужно сохранить в точку(и) назначения — `targets`. См.
+больше примеров в разделе **ПРИМЕРЫ**.
+
+Все ресурсы записываются в формате URI. См. подробности в разделе
+**СХЕМЫ URI** и в описании функции ``parse_uri`` ниже.
+
+Каждой схеме URI соответствует функция-обработчик, которая выполняет действие
+с ресурсом. Например, URI со схемой `mysql` будет обработан функцией
+``src_mysqldump``.
+
+Обработчики ресурсов для массива `sources` имеют в имени префикс ``src_``, а
+обработчики для массива `targets` префикс ``tgt_``. См. описания обработчиков в
+разделе **ВСТРОЕННЫЕ ФУНКЦИИ**.
+
+Поскольку скрипты резервного копирования это обычные скрипты Bash, то здесь
+применимы все те же приёмы. В **boring_backup** предусмотрено несколько
+специальных пользовательских функций и ряд специальных переменных. См. разделы
+**ПЕРЕМЕННЫЕ** и **ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ**.
+
+СХЕМЫ URI
+---------
+
+file
+ Схема для указания ресурсов в файловой системе. Примеры записи::
+
+ /var/www/www-root/data
+ file:/var/www/html
+ file:///home/jhon/cool_stuff.txt
+
+ Не используйте двойной слэш для этой схемы, используйте один или три
+ слэша. Двойной слэш означает наличие компонента Authority, который здесь
+ не обрабатывается, что приводит к неверной интерпретации адреса.
+
+ Схема `file` может быть указана как в массиве `sources`, так и `targets`.
+
+ В массиве `sources` схема обрабатывается функцией ``src_tar``. Файлы
+ архивируются и сжимаются согласно значению переменной $compression.
+
+ В контексте `targets` `file` указывает директорию для сохранения бэкапов.
+ В `targets` обязательно должен быть хотя бы один URI со схемой `file`.
+ Этот URI будет использован как основной и сохранён в переменные
+ $__main_target (содержит URI целиком) и $__main_target_path (содержит
+ компонент URI path).
+
+ Если в массиве `targets` присутствует несколько URI со схемой `file`, то в
+ качестве основного будет выбран первый по порядку URI. Все бэкапы
+ первоначально будут сохраняться туда и затем копироваться в другой таргет с
+ помощью соответствующего обработчика. В случае копирования бэкапов между
+ директориями будет использован обработчик ``tgt_cp``.
+
+ Избегайте указания в одном сценарии таргетов, которые ведут одновременно на
+ примонтированный к локальной машине сетевой диск и на другое удалённое
+ хранилище. В таком случае архивы будут создаваться на сетевом диске и далее
+ снова копироваться по сети. Это может быть очень медленно.
+
+ См. также ``src_tar``, ``tgt_cp``.
+
+mysql, mariadb
+ URI содержит реквизиты для подключения к БД MySQL/MariaDB. Иногда такой
+ формат ещё называют DSN (data source name)::
+
+ mysql://[username[:password]@]hostname[:port]/database
+
+ См. также ``src_mysqldump``.
+
+postgres
+ Аналогично `mysql`, но для PostgreSQL. Для создания дампа используется
+ ``pg_dump``. Расширение несжатых файлов — .psql.
+
+ См. также ``src_pg_dump``
+
+sqlite [НЕ РЕАЛИЗОВАН]
+ Схема для баз данных SQLite. Мало отличается от `file`, добавлена для
+ наглядного обозначения, что ресурсом является БД SQLite, а не иной файл.
+
+ См. также ``src_sqlite``
+
+s3
+ Схема Simple Storage Service (S3). Пример использования::
+
+ s3://bucket
+
+ URI содержит только схему и путь. Все остальные реквизиты для подключения к
+ хранилищу задаются через конфигурационный файл или отдельные переменные.
+ См. ``tgt_s3cmd`` ниже.
+
+ В S3 важно наличие слэшей в конце URI. Пример::
+
+ s3://bucket/backups (1)
+ s3://bucket/backups/ (2)
+
+ В случае (1) при загрузке файла с именем dump.sql.gz файл будет сохранён
+ как, s3://bucket/backups, а не s3://bucket/backups/dump.sql.gz. Чтобы
+ такого не происходило следует добавлять слэш в конце (2), чтобы обозначить,
+ что backups в данном случае является директорией. Обработчик ``tgt_s3cmd``
+ сам добавляет слэш в конец URI, если его нет.
+
+ Ещё одной особенностью является то, что в URI можно записывать
+ несуществующие в хранилище директории. Они будут созданы при загрузке
+ файла. Таким образом можно делать следующее::
+
+ today="$(date +%d_%b_%Y)"
+ targets=(
+ file:///var/backups
+ s3://bucket/backups/$today
+ )
+
+ Бэкап будет сохранён как::
+
+ s3://bucket/backups/22_Aug_2022/dump.sql.gz
+
+ПЕРЕМЕННЫЕ
+----------
+
+``sources``
+ | Тип: массив
+ | Умолчание: нет
+
+ Массив из строк с URI ресурсов, резервную копию которых нужно выполнить.
+ Массив обязатально должен быть непустой. Пример::
+
+ sources=(
+ file:///home/john
+ mysql://user:password@localhost:3306/database
+ )
+
+ См. **СХЕМЫ URI**.
+
+``targets``
+ | Тип: массив
+ | Умолчание: нет
+
+ Массив из строк URI хранилищ, куда необходимо доставить резервные копии.
+ Обязательно должен содержать хотя бы один URI со схемой `file`. Пример::
+
+ targets=(
+ file:///var/backups
+ s3://bucket/backups/$today
+ )
+
+ См. **СХЕМЫ URI**.
+
+``backups``
+ | Тип: массив
+ | Умолчание: нет
+
+ Массив со списком созданных бэкапов. Содержит абсолютные пути к файлам.
+ Заполняется функциями-обработчиками `sources` при успешном создании бэкапа.
+
+ При использовании пользовательской функции ``backup`` массив следует
+ заполнять вручную для корректного вызова функций-обработчиков для
+ `targets`. См. пример в разделе **ПРИМЕРЫ**.
+
+``compression``
+ | Тип: строка
+ | Умолчание: нет
+
+ Тип компрессии для сжатия файлов.
+
+ В контексте ``tar`` работа этой фичи базируется на опции ``tar``
+ ``--auto-compress``. Переменная может принимать значения, в соответствии с
+ табилцей ниже. Если переменная не задана, имеет пустое или отличное от
+ перечисленныых в таблице значение, то сжатие будет отключено.
+
+ Для файлов, которые не являются архивами tar (не созданы функцией
+ ``src_tar``) расширение из таблицы будет добавлено к оригинальному
+ рассширению файла.
+
+ ==================== ========== =================== =====================
+ Значение compression Утилита Расширение файла Расширение архива tar
+ ==================== ========== =================== =====================
+ gzip, gz gzip .gz .tar.gz
+ tgz gzip .gz .tgz
+ taz gzip .gz .taz
+ bzip2, bz2 bzip2 .bz2 .tar.bz2
+ tz2 bzip2 .bz2 .tz2
+ tbz2 bzip2 .bz2 .tbz2
+ tbz bzip2 .bz2 .tbz
+ lzip, lz lzip .lz .tar.lz
+ lzma lzma .lzma .tar.lzma
+ tlz lzma .lzma .tlz
+ lzop, lzo lzop .lzo .tar.lzo
+ xz xz .xz .tar.xz
+ zstd, zst zstd .zst .tar.zst
+ tzst zstd .zst .tzst
+ ==================== ========== =================== =====================
+
+``log_date_format``
+ | Тип: строка
+ | Умолчание: %d/%b/%Y:%H:%M:%S %z
+
+ Формат даты в логе. См. ``date``. См. **КОНФИГУРИРОВАНИЕ**.
+
+``name``
+ | Тип: строка
+ | Умолчание: нет
+
+ Соответствует имени архивируемой директории/файла полученного из `path` с
+ помощью утилиты ``basename``. Вычисляется автоматически, не может быть
+ задан в скрипте.
+
+``name_date_format``
+ | Тип: строка
+ | Умолчание: _%Y%m%d
+
+ Дата, интерпретируемая утилитой ``date``. Полученная строка используется в
+ имени файла бэкапа.
+
+``name_prefix``
+ | Тип: строка
+ | Умолчание: имя_скрипта\_
+
+ Префикс имени файла. Может быть задан в скрипте. Значение по-умолчанию
+ состоит из имени скрипта резервного копирования и знака "_".
+
+``name_suffix``
+ | Тип: строка
+ | Умолчание: -%H%M
+
+ Суффикс, добавляемый к имени файла перед расширением. Строка
+ интерпретируется утилитой ``date``.
+
+``name_ext``
+ | Тип: строка
+ | Умолчание: нет
+
+ Расширение имени файла соответствующее формату архива. Вычисляется
+ автоматически и не может быть задано в скрипте резервного копирования.
+
+``mysqldump_options``
+ | Тип: строка
+ | Умолчание: нет
+
+ Опции для утилиты ``mysqldump``.
+
+``pg_dump_options``
+ | Тип: строка
+ | Умолчание: нет
+
+ Опции для утилиты ``pg_dump``.
+
+``s3cmd_config``
+ | Тип: строка
+ | Умолчание: нет
+
+ Путь к файлу конфигурации утилиты ``s3cmd``. См. соответствующую страницу
+ страницу справки ``s3cmd``\(1).
+
+``s3cmd_options``
+ | Тип: строка
+ | Умолчание: --preserve --quiet --no-progress
+
+ Опции для утилиты ``s3cmd``.
+
+``s3_access_key``
+ | Тип: строка
+ | Умолчание: нет
+
+ Значение для опции ``s3cmd`` ``--access_key``.
+
+``s3_secret_key``
+ | Тип: строка
+ | Умолчание: нет
+
+ Значение для опции ``s3cmd`` ``--secret_key``.
+
+``s3_host``
+ | Тип: строка
+ | Умолчание: нет
+
+ Значение для опции ``s3cmd`` ``--host``. Должен содержать адрес эндпоинта
+ для доступа к объектному хранилищу без схемы (только домен).
+
+``s3_host_bucket``
+ | Тип: строка
+ | Умолчание: нет
+
+ Значение для опции ``s3cmd`` ``--host-bucket``. Шаблон для `virtual-hosted
+ style` адреса бакета. Для `path style` это значение должно совпадать с
+ `s3_host`.
+
+``s3_region``
+ | Тип: строка
+ | Умолчание: na
+
+ Значение для опции ``s3cmd`` ``--region`` или ``--bucket_location``.
+ Переменная необязательна к заполнению, так как некоторые S3-совместимые
+ хранилища не используют регионы. В таком случае будет использован фиктивный
+ регион `na` (not available).
+
+``tar_options``
+ | Тип: строка
+ | Умолчание: -acf
+
+ Опции ``tar``. См. ``tar``\(1).
+
+``tar_exclude``
+ | Тип: массив
+ | Умолчание: нет
+
+ Список имён для опции ``tar`` ``--exclude``. Пример::
+
+ tar_exclude=( foo bar )
+
+ Массив разворачивается в строку вида '--exclude=foo --exclude=bar' и
+ подставляется в строку опций ``tar``.
+
+ВСТРОЕННЫЕ ФУНКЦИИ
+------------------
+
+``set_compression``
+ Определить утилиту и расширение файла на основе строки.
+
+ При вызове этой функции в качестве аргумента ей передаётся значение
+ переменной $compression. На её основе функция задаёт переменные $cmpr_ext,
+ $tar_ext и $cmpr_cmd. $tar_ext используется только в функции ``src_tar``,
+ другие две в функции ``compress_file``.
+
+ См. таблицу в описании переменной $compression.
+
+``compress_file``
+ Выполнить сжатие файла и напечатать имя сжатого файла. Удалить несжатый
+ файл.
+
+ Внутри себя вызывает функцию ``set_compression`` для определния утилиты и
+ расширения файла. Если переменная $compression не задана, то сжатие не
+ производится.
+
+``gen_backup_name``
+ Функция печатает строку, содержащую имя файла. Имя генерируется с помощью
+ команды::
+
+ date +"${name_prefix}${name}${name_date_format}${name_suffix}${name_ext}"
+
+ $name_ext принимает значение, переданное в качестве аргумента. См. описания
+ переменных выше и также в исходном коде функции.
+
+``handle_error``
+ Обработать ошибку. Делает проверку и вызывает пользовательскую функцию
+ ``on_error``.
+
+``is_function_set``
+ Проверить задана ли функция и вернуть код выхода. Применима в конструкции
+ **if**.
+
+``is_installed``
+ Проверить установлена ли утилита и выйти из скрипта при неудаче.
+
+``log``
+ Записать сообщение в лог.
+
+ Синтаксис: **log** [-pV] сообщение
+
+ | Опции:
+ | -p напечатать сообщение также на экран (STDOUT)
+ | -V игнорировать опцию **--verbose**
+
+ Функция записывает сообщения в лог-файл. Лог-файл может быть задан через
+ опцию **--log-file**, имя этого файла будет сохранено в переменную
+ $__log_file. **log** перед записью в файл удаляет из текста
+ escape-последовательности ANSI.
+
+ Формат лога '[%s] %s\\n', где первое вхождение %s заменяется на дату, а
+ второе на текст сообщения. Формат даты задаётся через переменную
+ $log_date_format (см. описание выше).
+
+ Все сообщения, отправляемые в **log** печатаются в терминал, если
+ **boring_backup** запущен с опцией **--verbose**. Избежать этого можно
+ вызвав логгер с опцией **-V**.
+
+``parse_uri``
+ Разобрать строку URI на компоненты. Парсер соответствует RFC 3986.
+
+ Функция задаёт переменные: $scheme, $username, $password, $hostname,
+ $port, $path, $query, $fragment
+
+ Поддерживается работа с IPv6 адресами, если они заключены в квадратные
+ скобки.
+
+ Поддерживается работа с паролями, содержащими зарезервированные символы.
+ Такие пароли необходимо закодировать в так называемый percent code.
+ **parse_uri** возвращает в переменной $password уже раскодированный пароль.
+ Ниже представлены примеры кодирования паролей в командной строке.
+
+ Python 2::
+
+ python2 -c "import urllib, sys; \
+ print urllib.quote(sys.argv[1], safe='')" 'p@$$w0rd'
+
+ Python 3::
+
+ python3 -c "import urllib.parse, sys; \
+ print(urllib.parse.quote(sys.argv[1], safe=''))" 'p@$$w0rd'
+
+ Perl 5::
+
+ echo 'p@$$w0rd' | perl -MURI::Escape -wlne 'print uri_escape $_'
+
+``remove_if_empty``
+ Удалить файл, если он пустой.
+
+``src_mysqldump``
+ Получить SQL дамп базы данных MariaDB или MySQL.
+
+ Дамп выполняется с помощью утилиты ``mysqldump``. Ей можно передать
+ дополнительные опции через переменную $mysqldump_options (см. описание
+ выше).
+
+``src_pg_dump``
+ Получить SQL дамп базы данных PostgreSQL.
+
+ Дамп выполняется с помощью утилиты ``pg_dump``. Ей можно передать
+ дополнительные опции через переменную $pg_dump_options (см. описание выше).
+
+``src_tar``
+ Создать архив tar. Используемые переменные: $tar_options, $tar_exclude.
+
+``tgt_cp``
+ Скопировать файлы в новое назначение.
+
+ Эта функция вызывается при каждом запуске резервного копирования и
+ обрабатывает схему `file` в массиве `targets`. Если в массиве есть
+ несколько URI со схемой `file`, то ``tgt_cp`` скопирует файлы из первой
+ директории во все остальные.
+
+``tgt_s3cmd``
+ Загрузить файлы в S3-совместимое объектное хранилище с помощью ``s3cmd``.
+
+ Реквизиты для подключения к хранилищу можно передать в конфигурационном
+ файл ``s3cmd`` указав путь до него в переменной $s3cmd_config.
+
+ Помимо этого реквизиты можно записать прямо в скрипт резервного копирования
+ в переменные: $s3_access_key, $s3_secret_key, $s3_host, $s3_host_bucket,
+ $s3_region. Дополнительные опции для ``s3cmd`` можно задать через
+ $s3cmd_options. См. описание всех переменных в разделе **ПЕРЕМЕННЫЕ**.
+
+``builtin_backup``
+ Запустить функции ``process_source`` и ``process_target`` для каждого URI
+ из соответствующих массивов.
+
+``process_source``
+ Запустить соответствующую функцию-обработчик для массива `sources`.
+
+``process_target``
+ Запустить соответствующую функцию-обработчик для массива `targets`.
+
+``source_script``
+ Выполнить проверки и загрузить (``source``) пользовательский скрипт
+ резервного копирования.
+
+``validate_sources``
+ Проверить массив `sources`. Выполняются проверки на пустой массив и на
+ использование правильного набора схем URI.
+
+``validate_targets``
+ Проверить массив `targets`. Выполняются проверки на пустой массив и на
+ использование правильного набора схем URI. Для успешной проверки массив
+ должен содержать хотя бы одну строку URI со схемой `file`.
+
+ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ
+------------------------
+
+``prepare``
+ В этой функции можно запрограммировать действия, необходимые перед
+ выполнением бэкапа.
+
+``backup``
+ Эта функция позволяет переопределить логику резервной копии.
+
+ Если функция **backup** объявлена, то она будет вызвана вместо встроенной
+ функции **builtin_backup**.
+
+ Используйте **backup**, когда вам необходимо использовать собственную
+ логику вместо заложенной разработчиком **boring_backup**.
+
+``finalise``
+ В этой функции можно запрограммировать действия, выполнение которых
+ необходимо после выполнения бэкапа.
+
+ Пример использования: удаление локальных резервных копий после их загрузки
+ на удалённое хранилище.
+
+``on_error``
+ В этой функции можно запрограммировать действия при возникновении ошибки.
+ В качестве аргумента для неё передаётся строка с текстом произошедшей
+ ошибки.
+
+ Пример использования: отправка отчёта об ошибке на имейл.
+
+КОНФИГУРИРОВАНИЕ
+----------------
+
+По умолчанию **boring_backup** пытается прочитать файл по пути
+~/.config/boring_backup. Также путь до конфигурационного файла можно
+передать через опцию **--config**.
+
+Конфиг имеет те же свойства, что и скрипт резервного копированиия, но
+загружается всякий раз после загрузки скрипта резевного копирования. Таким
+образом он может переопределять заданные в скриптах функции и переменные.
+
+Параметры, которые нежелательно определять в скриптах резервного копирования:
+
+* log_date_format
+* name_date_format
+
+Переопределять их следует через конфигурационный файл.
+
+ПРИМЕРЫ
+-------
+
+Скрипт для бэкапа сайта со сжатием файлов с помощью ``xz``, загрузкой в S3 и
+удалением локальных бэкапов после загрузки::
+
+ compression=xz
+ s3cmd_config=~/.s3cfg
+ sources=(
+ /var/www/www-data/example.com
+ mysql://example_user:Smk3mVH2@localhost/example_db
+ )
+ targets=(
+ /var/backups/example.com/
+ s3://mybucket/backups/example-com
+ )
+ finalise() {
+ log -p "\tClean up local backups"
+ log -p "\tFiles to delete: ${backups[@]}"
+ rm -- "${backups[@]}"
+ log -p "\tLocal backups deleted"
+ }
+
+Бэкап домашней папки на примонтированный в /mnt/backups сетевой диск::
+
+ compression=xz
+ tar_exclude=(.cache)
+ sources=(/home/john)
+ targets=(/mnt/backups)
+
+Бэкап приложения Gitea::
+
+ sources=(.) # just pass validation
+ targets=(.)
+ today="$(date +%d_%b_%Y)"
+ s3cmd_config=~/.s3cfg
+ prepare() {
+ systemctl stop gitea.service
+ sleep 5
+ }
+ backup() {
+ log -p "Dumping Gitea"
+ su -c "/usr/local/bin/gitea dump -c /etc/gitea/app.ini \
+ -f /home/git/.cache/gitea_dump.zip" - git 2>> "$__log_file"
+ backups+=(/home/git/.cache/gitea_dump.zip)
+ tgt_s3cmd s3://mybucket/backups/gitea-$today
+ }
+ finalise() {
+ systemctl start gitea.service
+ rm "${backups[@]}"
+ }
+
+ОКРУЖЕНИЕ
+---------
+
+LIBRARY
+ Если задана переменная окружения $LIBRARY, то её значение будет
+ использовано в качестве пути для поиска библиотеки **boring_backup**.
+
+СМ. ТАКЖЕ
+---------
+
+``bash``\(1), ``date``\(1), ``cp``\(1), ``tar``\(1), ``mysqldump``\(1),
+``pg_dump``\(1), ``s3cmd``\(1)
+
+RFC 3986 https://datatracker.ietf.org/doc/html/rfc3986
+
+ОШИБКИ
+------
+
+https://git.nxhs.cloud/ge/boring_backup/issues
diff --git a/src/boring-backup b/src/boring_backup
similarity index 58%
rename from src/boring-backup
rename to src/boring_backup
index 6512a78..a7e2f7a 100755
--- a/src/boring-backup
+++ b/src/boring_backup
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# boring-backup -- backup files and databases.
+# boring_backup -- backup files and databases.
# Copyright (c) 2022 ge
#
# This program is free software: you can redistribute it and/or modify
@@ -16,12 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-__version='0.1.0'
-__config=
-__verbose=
-__log_file='./log.txt'
-__pid_file='/tmp/boring-backup.pid'
-
+VERSION='0.1.0'
LIBRARY="${LIBRARY:-./lib}"
# Source library
@@ -30,24 +25,47 @@ if [ -f "$LIBRARY/lib.sh" ]; then
. "$LIBRARY/lib.sh"
else
echo "Error: Cannot source library $LIBRARY/lib.sh: No such file" >&2
+ __exit=1
fi
print_help() {
- cat <<- EOF
-Backup files and databases.
+ printf << EOF \
+"USAGE:
-Usage: $0 [-cvlphV] FILES..
+ $0 [-hVvs] [-c \033[4mfile\033[0m] [-l \033[4mfile\033[0m] \
+[-p \033[4mfile\033[0m] file ...
-Options:
- -c, --config config file.
- -v, --verbose verbose output.
- -l, --log-file log file [default: $__log_file]
- -p, --pid-file PID file [default: $__pid_file]
- -h, --help print this help messagea and exit.
- -V, --version print version and exit.
+OPTIONS:
-Environment:
- LIBRARY path to bb library [current: $LIBRARY]
+ -h, --help
+ Print this help message and exit.
+
+ -V, --version
+ Print version and exit.
+
+ -v, --verbose
+ Enable verbose output.
+
+ -c, --config=\033[4mfile\033[0m
+ Path to configuration file. Default: ~/.config/boring_backup
+ Configuration file actually is Bash-script similar to backup
+ script. See boring_backup(1) CONFIGURATION.
+
+ -l, --log-file=\033[4mfile\033[0m
+ Log file.
+
+ -s, --use-syslog
+ Write log into syslog via logger instead of log file. This option
+ is incompatible with --log-file option and log_date_format variable.
+
+ -p, --pid-file=\033[4mfile\033[0m
+ PID file. Default: /tmp/boring_backup.pid
+
+ENVIRONMENT:
+
+ LIBRARY Path to boring_backup library. Current path is
+ $LIBRARY
+"
EOF
}
@@ -88,33 +106,70 @@ for args in "$@"; do
shift
case "$args" in
--*)
- set -- "$@" "$args";; # save long options
+ set -- "$@" "$args" # save long options
+ ;;
-*)
- args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')"
+ args="$(echo "${args:1}" |
+ grep -o . | xargs -I {} echo -n '-{} ')"
# shellcheck disable=SC2086
- set -- "$@" $args;; # 'args' must be unquoted!
+ set -- "$@" $args # 'args' must be unquoted!
+ ;;
*)
- set -- "$@" "$args";; # save positional arguments
+ set -- "$@" "$args" # save positional arguments
+ ;;
esac
done
# Final arguments parser
while (( "$#" )); do
case "$1" in
+ -h|--help)
+ print_help
+ exit 0
+ ;;
+ -V|--version)
+ echo "$VERSION"
+ exit 0
+ ;;
+ -v|--verbose)
+ verbose_output=1
+ shift
+ ;;
-c|--config|--config=*)
- optval "$1" "$2"; __config="$val"; shift "$sft";;
- -v|--verbose) __verbose=1; shift;;
+ optval "$1" "$2"
+ bb_config="$val"
+ shift "$sft"
+ ;;
-l|--log-file|--log-file=*)
- optval "$1" "$2"; __log_file="$val"; shift "$sft";;
+ optval "$1" "$2"
+ log_file="$val"
+ shift "$sft"
+ ;;
+ -s|--use-syslog)
+ use_syslog=1
+ shift
+ ;;
-p|--pid-file|--pid-file=*)
- optval "$1" "$2"; __pid_file="$val"; shift "$sft";;
- -h|--help) print_help; exit 0;;
- -V|--version) echo "$__version"; exit 0;;
- -*) echo "Error: Unknown option: $1" >&2; exit 1;;
- *) __args+=("$1"); shift;; # Save positional args
+ optval "$1" "$2"
+ pid_file="$val"
+ shift "$sft"
+ ;;
+ -*)
+ echo "Error: Unknown option: $1" >&2
+ exit 1
+ ;;
+ *)
+ __args+=("$1") # Save positional args
+ shift
+ ;;
esac
done
+# -- Set defaults -- #
+log_file="${log_file:-./log.txt}"
+bb_config="${bb_config:-$HOME/.config/boring_backup}"
+pid_file="${pid_file:-/tmp/boring_backup.pid}"
+
# Exit if library is not loaded
if ! declare -F -- log > /dev/null 2>&1; then
exit 1
@@ -127,20 +182,20 @@ fi
log -V "Backup STARTED"
# Check PID file
-if [ -e "$__pid_file" ]; then
+if [ -e "$pid_file" ]; then
# shellcheck disable=SC2009
# shellcheck disable=SC2143
- if [ -z "$(ps ax -o pid | grep "$(cat "$__pid_file")")" ]; then
- log -p "Process $(cat "$__pid_file") died." >&2
- rm "$__pid_file"
+ if [ -z "$(ps ax -o pid | grep "$(cat "$pid_file")")" ]; then
+ log -p "Process $(cat "$pid_file") died." >&2
+ rm "$pid_file"
else
- echo "Process $(cat "$__pid_file") still running." >&2
+ echo "Process $(cat "$pid_file") still running." >&2
exit 1
fi
fi
# Touch PID file
-echo "$$" > "$__pid_file"
+echo "$$" > "$pid_file"
# Scripts counter.
__count="${#__args[@]}" # count
@@ -149,9 +204,12 @@ __i=1 # iterator
# Startup log.
date +'Start: %d %b %Y %T %z'
log -p "Library path: $LIBRARY"
-log -p "Log file: $__log_file"
-log -p "Configuration file:" \
- "$([ "$__config" ] || echo not specified && echo "$__config")"
+log -p "Log file: $log_file"
+log -p "Configuration file:" "$(\
+ if [ -f "$bb_config" ];
+ then echo "$bb_config";
+ else echo not specified;
+ fi)"
log -p "Total scripts: $__count"
log "Scripts to process (${__count}): ${__args[*]}"
@@ -171,7 +229,7 @@ for script in "${__args[@]}"; do
# Config can ovewrite script functions and variables
# shellcheck source=/dev/null
- [ -n "$__config" ] && . "$__config"
+ [ -f "$bb_config" ] && . "$bb_config"
# --- Run user script -- #
@@ -208,17 +266,10 @@ for script in "${__args[@]}"; do
# Unset user defined variables
unset compression
- unset name_prefix
- unset name_date_format
- unset s3cmd_options
- unset s3cmd_config
- unset s3_access_key
- unset s3_secret_key
- unset s3_region
- unset s3_host
- unset s3_host_bucket
- unset tar_options
- unset tar_exclude
+ unset name_prefix name_date_format name_prefix name_suffix
+ unset s3cmd_config s3cmd_options
+ unset s3_access_key s3_secret_key s3_region s3_host s3_host_bucket
+ unset tar_options tar_exclude
unset mysqldump_options
unset pg_dump_options
done
@@ -227,4 +278,6 @@ echo -e "\nBackup [Done]"
log -V "Backup FINISHED"
# Remove PID file
-rm "$__pid_file"
+rm "$pid_file"
+
+exit "${__exit:-0}"
diff --git a/src/lib/handlers/targets/s3cmd.sh b/src/lib/handlers/targets/s3cmd.sh
index 2be2cbd..097a865 100644
--- a/src/lib/handlers/targets/s3cmd.sh
+++ b/src/lib/handlers/targets/s3cmd.sh
@@ -25,7 +25,6 @@ tgt_s3cmd() {
log "Run handler ${FUNCNAME[0]}()"
local uri
- local src_path
uri="$1"
@@ -44,7 +43,7 @@ tgt_s3cmd() {
# Set s3cmd comand. See s3cmd(1)
if [ -n "$s3cmd_config" ]; then
# Use configuration file
- # shellcheck disable=SC2154
+ # shellcheck disable=SC2154,SC2086
set -- s3cmd $s3cmd_options --config "$s3cmd_config" \
put "${backups[@]}" "$uri"
elif [ -n "$s3_access_key" ] && \
@@ -54,7 +53,7 @@ tgt_s3cmd() {
then
s3_region="${s3_region:-na}" # fallback to 'no available' region
# Use parameters provided from backup script
- # shellcheck disable=SC2154
+ # shellcheck disable=SC2154,SC2086
set -- s3cmd $s3cmd_options \
--access_key="$s3_access_key" \
--secret_key="$s3_secret_key" \
@@ -74,6 +73,7 @@ tgt_s3cmd() {
# ^^^ hide secret_key from output ^^^
# Upload backups
+ # shellcheck disable=SC2154
if "$@" 2>> "$__log_file"; then
: # Success
else