feat: Add variable name_suffix; Pass shellcheck; Discard useless variables from main script
This commit is contained in:
		
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							@@ -23,8 +23,10 @@ tests:
 | 
				
			|||||||
	for test in $(tests_dir)/*.bats; do bats --verbose-run --print-output-on-failure "$$test"; done
 | 
						for test in $(tests_dir)/*.bats; do bats --verbose-run --print-output-on-failure "$$test"; done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lint:
 | 
					lint:
 | 
				
			||||||
	shellcheck $(src_dir)/boring-backup || true
 | 
						shellcheck $(src_dir)/boring-backup
 | 
				
			||||||
	shellcheck $(src_dir)/lib/* || true
 | 
						shellcheck $(src_dir)/lib/*.sh
 | 
				
			||||||
 | 
						shellcheck $(src_dir)/lib/handlers/sources/*.sh
 | 
				
			||||||
 | 
						shellcheck $(src_dir)/lib/handlers/targets/*.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
docs: builddir
 | 
					docs: builddir
 | 
				
			||||||
	# See rst2man(1), rst2html(1), https://docutils.sourceforge.io/docs/index.html
 | 
						# See rst2man(1), rst2html(1), https://docutils.sourceforge.io/docs/index.html
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ backup files and databases.
 | 
				
			|||||||
Описание
 | 
					Описание
 | 
				
			||||||
--------
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
boring-backup - это расширяемая утилита для резервного копирования на основе сценариев Bash. По умолчанию предусмотрено создание резервных копий файлов с помощью ``tar`` и дампов баз данных MySQL/MariaDB и PostgreSQL.
 | 
					boring-backup - это расширяемая утилита для резервного копирования на основе сценариев Bash.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Опции
 | 
					Опции
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
@@ -35,28 +35,26 @@ boring-backup - это расширяемая утилита для резерв
 | 
				
			|||||||
Быстрый старт
 | 
					Быстрый старт
 | 
				
			||||||
-------------
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
boring-backup можно рассматривать как небольшой фреймворк/библиотеку для создания сценариев резервного копирования. boring-backup не реализует собственный язык сценариев, а полагается на Bash. В любом варианте применения утилита требует написания сценария для выполнения бэкапа.
 | 
					boring-backup можно рассматривать как фреймворк или библиотеку для создания сценариев резервного копирования. Сценарии должны содержать валидный код на Bash. Сценарий импортируется в основной скрипт с помощью команды ``source`` (см. ``bash``\(1) п. SHELL BUILTIN COMMANDS).
 | 
				
			||||||
 | 
					 | 
				
			||||||
В сценариях можно использовать переменные и функции. Сценарий импортируется в основной скрипт с помощью команды ``source`` (см. ``bash``\(1) п. SHELL BUILTIN COMMANDS).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Простейший сценарий резервного копирования выглядит следующим образом::
 | 
					Простейший сценарий резервного копирования выглядит следующим образом::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sources=('file:/home/user')
 | 
					    sources=('file:/home/user')
 | 
				
			||||||
    targets=('file:/var/backup')
 | 
					    targets=('file:/var/backup')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Здесь массивы `sources` и `targets` определяют точки или поинты (`points`) резервного копирования — источники (`sources`) и назначения (`targets`). Это основные сущности, с которыми работает boring-backup. Вот некоторые особенности поинтов:
 | 
					Здесь массивы `sources` и `targets` определяют точки, они же поинты (`points`) резервного копирования: источники (`sources`) и назначения (`targets`). Это основные сущности, с которыми работает boring-backup. Вот некоторые особенности поинтов:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Все поинты указываются в формате URI. Описание URI также есть в этой документации ниже.
 | 
					- Все поинты указываются в формате URI.
 | 
				
			||||||
- Поинты могут указывать как на локальные (размещённые на текущей машине), так и на удалённые (размещённые на удалённой машине) ресурсы.
 | 
					- Поинты могут указывать как на локальные (размещённые на текущей машине), так и на удалённые (размещённые на удалённой машине) ресурсы.
 | 
				
			||||||
- Можно указать как несколько источников, так и несколько назначений.
 | 
					- Можно указать как несколько источников, так и несколько назначений.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Для выполнения бэкапа директорий или отдельных файлов применяется схема URI `file`. В схеме `file` нельзя указать директорию, размещённую на удалённом хранилище (за исключением случая, когда удалённое хранилище примонтировано как файловая система), для этого используйте другие схемы. В примере выше будет выполнена резервная копия локальной директории /home/user в другую локальную директорию /var/backup. Поскольку в сценарии из примера нет ничего, кроме указания точек `sources` и `targets`, бэкап будет выполнен с параметрами по умолчанию: директория /home/user будет заархивирована с помощью утилиты ``tar``\(1), архив будет сжат с помощью утилиты ``gzip``\(1) и помещён в директорию /var/backup. Имя архива будет сложено из строки::
 | 
					Для выполнения бэкапа директорий или отдельных файлов применяется схема URI `file`. В схеме `file` нельзя указать директорию, размещённую на удалённом хранилище (за исключением случая, когда удалённое хранилище примонтировано как файловая система), для этого используйте другие схемы. В примере выше будет выполнена резервная копия локальной директории /home/user в другую локальную директорию /var/backup. Поскольку в сценарии из примера нет ничего, кроме указания точек `sources` и `targets`, бэкап будет выполнен с параметрами по умолчанию: директория /home/user будет заархивирована с помощью утилиты ``tar``\(1) и помещён в директорию /var/backup. Имя архива будет сложено из строки::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ${prefix}${name}${date_fmt}${name_ext}
 | 
					    ${name_prefix}${name}${name_date_fmt}${name_suffix}${name_ext}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Описание переменных см. в разделе ПЕРЕМЕННЫЕ. Пример имени файла:: 
 | 
					Описание переменных см. в разделе ПЕРЕМЕННЫЕ. Пример имени файла:: 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    example.sh_example_20220515-0953.tar.gz
 | 
					    example.sh_example_2022.05.15-0953.tar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Обзор URI
 | 
					Обзор URI
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
@@ -101,8 +99,9 @@ Perl 5::
 | 
				
			|||||||
``````````````````````````````````````````````````
 | 
					``````````````````````````````````````````````````
 | 
				
			||||||
 | 
					
 | 
				
			||||||
file
 | 
					file
 | 
				
			||||||
    Может содержать путь к локальному файлу или директории. Файлы архивируются при помощи ``tar`` и по умолчанию сжимаются с помощью ``gzip``. Примеры::
 | 
					    Может содержать путь к локальному файлу или директории. Файлы архивируются при помощи ``tar`` и по умолчанию не сжимаются. Cжатие архива может быть включено через переменную `compression`. Примеры::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /var/www/www-root/data
 | 
				
			||||||
        file:/var/www/html
 | 
					        file:/var/www/html
 | 
				
			||||||
        file:///home/jhon/cool_stuff.txt
 | 
					        file:///home/jhon/cool_stuff.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,17 +114,17 @@ mysql
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        mysql://[username[:password]@]hostname[:port]/database
 | 
					        mysql://[username[:password]@]hostname[:port]/database
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    С помощью утилиты ``mysqldump``\(1) формируется дамп в формате SQL, файл по умолчанию сжимается утилитой ``gzip``.
 | 
					    С помощью утилиты ``mysqldump``\(1) формируется дамп в формате SQL. Файл по умолчанию не сжимается, но сжатие может быть включено через переменную `compression`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    См. также ``handler::mysqldump``
 | 
					    См. также ``handler::mysqldump``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
postgres
 | 
					postgres
 | 
				
			||||||
    Аналогично `mysql`, но для PostgreSQL. Для создания дампа используется ``pg_dump``\(1), файлы по умолчанию сохраняются с расширением .psql.gz.
 | 
					    Аналогично `mysql`, но для PostgreSQL. Для создания дампа используется ``pg_dump``\(1) с расширением .psql. Файл по умолчанию не сжимается, но сжатие может быть включено через переменную `compression`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    См. также ``handler::pg_dump``
 | 
					    См. также ``handler::pg_dump``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sqlite
 | 
					sqlite
 | 
				
			||||||
    Схема для баз данных SQLite. Ничем не отличается от `file`, добавлена для наглядного обозначения, что источником является БД SQLite, а не иной файл.
 | 
					    Схема для баз данных SQLite. Мало отличается от `file`, добавлена для наглядного обозначения, что источником является БД SQLite, а не иной файл.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    См. также ``handler::sqlite``
 | 
					    См. также ``handler::sqlite``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,7 +132,7 @@ sqlite
 | 
				
			|||||||
``````````````````````````````````````````````````
 | 
					``````````````````````````````````````````````````
 | 
				
			||||||
 | 
					
 | 
				
			||||||
file
 | 
					file
 | 
				
			||||||
    В контексте `targets` указывает директорию для сохранения бэкапов. В массиве `targets` обязательно должен быть хотя бы один поинт со схемой `file`. Этот поинт будет использован как основной и сохранён в переменные ``__main_target`` (содержит URI) и ``__main_target_path`` (path). Если в массиве присутствует несколько поинтов со схемой `file`, то в качестве основного будет выбран первый по порядку поинт. Все бэкапы первоначально будут сохраняться в директорию ``__main_target_path`` и затем копироваться в другой таргет с помощью соответствующего обработчика. В случае копировани из одной директории в другую используется утилита ``cp``\(1).
 | 
					    В контексте `targets` указывает директорию для сохранения бэкапов. В массиве `targets` обязательно должен быть хотя бы один поинт со схемой `file`. Этот поинт будет использован как основной и сохранён в переменные ``__main_target`` (содержит URI) и ``__main_target_path`` (содержит компонент URI path). Если в массиве присутствует несколько поинтов со схемой `file`, то в качестве основного будет выбран первый по порядку поинт. Все бэкапы первоначально будут сохраняться в директорию ``__main_target_path`` и затем копироваться в другой таргет с помощью соответствующего обработчика. В случае копировани из одной директории в другую используется утилита ``cp``\(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Избегайте указания в одном сценарии таргетов, которые ведут одновременно на примонтированный к локальной машине сетевой диск и другое удалённое хранилище. В таком случае архивы будут создаваться на сетевом диске и далее снова копироваться по сети, что будет очень медленно.
 | 
					    Избегайте указания в одном сценарии таргетов, которые ведут одновременно на примонтированный к локальной машине сетевой диск и другое удалённое хранилище. В таком случае архивы будут создаваться на сетевом диске и далее снова копироваться по сети, что будет очень медленно.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -165,11 +164,11 @@ dav, davs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
boring-backup предполагает, что для всех резервных копий необходимо создавать архивы. Поэтому вам нужно следить за тем, чтобы в локальном хранилище всегда хватало дискового пространства для создания новых архивов. boring-backup также не удаляет старые архивы и вам также надо позаботиться об удалении устаревших резервных копий. Изменить это поведение можно с помощью пользовательских функций в сценариях. В этом разделе речь пойдёт о поведении, которое установлено по умолчанию. См. функции ``builtin_backup``, ``process_sources``, ``process_targets``.
 | 
					boring-backup предполагает, что для всех резервных копий необходимо создавать архивы. Поэтому вам нужно следить за тем, чтобы в локальном хранилище всегда хватало дискового пространства для создания новых архивов. boring-backup также не удаляет старые архивы и вам также надо позаботиться об удалении устаревших резервных копий. Изменить это поведение можно с помощью пользовательских функций в сценариях. В этом разделе речь пойдёт о поведении, которое установлено по умолчанию. См. функции ``builtin_backup``, ``process_sources``, ``process_targets``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Базовая концепция строится на том, что существует несколько точек источников и несколько точек назначения. Создаётся резервная копия источника и копируется в точку назначения.
 | 
					Базовая концепция строится на том, что существует несколько источников и несколько точек назначения. Создаётся резервная копия источника и копируется в точку назначения.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Для всех источников в сценарии выполняется локальная резервная копия. После этого локальная копия переносится в удалённые точки назначения, если они заданы. Копирование локального бэкапа будет осуществлёно столько раз, сколько точек назначения задано. В каждом сценарии обязательно должен быть задан хотя бы один источник и одна точка назначения. При этом в списке точек назначения обязательно должна присутствовать точка со схемой `file`. Именно в неё будут сохранены архивы.
 | 
					Для всех источников в сценарии выполняется локальная резервная копия. После этого локальная копия переносится в удалённые точки назначения, если они заданы. Копирование локального бэкапа будет осуществлёно столько раз, сколько точек назначения задано. В каждом сценарии обязательно должен быть задан хотя бы один источник и одна точка назначения. При этом в списке точек назначения обязательно должна присутствовать точка со схемой `file`. Именно в неё будут сохранены архивы.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Пример. Имеется следующий сценарий::
 | 
					Например, имеется следующий сценарий::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sources=(
 | 
					    sources=(
 | 
				
			||||||
        'mysql://wordpress:1jobrRRjtLYs@localhost/wordpress'
 | 
					        'mysql://wordpress:1jobrRRjtLYs@localhost/wordpress'
 | 
				
			||||||
@@ -212,80 +211,89 @@ WebDAV
 | 
				
			|||||||
``backups``
 | 
					``backups``
 | 
				
			||||||
    Массив со списком созданных бэкапов. Содержит абсолютные пути к файлам. Заполняется функциями-обработчиками `sources`.
 | 
					    Массив со списком созданных бэкапов. Содержит абсолютные пути к файлам. Заполняется функциями-обработчиками `sources`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: массив
 | 
					    | Тип: массив
 | 
				
			||||||
    Умолчание: ()
 | 
					    | Умолчание: ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``errors``
 | 
					``errors``
 | 
				
			||||||
    Массив с текстами ошибок. Заполняется функцией ``err`` с опцией ``-a``.
 | 
					    Массив с текстами ошибок. Заполняется функцией ``err`` с опцией ``-a``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: массив
 | 
					    | Тип: массив
 | 
				
			||||||
    Умолчание: ()
 | 
					    | Умолчание: ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``log_date_fmt``
 | 
					``log_date_fmt``
 | 
				
			||||||
    Формат даты в логе. См. ``date``\(1).
 | 
					    Формат даты в логе. См. ``date``\(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: %d/%b/%Y:%H:%M:%S %z
 | 
					    | Умолчание: %d/%b/%Y:%H:%M:%S %z
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``name_prefix``
 | 
					``name_prefix``
 | 
				
			||||||
    Префикс имени файла. Может быть задан в скрипте.
 | 
					    Префикс имени файла. Может быть задан в скрипте.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: имя_скрипта\_
 | 
					    | Умолчание: имя_скрипта\_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``name``
 | 
					``name``
 | 
				
			||||||
    Соответствует имени архивируемой директории/файла полученного из `path` с помощью утилиты ``basename``\(1).
 | 
					    Соответствует имени архивируемой директории/файла полученного из `path` с помощью утилиты ``basename``\(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: нет
 | 
					    | Умолчание: нет
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``name_date_fmt``
 | 
					``name_date_fmt``
 | 
				
			||||||
    Дата, интерпретируемая утилитой ``date``\(1).
 | 
					    Дата, интерпретируемая утилитой ``date``\(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: _%Y%m%d-%H%M
 | 
					    | Умолчание: _%Y%m%d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``name_suffix``
 | 
				
			||||||
 | 
					    Суффикс, добавляемый к имени файла перед расширением. Строка интерпретируется утилитой ``date``.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    | Тип: строка
 | 
				
			||||||
 | 
					    | Умолчание: -%H%M
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``name_ext``
 | 
					``name_ext``
 | 
				
			||||||
    Расширение имени файла, соответствующее формату архива.
 | 
					    Расширение имени файла, соответствующее формату архива.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: .tar.gz
 | 
					    | Умолчание: .tar.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``tar_options``
 | 
					``tar_options``
 | 
				
			||||||
    Опции ``tar``. См. ``tar``\(1).
 | 
					    Опции ``tar``. См. ``tar``\(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: строка
 | 
					    | Тип: строка
 | 
				
			||||||
    Умолчание: -acf
 | 
					    | Умолчание: -acf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``tar_exclude``
 | 
					``tar_exclude``
 | 
				
			||||||
    Список имён для опции ``tar`` ``--exclude``.
 | 
					    Список имён для опции ``tar`` ``--exclude``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Тип: массив
 | 
					    | Тип: массив
 | 
				
			||||||
    Умолчание: нет
 | 
					    | Умолчание: нет
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``compression``
 | 
					``compression``
 | 
				
			||||||
    В контексте ``tar`` работа этой фичи базируется на опции ``tar`` ``--auto-compress``. Переменная может принимать значения, в соответствии с табилцей ниже. Если переменная имеет значение, отличное от перечисленныых, то будет использован ``gzip``.
 | 
					    В контексте ``tar`` работа этой фичи базируется на опции ``tar`` ``--auto-compress``. Переменная может принимать значения, в соответствии с табилцей ниже. Если переменная имеет значение, отличное от перечисленныых, то будет использован ``gzip``. Если переменная пуста или не задана, то сжатие будет отключено.
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    ======================== ================ ========
 | 
					    | Тип: строка
 | 
				
			||||||
    Значение tar_compression Расширение файла Утилита
 | 
					    | Умолчание: нет
 | 
				
			||||||
    ======================== ================ ========
 | 
					
 | 
				
			||||||
    gzip, gz                 .tar.gz          gzip
 | 
					    ==================== ================ ========
 | 
				
			||||||
    tgz                      .tgz             gzip
 | 
					    Значение compression Расширение файла Утилита
 | 
				
			||||||
    taz                      .taz             gzip
 | 
					    ==================== ================ ========
 | 
				
			||||||
    compress, Z              .tar.Z           compress
 | 
					    gzip, gz             .tar.gz          gzip
 | 
				
			||||||
    taZ                      .taZ             compress
 | 
					    tgz                  .tgz             gzip
 | 
				
			||||||
    bzip2, bz2               .tar.bz2         bzip2
 | 
					    taz                  .taz             gzip
 | 
				
			||||||
    tz2                      .tz2             bzip2
 | 
					    compress, Z          .tar.Z           compress
 | 
				
			||||||
    tbz2                     .tbz2            bzip2
 | 
					    taZ                  .taZ             compress
 | 
				
			||||||
    tbz                      .tbz             bzip2
 | 
					    bzip2, bz2           .tar.bz2         bzip2
 | 
				
			||||||
    lzip, lz                 .tar.lz          lzip
 | 
					    tz2                  .tz2             bzip2
 | 
				
			||||||
    lzma                     .tar.lzma        lzma
 | 
					    tbz2                 .tbz2            bzip2
 | 
				
			||||||
    tlz                      .tlz             lzma
 | 
					    tbz                  .tbz             bzip2
 | 
				
			||||||
    lzop, lzo                .tar.lzo         lzop
 | 
					    lzip, lz             .tar.lz          lzip
 | 
				
			||||||
    xz                       .tar.xz          xz
 | 
					    lzma                 .tar.lzma        lzma
 | 
				
			||||||
    zstd, zst                .tar.zst         zstd
 | 
					    tlz                  .tlz             lzma
 | 
				
			||||||
    tzst                     .tzst            zstd
 | 
					    lzop, lzo            .tar.lzo         lzop
 | 
				
			||||||
    ======================== ================ ========
 | 
					    xz                   .tar.xz          xz
 | 
				
			||||||
 | 
					    zstd, zst            .tar.zst         zstd
 | 
				
			||||||
 | 
					    tzst                 .tzst            zstd
 | 
				
			||||||
 | 
					    ==================== ================ ========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Функции
 | 
					Функции
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,21 +20,17 @@ __version='0.0.0'
 | 
				
			|||||||
__config=
 | 
					__config=
 | 
				
			||||||
__verbose=
 | 
					__verbose=
 | 
				
			||||||
__log_file='./log.txt'
 | 
					__log_file='./log.txt'
 | 
				
			||||||
__log_date_fmt='%d/%b/%Y:%H:%M:%S %z'
 | 
					 | 
				
			||||||
__pid_file='/tmp/boring-backup.pid'
 | 
					__pid_file='/tmp/boring-backup.pid'
 | 
				
			||||||
__tar_options='-acf'
 | 
					 | 
				
			||||||
__tar_exclude=
 | 
					 | 
				
			||||||
__name_date_fmt='_%Y%m%d-%H%M'
 | 
					 | 
				
			||||||
__compression=
 | 
					 | 
				
			||||||
__errors_count=0
 | 
					__errors_count=0
 | 
				
			||||||
__errors_file='/tmp/boring-backup.errors'
 | 
					__errors_file='/tmp/boring-backup.errors'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo $__errors_count > $__errors_file
 | 
					echo "$__errors_count" > "$__errors_file"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LIBRARY="${LIBRARY:-./lib}"
 | 
					LIBRARY="${LIBRARY:-./lib}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Source library
 | 
					# Source library
 | 
				
			||||||
if [ -f "$LIBRARY/lib.sh" ]; then
 | 
					if [ -f "$LIBRARY/lib.sh" ]; then
 | 
				
			||||||
 | 
					    # shellcheck disable=SC1091
 | 
				
			||||||
    . "$LIBRARY/lib.sh"
 | 
					    . "$LIBRARY/lib.sh"
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
    echo "Error: Cannot source library from $LIBRARY" >&2
 | 
					    echo "Error: Cannot source library from $LIBRARY" >&2
 | 
				
			||||||
@@ -69,7 +65,7 @@ optval() {
 | 
				
			|||||||
    #
 | 
					    #
 | 
				
			||||||
    # Parse --opt VAL and --opt=VAL options.
 | 
					    # Parse --opt VAL and --opt=VAL options.
 | 
				
			||||||
    # Requires 2 arguments: $1, $2.
 | 
					    # Requires 2 arguments: $1, $2.
 | 
				
			||||||
    # Return variables:
 | 
					    # Set variables:
 | 
				
			||||||
    #   opt     option name.
 | 
					    #   opt     option name.
 | 
				
			||||||
    #   val     option value.
 | 
					    #   val     option value.
 | 
				
			||||||
    #   sft     value for shift.
 | 
					    #   sft     value for shift.
 | 
				
			||||||
@@ -96,7 +92,8 @@ for args in "$@"; do
 | 
				
			|||||||
            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 '-{} ')"
 | 
				
			||||||
            set -- "$@" $args;;
 | 
					            # shellcheck disable=SC2086
 | 
				
			||||||
 | 
					            set -- "$@" $args;; # 'args' must be unquoted!
 | 
				
			||||||
        *)
 | 
					        *)
 | 
				
			||||||
            set -- "$@" "$args";;  # save positional arguments
 | 
					            set -- "$@" "$args";;  # save positional arguments
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
@@ -123,20 +120,22 @@ done
 | 
				
			|||||||
log "Backup STARTED"
 | 
					log "Backup STARTED"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check PID file
 | 
					# Check PID file
 | 
				
			||||||
if [ -e $__pid_file ]; then
 | 
					if [ -e "$__pid_file" ]; then
 | 
				
			||||||
    if [ -z "$(ps ax -o pid | grep "$(cat $__pid_file)")" ]; then
 | 
					    # shellcheck disable=SC2009
 | 
				
			||||||
        err "Process $(cat $__pid_file) died."
 | 
					    # shellcheck disable=SC2143
 | 
				
			||||||
        rm $__pid_file
 | 
					    if [ -z "$(ps ax -o pid | grep "$(cat "$__pid_file")")" ]; then
 | 
				
			||||||
 | 
					        err "Process $(cat "$__pid_file") died."
 | 
				
			||||||
 | 
					        rm "$__pid_file"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        err -e "Process $(cat $__pid_file) still running.";
 | 
					        err -e "Process $(cat "$__pid_file") still running.";
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Touch PID file
 | 
					# Touch PID file
 | 
				
			||||||
echo $$ > $__pid_file
 | 
					echo "$$" > "$__pid_file"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Scripts counter.
 | 
					# Scripts counter.
 | 
				
			||||||
__count=${#__args[@]}    # count
 | 
					__count="${#__args[@]}"  # count
 | 
				
			||||||
__iter=1                 # iterator
 | 
					__iter=1                 # iterator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Startup log.
 | 
					# Startup log.
 | 
				
			||||||
@@ -144,18 +143,22 @@ date +'Start: %d %b %Y %T %z'
 | 
				
			|||||||
log -p "Library path: $LIBRARY"
 | 
					log -p "Library path: $LIBRARY"
 | 
				
			||||||
log -p "Log file: $__log_file"
 | 
					log -p "Log file: $__log_file"
 | 
				
			||||||
log -p "Configuration file: $([ "$__config" ] || echo not specified && echo "$__config")"
 | 
					log -p "Configuration file: $([ "$__config" ] || echo not specified && echo "$__config")"
 | 
				
			||||||
log "Scripts to process (${__count}): ${__args[@]}"
 | 
					log "Scripts to process (${__count}): ${__args[*]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for script in "${__args[@]}"; do
 | 
					for script in "${__args[@]}"; do
 | 
				
			||||||
    # Initialise variables
 | 
					    # Initialise variables
 | 
				
			||||||
    __user_script="$script"
 | 
					    __user_script="$script"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2034
 | 
				
			||||||
    backups=()  # Array of created backups, contains full pathes
 | 
					    backups=()  # Array of created backups, contains full pathes
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2034
 | 
				
			||||||
    errors=()   # Array of error messages written by err() function
 | 
					    errors=()   # Array of error messages written by err() function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Source scripts
 | 
					    # Source scripts
 | 
				
			||||||
    source_script "$script"
 | 
					    source_script "$script"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Config can ovewrite script functions and variables
 | 
					    # Config can ovewrite script functions and variables
 | 
				
			||||||
 | 
					    # shellcheck source=/dev/null
 | 
				
			||||||
    [ -n "$__config" ] && . "$__config"
 | 
					    [ -n "$__config" ] && . "$__config"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo
 | 
					    echo
 | 
				
			||||||
@@ -209,7 +212,7 @@ if [[ "$(cat $__errors_file)" != '0' ]]; then
 | 
				
			|||||||
    echo
 | 
					    echo
 | 
				
			||||||
    log -p "Backup [Failed]: Process finished with $(cat $__errors_file) errors."\
 | 
					    log -p "Backup [Failed]: Process finished with $(cat $__errors_file) errors."\
 | 
				
			||||||
        "See $__log_file for info."
 | 
					        "See $__log_file for info."
 | 
				
			||||||
    rm $__errors_file
 | 
					    rm "$__errors_file"
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
    echo -e "\nBackup [Done]"
 | 
					    echo -e "\nBackup [Done]"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
@@ -217,4 +220,4 @@ fi
 | 
				
			|||||||
log "Backup FINISHED"
 | 
					log "Backup FINISHED"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Remove PID file
 | 
					# Remove PID file
 | 
				
			||||||
rm $__pid_file
 | 
					rm "$__pid_file"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,9 @@ process_source() {
 | 
				
			|||||||
        mysql)  handler='handler::mysqldump';;
 | 
					        mysql)  handler='handler::mysqldump';;
 | 
				
			||||||
        postgres) handler='handler::pg_dump';;
 | 
					        postgres) handler='handler::pg_dump';;
 | 
				
			||||||
        sqlite) handler='handler::sqlite';;
 | 
					        sqlite) handler='handler::sqlite';;
 | 
				
			||||||
        *) echo "Error: $__user_script: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
					        *)  # shellcheck disable=SC2154
 | 
				
			||||||
 | 
					            # '__user_script' is assigned in main script.
 | 
				
			||||||
 | 
					            echo "Error: $__user_script: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Run handler function
 | 
					    # Run handler function
 | 
				
			||||||
@@ -84,10 +86,12 @@ builtin_backup() {
 | 
				
			|||||||
    #
 | 
					    #
 | 
				
			||||||
    # Usage: builtin_backup
 | 
					    # Usage: builtin_backup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    for source in "${sources[@]}"; do
 | 
					    for source in "${sources[@]}"; do
 | 
				
			||||||
        process_source "$source"
 | 
					        process_source "$source"
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    for target in "${targets[@]}"; do
 | 
					    for target in "${targets[@]}"; do
 | 
				
			||||||
        process_target "$target"
 | 
					        process_target "$target"
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
@@ -102,21 +106,15 @@ gen_backup_name() {
 | 
				
			|||||||
    #
 | 
					    #
 | 
				
			||||||
    # Usage: gen_backup_name NAME_EXT
 | 
					    # Usage: gen_backup_name NAME_EXT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    local prefix
 | 
					 | 
				
			||||||
    local name
 | 
					    local name
 | 
				
			||||||
    local date_fmt
 | 
					 | 
				
			||||||
    local name_ext
 | 
					    local name_ext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [ -n "$name_prefix" ] || { prefix="${__user_script}_"; }
 | 
					    name_prefix="${name_prefix:-${__user_script}_}"
 | 
				
			||||||
    name="$(basename $path)" # 'path' is variable parsed from URI
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
 | 
					    name="$(basename "$path")" # 'path' is variable parsed from URI
 | 
				
			||||||
    name_ext="$1"
 | 
					    name_ext="$1"
 | 
				
			||||||
 | 
					    name_date_fmt="${name_date_fmt:-_%Y.%m.%d}"
 | 
				
			||||||
 | 
					    name_suffix="${name_suffix:--%H%M}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Overwrite __name_date_fmt
 | 
					    date +"${name_prefix}${name}${name_date_fmt}${name_suffix}${name_ext}"
 | 
				
			||||||
    if [ -n "$name_date_fmt" ]; then
 | 
					 | 
				
			||||||
        date_fmt="$name_date_fmt"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        date_fmt="$__name_date_fmt"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    date +"${prefix}${name}${date_fmt}${name_ext}"
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ log() {
 | 
				
			|||||||
    [[ ! -t 0 ]] || [[ "$#" == 0 ]] && message="$(cat <&0)"
 | 
					    [[ ! -t 0 ]] || [[ "$#" == 0 ]] && message="$(cat <&0)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Set log date format
 | 
					    # Set log date format
 | 
				
			||||||
    [ "$log_date_fmt" ] || log_date_fmt="$__log_date_fmt"
 | 
					    log_date_fmt="${log_date_fmt:-%d/%b/%Y:%H:%M:%S %z}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (( "$#" )); do
 | 
					    while (( "$#" )); do
 | 
				
			||||||
        case "$1" in
 | 
					        case "$1" in
 | 
				
			||||||
@@ -44,7 +44,8 @@ log() {
 | 
				
			|||||||
    [[ "$print" == 1 ]] && echo -e "$message"
 | 
					    [[ "$print" == 1 ]] && echo -e "$message"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while read -r line; do
 | 
					    while read -r line; do
 | 
				
			||||||
        if [[ "$line" ]]; then
 | 
					        if [ -n "$line" ]; then
 | 
				
			||||||
 | 
					            # shellcheck disable=SC2154
 | 
				
			||||||
            printf '[%s] %s\n' "$(date +"$log_date_fmt")" "$line" >> "$__log_file"
 | 
					            printf '[%s] %s\n' "$(date +"$log_date_fmt")" "$line" >> "$__log_file"
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
    done <<< "$(sed -r 's/\x1B\[(([0-9]+)(;[0-9]+)*)?[m,K,H,f,J]//g' <<< "$message")"
 | 
					    done <<< "$(sed -r 's/\x1B\[(([0-9]+)(;[0-9]+)*)?[m,K,H,f,J]//g' <<< "$message")"
 | 
				
			||||||
@@ -69,7 +70,8 @@ err() {
 | 
				
			|||||||
        case "$args" in
 | 
					        case "$args" in
 | 
				
			||||||
            -*)
 | 
					            -*)
 | 
				
			||||||
                args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')"
 | 
					                args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')"
 | 
				
			||||||
                set -- "$@" $args;;
 | 
					                # shellcheck disable=SC2086
 | 
				
			||||||
 | 
					                set -- "$@" $args;; # 'args' must be unquoted!
 | 
				
			||||||
            *)
 | 
					            *)
 | 
				
			||||||
                set -- "$@" "$args";;  # save positional arguments
 | 
					                set -- "$@" "$args";;  # save positional arguments
 | 
				
			||||||
        esac
 | 
					        esac
 | 
				
			||||||
@@ -100,9 +102,10 @@ err() {
 | 
				
			|||||||
    # Exit
 | 
					    # Exit
 | 
				
			||||||
    if [ "$errexit" ]; then
 | 
					    if [ "$errexit" ]; then
 | 
				
			||||||
        # Count errors for backup recap
 | 
					        # Count errors for backup recap
 | 
				
			||||||
        __errors_count="$(cat $__errors_file)"
 | 
					        # shellcheck disable=SC2154
 | 
				
			||||||
 | 
					        __errors_count="$(cat "$__errors_file")"
 | 
				
			||||||
        ((__errors_count++)) || true
 | 
					        ((__errors_count++)) || true
 | 
				
			||||||
        echo $__errors_count > "$__errors_file"
 | 
					        echo "$__errors_count" > "$__errors_file"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log -p "Backup ERROR: Exiting with previous errors" >&2; exit 1
 | 
					        log -p "Backup ERROR: Exiting with previous errors" >&2; exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
@@ -113,7 +116,8 @@ try() {
 | 
				
			|||||||
    #
 | 
					    #
 | 
				
			||||||
    # Usage: try COMMAND
 | 
					    # Usage: try COMMAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if eval "$@" 2>> "$__log_file"; then
 | 
					    # https://www.shellcheck.net/wiki/SC2294
 | 
				
			||||||
 | 
					    if "$@" 2>> "$__log_file"; then
 | 
				
			||||||
        return 0 # Success
 | 
					        return 0 # Success
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        # Count errors
 | 
					        # Count errors
 | 
				
			||||||
@@ -168,6 +172,11 @@ set_compression() {
 | 
				
			|||||||
        xz)         file_ext='.xz';      compr_util='xz';;
 | 
					        xz)         file_ext='.xz';      compr_util='xz';;
 | 
				
			||||||
        zstd|zst)   file_ext='.zst';     compr_util='zstd';;
 | 
					        zstd|zst)   file_ext='.zst';     compr_util='zstd';;
 | 
				
			||||||
        tzst)       file_ext='.zst';     compr_util='zstd';;
 | 
					        tzst)       file_ext='.zst';     compr_util='zstd';;
 | 
				
			||||||
        *)          file_ext='';        compr_util='';;  # No compression
 | 
					        *)  # No compression
 | 
				
			||||||
 | 
					            # shellcheck disable=SC2034
 | 
				
			||||||
 | 
					            file_ext=''
 | 
				
			||||||
 | 
					            # shellcheck disable=SC2034
 | 
				
			||||||
 | 
					            compr_util=''
 | 
				
			||||||
 | 
					            ;;
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,12 +32,14 @@ handler::mysqldump() {
 | 
				
			|||||||
    local file_ext
 | 
					    local file_ext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uri="$1"
 | 
					    uri="$1"
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    dst_path="$__main_target_path"
 | 
					    dst_path="$__main_target_path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parse_uri "$uri"
 | 
					    parse_uri "$uri"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [ -z "$port" ] && port=3306  # Set default MySQL port.
 | 
					    [ -z "$port" ] && port=3306  # Set default MySQL port.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    [ -n "$__verbose" ] && echo "Dumping database '${path##*/}'"\
 | 
					    [ -n "$__verbose" ] && echo "Dumping database '${path##*/}'"\
 | 
				
			||||||
        "owned by ${username}@${hostname} ..." | log -p
 | 
					        "owned by ${username}@${hostname} ..." | log -p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,7 +63,10 @@ handler::mysqldump() {
 | 
				
			|||||||
        compr_cmd="cat"
 | 
					        compr_cmd="cat"
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mysqldump_opts="${mysqldump_opts:-}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # NOTE! mysqldump_opts and compr_cmd variables must be unquoted!
 | 
					    # NOTE! mysqldump_opts and compr_cmd variables must be unquoted!
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2086,SC2154
 | 
				
			||||||
    try mysqldump $mysqldump_opts \
 | 
					    try mysqldump $mysqldump_opts \
 | 
				
			||||||
        --host="$hostname" \
 | 
					        --host="$hostname" \
 | 
				
			||||||
        --port="$port" \
 | 
					        --port="$port" \
 | 
				
			||||||
@@ -76,33 +81,32 @@ handler::mysqldump() {
 | 
				
			|||||||
    fi
 | 
					    fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# POSTGRESQL vvv
 | 
					# POSTGRESQL
 | 
				
			||||||
 | 
					#bk_dump_postgresql() {
 | 
				
			||||||
bk_dump_postgresql() {
 | 
					#    # Do PostgreSQL dump.
 | 
				
			||||||
    # Do PostgreSQL dump.
 | 
					#
 | 
				
			||||||
 | 
					#    bk_log "Dumping database '${path##*/}' owned by ${user}@${host} (PostgreSQL) ..."
 | 
				
			||||||
    bk_log "Dumping database '${path##*/}' owned by ${user}@${host} (PostgreSQL) ..."
 | 
					#
 | 
				
			||||||
 | 
					#    dump_name="$entry_local"/"$(bk_get_name "$db_name" .psql.gz)"
 | 
				
			||||||
    dump_name="$entry_local"/"$(bk_get_name "$db_name" .psql.gz)"
 | 
					#    [ "$port" ] || port=5432  # Set default PostgreSQL port.
 | 
				
			||||||
    [ "$port" ] || port=5432  # Set default PostgreSQL port.
 | 
					#    export PGPASSWORD="$password"
 | 
				
			||||||
    export PGPASSWORD="$password"
 | 
					#
 | 
				
			||||||
 | 
					#    pg_dump \
 | 
				
			||||||
    pg_dump \
 | 
					#        --host="$host" \
 | 
				
			||||||
        --host="$host" \
 | 
					#        --port="$port" \
 | 
				
			||||||
        --port="$port" \
 | 
					#        --dbname="${path##*/}" \
 | 
				
			||||||
        --dbname="${path##*/}" \
 | 
					#        --username="$user" \
 | 
				
			||||||
        --username="$user" \
 | 
					#        --no-password | gzip -c > "$dump_name" |& bk_log
 | 
				
			||||||
        --no-password | gzip -c > "$dump_name" |& bk_log
 | 
					#
 | 
				
			||||||
 | 
					#    unset PGPASSWORD
 | 
				
			||||||
    unset PGPASSWORD
 | 
					#
 | 
				
			||||||
 | 
					#    if [ -s "$dump_name" ]; then
 | 
				
			||||||
    if [ -s "$dump_name" ]; then
 | 
					#        bk_log "Dumping database '${path##*/}' owned by ${user}@${host} (PostgreSQL) [Done]"
 | 
				
			||||||
        bk_log "Dumping database '${path##*/}' owned by ${user}@${host} (PostgreSQL) [Done]"
 | 
					#        bk_log "Dump saved as: $dump_name"
 | 
				
			||||||
        bk_log "Dump saved as: $dump_name"
 | 
					#        bk_upload_file "$dump_name"
 | 
				
			||||||
        bk_upload_file "$dump_name"
 | 
					#
 | 
				
			||||||
 | 
					#    else
 | 
				
			||||||
    else
 | 
					#        rm "$dump_name"
 | 
				
			||||||
        rm "$dump_name"
 | 
					#        bk_err "Something went wrong. Dump size is 0 bytes. Removing $dump_name"
 | 
				
			||||||
        bk_err "Something went wrong. Dump size is 0 bytes. Removing $dump_name"
 | 
					#    fi
 | 
				
			||||||
    fi
 | 
					#}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,16 +26,17 @@ handler::tar() {
 | 
				
			|||||||
    local uri
 | 
					    local uri
 | 
				
			||||||
    local src_path
 | 
					    local src_path
 | 
				
			||||||
    local dst_path
 | 
					    local dst_path
 | 
				
			||||||
    local opts
 | 
					 | 
				
			||||||
    local archive
 | 
					    local archive
 | 
				
			||||||
    local exclude
 | 
					    local exclude
 | 
				
			||||||
    local file_ext
 | 
					    local file_ext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uri="$1"
 | 
					    uri="$1"
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    dst_path="$__main_target_path"
 | 
					    dst_path="$__main_target_path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parse_uri "$uri"
 | 
					    parse_uri "$uri"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    if [ -f "$path" ] || [ -d "$path" ]; then
 | 
					    if [ -f "$path" ] || [ -d "$path" ]; then
 | 
				
			||||||
        src_path="$path"
 | 
					        src_path="$path"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
@@ -51,15 +52,8 @@ handler::tar() {
 | 
				
			|||||||
    # Exit if tar is not installed
 | 
					    # Exit if tar is not installed
 | 
				
			||||||
    is_installed tar
 | 
					    is_installed tar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Overwrire __tar_options
 | 
					    # Set tar_exclude
 | 
				
			||||||
    if [ -n "$tar_options" ]; then
 | 
					    if [ -n "$tar_exclude" ]; then
 | 
				
			||||||
        opts="$tar_options"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        opts="$__tar_options"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Overwrite __tar_exclude
 | 
					 | 
				
			||||||
    if [ "$tar_exclude" ]; then
 | 
					 | 
				
			||||||
        for item in "${tar_exclude[@]}"; do
 | 
					        for item in "${tar_exclude[@]}"; do
 | 
				
			||||||
            exclude+=" --exclude $item"
 | 
					            exclude+=" --exclude $item"
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
@@ -67,6 +61,9 @@ handler::tar() {
 | 
				
			|||||||
        exclude=
 | 
					        exclude=
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Set options
 | 
				
			||||||
 | 
					    tar_options="${tar_options:--acf}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Select filename extension by compression type.
 | 
					    # Select filename extension by compression type.
 | 
				
			||||||
    if [ "$compression" ]; then
 | 
					    if [ "$compression" ]; then
 | 
				
			||||||
        # Make sure for the `--auto-compress` is enabled in __tar_options
 | 
					        # Make sure for the `--auto-compress` is enabled in __tar_options
 | 
				
			||||||
@@ -99,14 +96,14 @@ handler::tar() {
 | 
				
			|||||||
    [ "$__verbose" ] && {
 | 
					    [ "$__verbose" ] && {
 | 
				
			||||||
        echo "Source path: $src_path"
 | 
					        echo "Source path: $src_path"
 | 
				
			||||||
        echo "Destination path: $dst_path"
 | 
					        echo "Destination path: $dst_path"
 | 
				
			||||||
        echo "Run command: tar $exclude $opts $archive $src_path"
 | 
					        echo "Run command: tar $exclude $tar_options $archive $src_path"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log "Archiving $src_path to $archive ..."
 | 
					    log "Archiving $src_path to $archive ..."
 | 
				
			||||||
    log "Run command: tar $exclude $opts $archive $src_path"
 | 
					    log "Run command: tar $exclude $tar_options $archive $src_path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Run tar
 | 
					    # Run tar
 | 
				
			||||||
    try tar "$exclude" "$opts" "$archive" "$src_path"
 | 
					    try tar "$exclude" "$tar_options" "$archive" "$src_path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Append path to 'backups' array
 | 
					    # Append path to 'backups' array
 | 
				
			||||||
    backups+=("$archive")
 | 
					    backups+=("$archive")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ handler::cp() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    uri="$1"
 | 
					    uri="$1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shellcheck disable=SC2154
 | 
				
			||||||
    if [[ "$uri" == "$__main_target" ]]; then
 | 
					    if [[ "$uri" == "$__main_target" ]]; then
 | 
				
			||||||
        : # Do nothing. Source and destination is the same
 | 
					        : # Do nothing. Source and destination is the same
 | 
				
			||||||
        log "Nothing to do: Source and destination is the same: $__main_target"
 | 
					        log "Nothing to do: Source and destination is the same: $__main_target"
 | 
				
			||||||
@@ -36,6 +37,7 @@ handler::cp() {
 | 
				
			|||||||
        # Copy backups to another destination
 | 
					        # Copy backups to another destination
 | 
				
			||||||
        parse_uri "$uri"
 | 
					        parse_uri "$uri"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # shellcheck disable=SC2154
 | 
				
			||||||
        if [ -f "$path" ] || [ -d "$path" ]; then
 | 
					        if [ -f "$path" ] || [ -d "$path" ]; then
 | 
				
			||||||
            dst_path="$path"
 | 
					            dst_path="$path"
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
@@ -46,6 +48,7 @@ handler::cp() {
 | 
				
			|||||||
        [ "$__verbose" ] && echo "Destination path: $dst_path"
 | 
					        [ "$__verbose" ] && echo "Destination path: $dst_path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Copy files preserving metadata
 | 
					        # Copy files preserving metadata
 | 
				
			||||||
 | 
					        # shellcheck disable=SC2154
 | 
				
			||||||
        for backup in "${backups[@]}"; do
 | 
					        for backup in "${backups[@]}"; do
 | 
				
			||||||
            log "Copying file $backup to $dst_path ..."
 | 
					            log "Copying file $backup to $dst_path ..."
 | 
				
			||||||
            log "Run command: cp --archive $backup $dst_path"
 | 
					            log "Run command: cp --archive $backup $dst_path"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					# shellcheck disable=SC1091
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# lib.sh - source scripts.
 | 
					# lib.sh - source scripts.
 | 
				
			||||||
# Copyright (c) 2022 ge <https://nixhacks.net/>
 | 
					# Copyright (c) 2022 ge <https://nixhacks.net/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,8 @@ validate_sources() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        case "$scheme" in
 | 
					        case "$scheme" in
 | 
				
			||||||
            file|mysql|postgres|sqlite) : ;; # do nothing, this is OK
 | 
					            file|mysql|postgres|sqlite) : ;; # do nothing, this is OK
 | 
				
			||||||
            *) echo "Error: $__user_script: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
					            *)  # shellcheck disable=SC2154
 | 
				
			||||||
 | 
					                echo "Error: $__user_script: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
				
			||||||
        esac
 | 
					        esac
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -78,6 +79,7 @@ validate_targets() {
 | 
				
			|||||||
        __main_target="${file_targets[0]}"
 | 
					        __main_target="${file_targets[0]}"
 | 
				
			||||||
        # Fail if __main_target's path is not a directory
 | 
					        # Fail if __main_target's path is not a directory
 | 
				
			||||||
        parse_uri "$__main_target"
 | 
					        parse_uri "$__main_target"
 | 
				
			||||||
 | 
					        # shellcheck disable=SC2154
 | 
				
			||||||
        if [ -d "$path" ]; then
 | 
					        if [ -d "$path" ]; then
 | 
				
			||||||
            __main_target_path="$path"
 | 
					            __main_target_path="$path"
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
@@ -99,24 +101,25 @@ source_script() {
 | 
				
			|||||||
        echo "Error: No such file: $script" >&2; exit 1
 | 
					        echo "Error: No such file: $script" >&2; exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Dry run script, check syntax. See set(1p)
 | 
					    # Dry run script, check syntax. See manpage set(1)
 | 
				
			||||||
    if ! bash -n "$script"; then
 | 
					    if ! bash -n "$script"; then
 | 
				
			||||||
        echo Error: $__user_script: Please check your syntax >&2; exit 1
 | 
					        echo "Error: $__user_script: Please check your syntax" >&2; exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Source script
 | 
					    # Source script
 | 
				
			||||||
    . "$@"
 | 
					    # shellcheck disable=SC1090
 | 
				
			||||||
 | 
					    . "$script"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Check required variables
 | 
					    # Check required variables
 | 
				
			||||||
    if [[ "$sources" ]]; then
 | 
					    if [ -n "$sources" ]; then
 | 
				
			||||||
        validate_sources "${sources[@]}"
 | 
					        validate_sources "${sources[@]}"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        echo Error: $__user_script: sources array is not set >&2; exit 1
 | 
					        echo "Error: $__user_script: sources array is not set" >&2; exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if [[ "$targets" ]]; then
 | 
					    if [ -n "$targets" ]; then
 | 
				
			||||||
        validate_targets "${targets[@]}"
 | 
					        validate_targets "${targets[@]}"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        echo Error: $__user_script: targets array is not set >&2; exit 1
 | 
					        echo "Error: $__user_script: targets array is not set" >&2; exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ parse_uri() {
 | 
				
			|||||||
    # URL-encoded passwords supported.
 | 
					    # URL-encoded passwords supported.
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    # Usage: parse_uri URI
 | 
					    # Usage: parse_uri URI
 | 
				
			||||||
    # Return variables:
 | 
					    # Set variables:
 | 
				
			||||||
    #   scheme
 | 
					    #   scheme
 | 
				
			||||||
    #   username
 | 
					    #   username
 | 
				
			||||||
    #   password
 | 
					    #   password
 | 
				
			||||||
@@ -113,6 +113,7 @@ parse_uri() {
 | 
				
			|||||||
            port=
 | 
					            port=
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
 | 
					        # shellcheck disable=SC2034
 | 
				
			||||||
        hostname="$host"
 | 
					        hostname="$host"
 | 
				
			||||||
        port=
 | 
					        port=
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
@@ -122,6 +123,7 @@ parse_uri() {
 | 
				
			|||||||
        username="${userinfo%:*}"
 | 
					        username="${userinfo%:*}"
 | 
				
			||||||
        password="${userinfo#*:}"
 | 
					        password="${userinfo#*:}"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
 | 
					        # shellcheck disable=SC2034
 | 
				
			||||||
        username="$userinfo"
 | 
					        username="$userinfo"
 | 
				
			||||||
        password=
 | 
					        password=
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user