dar-backup 0.6.11__py3-none-any.whl → 0.6.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dar_backup/__about__.py +1 -1
- dar_backup/clean_log.py +1 -1
- dar_backup/cleanup.py +1 -1
- dar_backup/config_settings.py +34 -11
- dar_backup/dar-backup.conf +33 -0
- dar_backup/dar_backup.py +32 -24
- dar_backup/installer.py +129 -0
- dar_backup/manager.py +1 -1
- {dar_backup-0.6.11.dist-info → dar_backup-0.6.12.dist-info}/METADATA +41 -114
- dar_backup-0.6.12.dist-info/RECORD +16 -0
- {dar_backup-0.6.11.dist-info → dar_backup-0.6.12.dist-info}/entry_points.txt +1 -0
- dar_backup-0.6.11.dist-info/RECORD +0 -14
- {dar_backup-0.6.11.dist-info → dar_backup-0.6.12.dist-info}/WHEEL +0 -0
- {dar_backup-0.6.11.dist-info → dar_backup-0.6.12.dist-info}/licenses/LICENSE +0 -0
dar_backup/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.6.
|
|
1
|
+
__version__ = "0.6.12"
|
dar_backup/clean_log.py
CHANGED
|
@@ -122,7 +122,7 @@ def main():
|
|
|
122
122
|
|
|
123
123
|
args = parser.parse_args()
|
|
124
124
|
|
|
125
|
-
config_settings = ConfigSettings(os.path.expanduser(args.config_file))
|
|
125
|
+
config_settings = ConfigSettings(os.path.expanduser(os.path.expandvars(args.config_file)))
|
|
126
126
|
|
|
127
127
|
if not args.file:
|
|
128
128
|
args.file = [config_settings.logfile_location]
|
dar_backup/cleanup.py
CHANGED
|
@@ -171,7 +171,7 @@ def main():
|
|
|
171
171
|
parser.add_argument('--log-stdout', action='store_true', help='also print log messages to stdout')
|
|
172
172
|
args = parser.parse_args()
|
|
173
173
|
|
|
174
|
-
args.config_file = os.path.expanduser(args.config_file)
|
|
174
|
+
args.config_file = os.path.expanduser(os.path.expandvars(args.config_file))
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
if args.version:
|
dar_backup/config_settings.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import configparser
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
import sys
|
|
5
3
|
import logging
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass, field, fields
|
|
7
|
+
from os.path import expandvars, expanduser
|
|
8
|
+
from pathlib import Path
|
|
6
9
|
|
|
7
10
|
@dataclass
|
|
8
11
|
class ConfigSettings:
|
|
@@ -20,21 +23,35 @@ class ConfigSettings:
|
|
|
20
23
|
backup_d_dir (str): The directory for backup.d.
|
|
21
24
|
diff_age (int): The age for differential backups before deletion.
|
|
22
25
|
incr_age (int): The age for incremental backups before deletion.
|
|
26
|
+
error_correction_percent (int): The error correction percentage for PAR2.
|
|
27
|
+
par2_enabled (bool): Whether PAR2 is enabled.
|
|
23
28
|
"""
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
config_file: str
|
|
31
|
+
logfile_location: str = field(init=False)
|
|
32
|
+
max_size_verification_mb: int = field(init=False)
|
|
33
|
+
min_size_verification_mb: int = field(init=False)
|
|
34
|
+
no_files_verification: int = field(init=False)
|
|
35
|
+
command_timeout_secs: int = field(init=False)
|
|
36
|
+
backup_dir: str = field(init=False)
|
|
37
|
+
test_restore_dir: str = field(init=False)
|
|
38
|
+
backup_d_dir: str = field(init=False)
|
|
39
|
+
diff_age: int = field(init=False)
|
|
40
|
+
incr_age: int = field(init=False)
|
|
41
|
+
error_correction_percent: int = field(init=False)
|
|
42
|
+
par2_enabled: bool = field(init=False)
|
|
43
|
+
|
|
44
|
+
def __post_init__(self):
|
|
26
45
|
"""
|
|
27
|
-
Initializes the ConfigSettings instance by reading the specified configuration file
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
config_file (str): The path to the configuration file.
|
|
46
|
+
Initializes the ConfigSettings instance by reading the specified configuration file
|
|
47
|
+
and expands environment variables for all string fields.
|
|
31
48
|
"""
|
|
32
|
-
if config_file is None:
|
|
49
|
+
if self.config_file is None:
|
|
33
50
|
raise ValueError("`config_file` must be specified.")
|
|
34
51
|
|
|
35
52
|
self.config = configparser.ConfigParser()
|
|
36
53
|
try:
|
|
37
|
-
self.config.read(config_file)
|
|
54
|
+
self.config.read(self.config_file)
|
|
38
55
|
self.logfile_location = self.config['MISC']['LOGFILE_LOCATION']
|
|
39
56
|
self.max_size_verification_mb = int(self.config['MISC']['MAX_SIZE_VERIFICATION_MB'])
|
|
40
57
|
self.min_size_verification_mb = int(self.config['MISC']['MIN_SIZE_VERIFICATION_MB'])
|
|
@@ -46,12 +63,18 @@ class ConfigSettings:
|
|
|
46
63
|
self.diff_age = int(self.config['AGE']['DIFF_AGE'])
|
|
47
64
|
self.incr_age = int(self.config['AGE']['INCR_AGE'])
|
|
48
65
|
self.error_correction_percent = int(self.config['PAR2']['ERROR_CORRECTION_PERCENT'])
|
|
49
|
-
self.par2_enabled =
|
|
66
|
+
self.par2_enabled = self.config['PAR2']['ENABLED'].lower() in ('true', '1', 'yes')
|
|
67
|
+
|
|
50
68
|
# Ensure the directories exist
|
|
51
69
|
Path(self.backup_dir).mkdir(parents=True, exist_ok=True)
|
|
52
70
|
Path(self.test_restore_dir).mkdir(parents=True, exist_ok=True)
|
|
53
71
|
Path(self.backup_d_dir).mkdir(parents=True, exist_ok=True)
|
|
54
72
|
|
|
73
|
+
# Expand environment variables for all string fields
|
|
74
|
+
for field in fields(self):
|
|
75
|
+
if isinstance(getattr(self, field.name), str):
|
|
76
|
+
setattr(self, field.name, expanduser(expandvars(getattr(self, field.name))))
|
|
77
|
+
|
|
55
78
|
except FileNotFoundError as e:
|
|
56
79
|
logging.error(f"Configuration file not found: {self.config_file}")
|
|
57
80
|
logging.error(f"Error details: {e}")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This config file is intended to demo `dar-backup`.
|
|
2
|
+
#
|
|
3
|
+
# The `installer` puts it in ~/.config/dar-backup/dar-backup.conf
|
|
4
|
+
|
|
5
|
+
[MISC]
|
|
6
|
+
LOGFILE_LOCATION = ~/dar-backup/dar-backup.log
|
|
7
|
+
MAX_SIZE_VERIFICATION_MB = 20
|
|
8
|
+
MIN_SIZE_VERIFICATION_MB = 1
|
|
9
|
+
NO_FILES_VERIFICATION = 5
|
|
10
|
+
# timeout in seconds for backup, test, restore and par2 operations
|
|
11
|
+
# The author has such `dar` tasks running for 10-15 hours on the yearly backups, so a value of 24 hours is used.
|
|
12
|
+
# If a timeout is not specified when using the util.run_command(), a default timeout of 30 secs is used.
|
|
13
|
+
COMMAND_TIMEOUT_SECS = 86400
|
|
14
|
+
|
|
15
|
+
[DIRECTORIES]
|
|
16
|
+
BACKUP_DIR = ~/dar-backup/backups
|
|
17
|
+
BACKUP.D_DIR = ~/.config/dar-backup/backup.d/
|
|
18
|
+
TEST_RESTORE_DIR = ~/dar-backup/restore/
|
|
19
|
+
|
|
20
|
+
[AGE]
|
|
21
|
+
# age settings are in days
|
|
22
|
+
DIFF_AGE = 100
|
|
23
|
+
INCR_AGE = 40
|
|
24
|
+
|
|
25
|
+
[PAR2]
|
|
26
|
+
ERROR_CORRECTION_PERCENT = 5
|
|
27
|
+
ENABLED = True
|
|
28
|
+
|
|
29
|
+
[PREREQ]
|
|
30
|
+
#SCRIPT_1 = <pre-script 1>
|
|
31
|
+
|
|
32
|
+
[POSTREQ]
|
|
33
|
+
#SCRIPT_1 = <post-script 1>
|
dar_backup/dar_backup.py
CHANGED
|
@@ -8,13 +8,16 @@ import random
|
|
|
8
8
|
import re
|
|
9
9
|
import shlex
|
|
10
10
|
import subprocess
|
|
11
|
-
import sys
|
|
12
11
|
import xml.etree.ElementTree as ET
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
from argparse import ArgumentParser
|
|
16
15
|
from datetime import datetime
|
|
17
16
|
from pathlib import Path
|
|
17
|
+
from sys import exit
|
|
18
|
+
from sys import stderr
|
|
19
|
+
from sys import argv
|
|
20
|
+
from sys import version_info
|
|
18
21
|
from time import time
|
|
19
22
|
from typing import List
|
|
20
23
|
|
|
@@ -407,7 +410,7 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
|
|
|
407
410
|
logger.info(f"Using alternate reference archive: {latest_base_backup}")
|
|
408
411
|
if not os.path.exists(latest_base_backup + '.1.dar'):
|
|
409
412
|
logger.error(f"Alternate reference archive: \"{latest_base_backup}.1.dar\" does not exist, exiting.")
|
|
410
|
-
|
|
413
|
+
exit(1)
|
|
411
414
|
else:
|
|
412
415
|
base_backups = sorted(
|
|
413
416
|
[f for f in os.listdir(config_settings.backup_dir) if f.startswith(f"{backup_definition}_{base_backup_type}_") and f.endswith('.1.dar')],
|
|
@@ -492,7 +495,7 @@ def generate_par2_files(backup_file: str, config_settings: ConfigSettings, args)
|
|
|
492
495
|
|
|
493
496
|
|
|
494
497
|
def show_version():
|
|
495
|
-
script_name = os.path.basename(
|
|
498
|
+
script_name = os.path.basename(argv[0])
|
|
496
499
|
print(f"{script_name} {about.__version__}")
|
|
497
500
|
print(f"dar-backup.py source code is here: https://github.com/per2jensen/dar-backup")
|
|
498
501
|
print('''Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
|
|
@@ -580,9 +583,9 @@ def main():
|
|
|
580
583
|
global logger
|
|
581
584
|
|
|
582
585
|
MIN_PYTHON_VERSION = (3, 9)
|
|
583
|
-
if
|
|
584
|
-
|
|
585
|
-
|
|
586
|
+
if version_info < MIN_PYTHON_VERSION:
|
|
587
|
+
stderr.write(f"Error: This script requires Python {'.'.join(map(str, MIN_PYTHON_VERSION))} or higher.\n")
|
|
588
|
+
exit(1)
|
|
586
589
|
|
|
587
590
|
parser = argparse.ArgumentParser(description="Backup and verify using dar backup definitions.")
|
|
588
591
|
parser.add_argument('-F', '--full-backup', action='store_true', help="Perform a full backup.")
|
|
@@ -606,15 +609,25 @@ def main():
|
|
|
606
609
|
parser.add_argument('-v', '--version', action='store_true', help="Show version and license information.")
|
|
607
610
|
args = parser.parse_args()
|
|
608
611
|
|
|
609
|
-
args.config_file = os.path.expanduser(args.config_file)
|
|
610
|
-
config_settings = ConfigSettings(args.config_file)
|
|
611
|
-
|
|
612
612
|
if args.version:
|
|
613
613
|
show_version()
|
|
614
|
-
|
|
614
|
+
exit(0)
|
|
615
615
|
elif args.examples:
|
|
616
616
|
show_examples()
|
|
617
|
-
|
|
617
|
+
exit(0)
|
|
618
|
+
|
|
619
|
+
if not args.config_file:
|
|
620
|
+
print(f"Config file not specified, exiting", file=stderr)
|
|
621
|
+
exit(1)
|
|
622
|
+
|
|
623
|
+
config_settings_path = os.path.expanduser(os.path.expandvars(args.config_file))
|
|
624
|
+
if not os.path.exists(config_settings_path):
|
|
625
|
+
print(f"Config file {args.config_file} does not exist.", file=stderr)
|
|
626
|
+
exit(127)
|
|
627
|
+
|
|
628
|
+
args.config_file = config_settings_path
|
|
629
|
+
config_settings = ConfigSettings(args.config_file)
|
|
630
|
+
|
|
618
631
|
|
|
619
632
|
logger = setup_logging(config_settings.logfile_location, args.log_level, args.log_stdout)
|
|
620
633
|
|
|
@@ -622,18 +635,13 @@ def main():
|
|
|
622
635
|
current_script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
623
636
|
args.darrc = os.path.join(current_script_dir, ".darrc")
|
|
624
637
|
|
|
625
|
-
|
|
638
|
+
darrc_file = os.path.expanduser(os.path.expandvars(args.darrc))
|
|
639
|
+
if os.path.exists(darrc_file) and os.path.isfile(darrc_file):
|
|
626
640
|
logger.debug(f"Using .darrc: {args.darrc}")
|
|
627
641
|
else:
|
|
628
|
-
logger.error(f"Supplied .darrc: '{args.darrc}' does not exist or is not a file")
|
|
642
|
+
logger.error(f"Supplied .darrc: '{args.darrc}' does not exist or is not a file, exiting", file=stderr)
|
|
643
|
+
exit(127)
|
|
629
644
|
|
|
630
|
-
if not args.config_file:
|
|
631
|
-
logger.error(f"Config file not specified, exiting")
|
|
632
|
-
sys.exit(1)
|
|
633
|
-
|
|
634
|
-
if not os.path.exists(args.config_file):
|
|
635
|
-
logger.error(f"Config file {args.config_file} does not exist.")
|
|
636
|
-
sys.exit(1)
|
|
637
645
|
|
|
638
646
|
|
|
639
647
|
try:
|
|
@@ -668,10 +676,10 @@ def main():
|
|
|
668
676
|
# sanity check
|
|
669
677
|
if args.backup_definition and not os.path.exists(os.path.join(config_settings.backup_d_dir, args.backup_definition)):
|
|
670
678
|
logger.error(f"Backup definition: '{args.backup_definition}' does not exist, exiting")
|
|
671
|
-
|
|
679
|
+
exit(127)
|
|
672
680
|
if args.backup_definition and '_' in args.backup_definition:
|
|
673
681
|
logger.error(f"Backup definition: '{args.backup_definition}' contains '_', exiting")
|
|
674
|
-
|
|
682
|
+
exit(1)
|
|
675
683
|
|
|
676
684
|
|
|
677
685
|
requirements('PREREQ', config_settings)
|
|
@@ -695,12 +703,12 @@ def main():
|
|
|
695
703
|
requirements('POSTREQ', config_settings)
|
|
696
704
|
|
|
697
705
|
args.verbose and print("\033[1m\033[32mSUCCESS\033[0m No errors encountered")
|
|
698
|
-
|
|
706
|
+
exit(0)
|
|
699
707
|
except Exception as e:
|
|
700
708
|
logger.exception("An error occurred")
|
|
701
709
|
logger.error("Exception details:", exc_info=True)
|
|
702
710
|
args.verbose and print("\033[1m\033[31mErrors\033[0m encountered")
|
|
703
|
-
|
|
711
|
+
exit(1)
|
|
704
712
|
finally:
|
|
705
713
|
end_time=int(time())
|
|
706
714
|
logger.info(f"END TIME: {end_time}")
|
dar_backup/installer.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
installer.py source code is here: https://github.com/per2jensen/dar-backup/tree/main/v2/src/dar_backup/installer.py
|
|
4
|
+
This script is part of dar-backup, a backup solution for Linux using dar and systemd.
|
|
5
|
+
|
|
6
|
+
Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
|
|
7
|
+
|
|
8
|
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW,
|
|
9
|
+
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
10
|
+
See section 15 and section 16 in the supplied "LICENSE" file
|
|
11
|
+
|
|
12
|
+
This script can be used to configure dar-backup on your system.
|
|
13
|
+
It is non-destructive and will not overwrite any existing files or directories.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
from . import __about__ as about
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
LICENSE = '''Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
|
|
25
|
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
26
|
+
See section 15 and section 16 in the supplied "LICENSE" file.'''
|
|
27
|
+
|
|
28
|
+
CONFIG_DIR = os.path.expanduser("~/.config/dar-backup")
|
|
29
|
+
DAR_BACKUP_DIR = os.path.expanduser("~/dar-backup/")
|
|
30
|
+
|
|
31
|
+
BACKUP_DEFINITION = '''
|
|
32
|
+
# Demo of a `dar-backup` definition file
|
|
33
|
+
# This back definition file configures a backup of ~/.config/dar-backup
|
|
34
|
+
# `dar-backup` puts the backups in ~/dar-backup/backups
|
|
35
|
+
# ------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
# Switch to ordered selection mode, which means that the following options
|
|
38
|
+
# will be considered top to bottom
|
|
39
|
+
-am
|
|
40
|
+
|
|
41
|
+
# Backup Root dir
|
|
42
|
+
-R @@HOME_DIR@@
|
|
43
|
+
|
|
44
|
+
# Directories to backup below the Root dir
|
|
45
|
+
-g .config/dar-backup
|
|
46
|
+
|
|
47
|
+
# Examples of directories to exclude below the Root dir
|
|
48
|
+
-P mnt
|
|
49
|
+
-P .private
|
|
50
|
+
-P .cache
|
|
51
|
+
|
|
52
|
+
# compression level
|
|
53
|
+
-z5
|
|
54
|
+
|
|
55
|
+
# no overwrite, if you rerun a backup, 'dar' halts and asks what to do
|
|
56
|
+
-n
|
|
57
|
+
|
|
58
|
+
# size of each slice in the archive
|
|
59
|
+
--slice 10G
|
|
60
|
+
|
|
61
|
+
# bypass directores marked as cache directories
|
|
62
|
+
# http://dar.linux.free.fr/doc/Features.html
|
|
63
|
+
--cache-directory-tagging
|
|
64
|
+
'''
|
|
65
|
+
|
|
66
|
+
def main():
|
|
67
|
+
parser = argparse.ArgumentParser(
|
|
68
|
+
description="Set up `dar-backup` on your system.",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"-i", "--install",
|
|
72
|
+
action="store_true",
|
|
73
|
+
help="Deploy a simple config file, use ~/dar-backup/ for log file, archives and restore tests."
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--dry-run",
|
|
78
|
+
action="store_true",
|
|
79
|
+
help="Show which lines would be removed without modifying the file."
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"-v", "--version",
|
|
85
|
+
action="version",
|
|
86
|
+
version=f"%(prog)s version {about.__version__}, {LICENSE}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
args = parser.parse_args()
|
|
90
|
+
|
|
91
|
+
if args.install:
|
|
92
|
+
errors = []
|
|
93
|
+
if os.path.exists(CONFIG_DIR):
|
|
94
|
+
errors.append(f"Config directory '{CONFIG_DIR}' already exists.")
|
|
95
|
+
|
|
96
|
+
if os.path.exists(DAR_BACKUP_DIR):
|
|
97
|
+
errors.append(f"Directory '{DAR_BACKUP_DIR}' already exists.")
|
|
98
|
+
|
|
99
|
+
if len(errors) > 0:
|
|
100
|
+
for error in errors:
|
|
101
|
+
print(f"Error: {error}")
|
|
102
|
+
sys.exit(1)
|
|
103
|
+
|
|
104
|
+
os.makedirs(DAR_BACKUP_DIR, exist_ok=False)
|
|
105
|
+
os.makedirs(os.path.join(DAR_BACKUP_DIR, "backups"), exist_ok=False)
|
|
106
|
+
os.makedirs(os.path.join(DAR_BACKUP_DIR, "restore"), exist_ok=False)
|
|
107
|
+
os.makedirs(CONFIG_DIR, exist_ok=False)
|
|
108
|
+
os.makedirs(os.path.join(CONFIG_DIR, "backup.d"), exist_ok=False)
|
|
109
|
+
print(f"Directories created: `{DAR_BACKUP_DIR}` and `{CONFIG_DIR}`")
|
|
110
|
+
|
|
111
|
+
script_dir = Path(__file__).parent
|
|
112
|
+
source_file = script_dir / "dar-backup.conf"
|
|
113
|
+
destination_file = Path(CONFIG_DIR) / "dar-backup.conf"
|
|
114
|
+
shutil.copy(source_file, destination_file)
|
|
115
|
+
print(f"Config file deployed to {destination_file}")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
backup_definition = BACKUP_DEFINITION.replace("@@HOME_DIR@@", os.path.expanduser("~"))
|
|
119
|
+
with open(os.path.join(CONFIG_DIR, "backup.d", "default"), "w") as f:
|
|
120
|
+
f.write(backup_definition)
|
|
121
|
+
print(f"Default backup definition file deployed to {os.path.join(CONFIG_DIR, 'backup.d', 'default')}")
|
|
122
|
+
print("1. Now run `manager --create` to create the catalog database.")
|
|
123
|
+
print("2. Then you can run `dar-backup --full-backup` to create a backup.")
|
|
124
|
+
print("3. List backups with `dar-backup --list`")
|
|
125
|
+
print("4. List contents of a backup with `dar-backup --list-contents <backup-name>`")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
if __name__ == "__main__":
|
|
129
|
+
main()
|
dar_backup/manager.py
CHANGED
|
@@ -395,7 +395,7 @@ See section 15 and section 16 in the supplied "LICENSE" file.''')
|
|
|
395
395
|
sys.exit(0)
|
|
396
396
|
|
|
397
397
|
# setup logging
|
|
398
|
-
args.config_file = os.path.expanduser(args.config_file)
|
|
398
|
+
args.config_file = os.path.expanduser(os.path.expandvars(args.config_file))
|
|
399
399
|
config_settings = ConfigSettings(args.config_file)
|
|
400
400
|
if not os.path.dirname(config_settings.logfile_location):
|
|
401
401
|
print(f"Directory for log file '{config_settings.logfile_location}' does not exist, exiting")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dar-backup
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.12
|
|
4
4
|
Summary: A script to do full, differential and incremental backups using dar. Some files are restored from the backups during verification, after which par2 redundancy files are created. The script also has a cleanup feature to remove old backups and par2 files.
|
|
5
5
|
Project-URL: Homepage, https://github.com/per2jensen/dar-backup/tree/main/v2
|
|
6
6
|
Project-URL: Changelog, https://github.com/per2jensen/dar-backup/blob/main/v2/Changelog.md
|
|
@@ -705,19 +705,18 @@ Description-Content-Type: text/markdown
|
|
|
705
705
|
- [Homepage - Github](#homepage---github)
|
|
706
706
|
- [Requirements](#requirements)
|
|
707
707
|
- [Config file](#config-file)
|
|
708
|
-
- [How to
|
|
709
|
-
- [1 -
|
|
710
|
-
- [2 -
|
|
711
|
-
- [3 -
|
|
712
|
-
- [4 -
|
|
713
|
-
- [5 -
|
|
714
|
-
- [6 - deactivate venv](#6---deactivate-venv)
|
|
708
|
+
- [How to run](#how-to-run)
|
|
709
|
+
- [1 - installation](#1---installation)
|
|
710
|
+
- [2 - configuration](#2---configuration)
|
|
711
|
+
- [3 - generate catalog databases](#3---generate-catalog-databases)
|
|
712
|
+
- [4 - do FULL backups](#4---do-full-backups)
|
|
713
|
+
- [5 - deactivate venv](#5---deactivate-venv)
|
|
715
714
|
- [.darrc](#darrc)
|
|
716
715
|
- [Systemctl examples](#systemctl-examples)
|
|
717
716
|
- [Service: dar-back --incremental-backup](#service-dar-back---incremental-backup)
|
|
718
717
|
- [Timer: dar-back --incremental-backup](#timer-dar-back---incremental-backup)
|
|
719
718
|
- [List contents of an archive](#list-contents-of-an-archive)
|
|
720
|
-
- [dar file selection examples](#dar-file-selection-
|
|
719
|
+
- [dar file selection examples](#dar-file-selection-examples)
|
|
721
720
|
- [Select a directory](#select-a-directory)
|
|
722
721
|
- [Select file dates in the directory](#select-file-dates-in-the-directory)
|
|
723
722
|
- [Exclude .xmp files from that date](#exclude-xmp-files-from-that-date)
|
|
@@ -798,105 +797,9 @@ On Ubuntu, install the requirements this way:
|
|
|
798
797
|
|
|
799
798
|
The default configuration is expected here: ~/.config/dar-backup/dar-backup.conf
|
|
800
799
|
|
|
801
|
-
## How to run
|
|
800
|
+
## How to run
|
|
802
801
|
|
|
803
|
-
### 1 -
|
|
804
|
-
|
|
805
|
-
Config file default location is $HOME/.config/dar-backup/dar-backup.conf
|
|
806
|
-
|
|
807
|
-
Example:
|
|
808
|
-
|
|
809
|
-
```` code
|
|
810
|
-
[MISC]
|
|
811
|
-
LOGFILE_LOCATION=/home/user/dar-backup.log
|
|
812
|
-
MAX_SIZE_VERIFICATION_MB = 20
|
|
813
|
-
MIN_SIZE_VERIFICATION_MB = 1
|
|
814
|
-
NO_FILES_VERIFICATION = 5
|
|
815
|
-
|
|
816
|
-
# timeout in seconds for backup, test, restore and par2 operations
|
|
817
|
-
# The author has such `dar` tasks running for 10-15 hours on the yearly backups, so a value of 24 hours is used.
|
|
818
|
-
# If a timeout is not specified when using the util.run_command(), a default timeout of 30 secs is used.
|
|
819
|
-
COMMAND_TIMEOUT_SECS = 86400
|
|
820
|
-
|
|
821
|
-
[DIRECTORIES]
|
|
822
|
-
BACKUP_DIR = /home/user/mnt/dir/
|
|
823
|
-
BACKUP.D_DIR = /home/user/.config/dar-backup/backup.d/
|
|
824
|
-
TEST_RESTORE_DIR = /tmp/dar-backup/restore/
|
|
825
|
-
|
|
826
|
-
[AGE]
|
|
827
|
-
# age settings are in days
|
|
828
|
-
DIFF_AGE = 100
|
|
829
|
-
INCR_AGE = 40
|
|
830
|
-
|
|
831
|
-
[PAR2]
|
|
832
|
-
ERROR_CORRECTION_PERCENT = 5
|
|
833
|
-
# False means "do not generate par2 redundancy files"
|
|
834
|
-
ENABLED = True
|
|
835
|
-
|
|
836
|
-
[PREREQ]
|
|
837
|
-
# SCRIPT_1 = /home/user/programmer/dar-backup/prereq/mount-server.sh
|
|
838
|
-
# SCRIPT_2 = <something>
|
|
839
|
-
# ...
|
|
840
|
-
|
|
841
|
-
[POSTREQ]
|
|
842
|
-
# SCRIPT_1 = /home/user/programmer/dar-backup/postreq/umount-server.sh
|
|
843
|
-
# SCRIPT_2 = <something>
|
|
844
|
-
# ...
|
|
845
|
-
|
|
846
|
-
````
|
|
847
|
-
|
|
848
|
-
### 2 - backup definitions
|
|
849
|
-
|
|
850
|
-
Put your backup definitions in the directory $BACKUP.D_DIR (defined in the config file)
|
|
851
|
-
|
|
852
|
-
The name of the file is the `backup definition` name.
|
|
853
|
-
|
|
854
|
-
Make as many backup definitions as you need. Run them all in one go, or run one at a time using the `-d` option.
|
|
855
|
-
|
|
856
|
-
The `dar` [documentation](http://dar.linux.free.fr/doc/man/dar.html#COMMANDS%20AND%20OPTIONS) has good information on file selection.
|
|
857
|
-
|
|
858
|
-
Example of backup definition for a home directory
|
|
859
|
-
|
|
860
|
-
```` code
|
|
861
|
-
|
|
862
|
-
# Switch to ordered selection mode, which means that the following
|
|
863
|
-
# options will be considered top to bottom
|
|
864
|
-
-am
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
# Backup Root dir
|
|
868
|
-
-R /home/user
|
|
869
|
-
|
|
870
|
-
# Directories to backup below the Root dir
|
|
871
|
-
# if you want to take a backup of /home/user/Documents only, uncomment next line
|
|
872
|
-
# -g Documents
|
|
873
|
-
|
|
874
|
-
# Some directories to exclude below the Root dir (here Root directory is `/home/user` as set in the -R option)
|
|
875
|
-
-P mnt
|
|
876
|
-
-P tmp
|
|
877
|
-
-P .cache
|
|
878
|
-
-P .config/Code/CachedData
|
|
879
|
-
-P .config/Code/Cache
|
|
880
|
-
-P ".config/Code/Service Worker"
|
|
881
|
-
-P .config/Code/logs
|
|
882
|
-
-P snap/firefox/common/.cache
|
|
883
|
-
|
|
884
|
-
# compression level
|
|
885
|
-
-z5
|
|
886
|
-
|
|
887
|
-
# no overwrite, if you rerun a backup, 'dar' halts and asks what to do (and Quits due to the "-Q" given by dar-backup)
|
|
888
|
-
-n
|
|
889
|
-
|
|
890
|
-
# size of each slice in the archive
|
|
891
|
-
--slice 10G
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
# bypass directores marked as cache directories
|
|
895
|
-
# http://dar.linux.free.fr/doc/Features.html
|
|
896
|
-
--cache-directory-tagging
|
|
897
|
-
````
|
|
898
|
-
|
|
899
|
-
### 3 - installation
|
|
802
|
+
### 1 - installation
|
|
900
803
|
|
|
901
804
|
Installation is currently in a venv. These commands are installed in the venv:
|
|
902
805
|
|
|
@@ -904,6 +807,7 @@ Installation is currently in a venv. These commands are installed in the venv:
|
|
|
904
807
|
- cleanup
|
|
905
808
|
- manager
|
|
906
809
|
- clean-log
|
|
810
|
+
- installer
|
|
907
811
|
|
|
908
812
|
To install, create a venv and run pip:
|
|
909
813
|
|
|
@@ -925,25 +829,48 @@ Typing `db` at the command line gives this
|
|
|
925
829
|
|
|
926
830
|
```` bash
|
|
927
831
|
(venv) user@machine:~$ db
|
|
928
|
-
dar-backup 0.6.
|
|
832
|
+
dar-backup 0.6.12
|
|
929
833
|
dar-backup.py source code is here: https://github.com/per2jensen/dar-backup
|
|
930
834
|
Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
|
|
931
835
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
932
836
|
See section 15 and section 16 in the supplied "LICENSE" file.
|
|
933
837
|
````
|
|
934
838
|
|
|
935
|
-
###
|
|
839
|
+
### 2 - configuration
|
|
840
|
+
|
|
841
|
+
The dar-backup installer is non-destructive and stops if some of the default directories exist.
|
|
842
|
+
|
|
843
|
+
Run the installer
|
|
844
|
+
|
|
845
|
+
```` bash
|
|
846
|
+
installer --install
|
|
847
|
+
````
|
|
848
|
+
|
|
849
|
+
The output is
|
|
850
|
+
|
|
851
|
+
```` text
|
|
852
|
+
Directories created: `/home/user/dar-backup/` and `/home/user/.config/dar-backup`
|
|
853
|
+
Config file deployed to /home/user/.config/dar-backup/dar-backup.conf
|
|
854
|
+
Default backup definition deployed to /home/user/.config/dar-backup/backup.d/default
|
|
855
|
+
1. Now run `manager --create` to create the catalog database.
|
|
856
|
+
2. Then you can run `dar-backup --full-backup` to create a backup.
|
|
857
|
+
3. List backups with `dar-backup --list`
|
|
858
|
+
4. List contents of a backup with `dar-backup --list-contents <backup-name>`
|
|
859
|
+
````
|
|
860
|
+
|
|
861
|
+
### 3 - generate catalog databases
|
|
862
|
+
|
|
863
|
+
Generate the archive catalog database(s).
|
|
936
864
|
|
|
937
|
-
Generate the archive catalog database(s).
|
|
938
865
|
`dar-backup` expects the catalog databases to be in place, it does not automatically create them (by design)
|
|
939
866
|
|
|
940
867
|
```` bash
|
|
941
|
-
manager --create
|
|
868
|
+
manager --create
|
|
942
869
|
````
|
|
943
870
|
|
|
944
|
-
###
|
|
871
|
+
### 4 - do FULL backups
|
|
945
872
|
|
|
946
|
-
You are ready to do backups of all your backup definitions, if your backup definitions are
|
|
873
|
+
You are ready to do backups of all your backup definitions, if your backup definitions are
|
|
947
874
|
in place in BACKUP.D_DIR (see config file)
|
|
948
875
|
|
|
949
876
|
```` bash
|
|
@@ -960,7 +887,7 @@ If you want a backup of a single definition, use the `-d <backup definition>` op
|
|
|
960
887
|
dar-backup --full-backup -d <your backup definition>
|
|
961
888
|
````
|
|
962
889
|
|
|
963
|
-
###
|
|
890
|
+
### 5 - deactivate venv
|
|
964
891
|
|
|
965
892
|
Deactivate the virtual environment (venv)
|
|
966
893
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
|
|
2
|
+
dar_backup/__about__.py,sha256=AY38r3HUSyMqkCPP-vaHASQmjQF5-PRm11j_QYtx28w,22
|
|
3
|
+
dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
dar_backup/clean_log.py,sha256=cGhtKYnQJ2ceNQfw5XcCln_WNBasbmlfhO3kRydjDNk,5196
|
|
5
|
+
dar_backup/cleanup.py,sha256=NaZMrTdtYv4uJSw3jwDQWc5F5jMfIdfIQdrcPGAVcnM,11439
|
|
6
|
+
dar_backup/config_settings.py,sha256=uicCq6FnpxPFzbv7xfYSXNnQf1tfLk1Z3VIO9M71fsE,4659
|
|
7
|
+
dar_backup/dar-backup.conf,sha256=-wXqP4vj5TS7cCfMJN1nbk-1Sqkq00Tg22ySQXynUF4,902
|
|
8
|
+
dar_backup/dar_backup.py,sha256=Cye8gS0E0mNKaUzcjqsdsuTyyeZYCspRMBIdcGbsEik,33171
|
|
9
|
+
dar_backup/installer.py,sha256=0TgC_O-T7Y3sLn_NIQ9lBYt8GJqLZzxPqkmbjElfgkM,4491
|
|
10
|
+
dar_backup/manager.py,sha256=MkrB0AL0MefE_cUAvdzQb_0bzvqsPmYi5s0M3EPw-z8,21379
|
|
11
|
+
dar_backup/util.py,sha256=E-sEBQZY1hmdeVx5xNE22zKQ0BXDee1eI9F1-w7Fq1Q,15756
|
|
12
|
+
dar_backup-0.6.12.dist-info/METADATA,sha256=YEbPNJr_ntP03BVKSACo2MU-Qko_9quyzmuqrhryBz0,69768
|
|
13
|
+
dar_backup-0.6.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
dar_backup-0.6.12.dist-info/entry_points.txt,sha256=Z7P5BUbhtJxo8_nB9qNIMay2eGDbsMKB3Fjwv3GMa4g,202
|
|
15
|
+
dar_backup-0.6.12.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
16
|
+
dar_backup-0.6.12.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
|
|
2
|
-
dar_backup/__about__.py,sha256=WAW-bfIrNx18qYeBN4lihEQibyosiKElDt_p7DfZELo,22
|
|
3
|
-
dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
dar_backup/clean_log.py,sha256=VXKA2BMyQmaC6R08Bq9a3wP3mczdFb_moy6HkL-mnF8,5176
|
|
5
|
-
dar_backup/cleanup.py,sha256=9yEdRR84XPtEvBGc2QfwGBQl2tdTPttjetHeiSc_TsM,11419
|
|
6
|
-
dar_backup/config_settings.py,sha256=CBMUhLOOZ-x7CRdS3vBDk4TYaGqC4N1Ot8IMH-qPaI0,3617
|
|
7
|
-
dar_backup/dar_backup.py,sha256=o4DvaVsqWHb1PxHIXfdr2qyqW6KRRGNcrR2_CRbPy1I,32942
|
|
8
|
-
dar_backup/manager.py,sha256=HDa8eYF89QFhlBRR4EWRzzmswOW00S_w8ToZ5SARO_o,21359
|
|
9
|
-
dar_backup/util.py,sha256=E-sEBQZY1hmdeVx5xNE22zKQ0BXDee1eI9F1-w7Fq1Q,15756
|
|
10
|
-
dar_backup-0.6.11.dist-info/METADATA,sha256=N7ICBJQEVDC01tza9lRAkmOXCIAILoDrg-mrHG926f0,71626
|
|
11
|
-
dar_backup-0.6.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
12
|
-
dar_backup-0.6.11.dist-info/entry_points.txt,sha256=p6c4uQLjlTIVP1Od2iorGefrVUH0IWZdFRMl63mNaRg,164
|
|
13
|
-
dar_backup-0.6.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
-
dar_backup-0.6.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|