dar-backup 0.6.18__py3-none-any.whl → 0.6.20__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/dar_backup.py CHANGED
@@ -14,6 +14,8 @@ This script can be used to control `dar` to backup parts of or the whole system.
14
14
  """
15
15
 
16
16
 
17
+
18
+ import argcomplete
17
19
  import argparse
18
20
  import filecmp
19
21
 
@@ -35,8 +37,10 @@ from sys import stderr
35
37
  from sys import argv
36
38
  from sys import version_info
37
39
  from time import time
40
+ from rich.console import Console
41
+ from rich.text import Text
38
42
  from threading import Event
39
- from typing import List
43
+ from typing import List, Tuple
40
44
 
41
45
  from . import __about__ as about
42
46
  from dar_backup.config_settings import ConfigSettings
@@ -46,12 +50,17 @@ from dar_backup.util import get_logger
46
50
  from dar_backup.util import BackupError
47
51
  from dar_backup.util import RestoreError
48
52
  from dar_backup.util import requirements
53
+ from dar_backup.util import show_version
54
+ from dar_backup.util import get_binary_info
55
+ from dar_backup.util import print_aligned_settings
56
+ from dar_backup.util import backup_definition_completer, list_archive_completer
49
57
 
50
58
  from dar_backup.command_runner import CommandRunner
51
59
  from dar_backup.command_runner import CommandResult
52
60
 
53
61
  from dar_backup.rich_progress import show_log_driven_bar
54
62
 
63
+ from argcomplete.completers import FilesCompleter
55
64
 
56
65
  logger = None
57
66
  runner = None
@@ -312,7 +321,8 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
312
321
  if filecmp.cmp(os.path.join(config_settings.test_restore_dir, restored_file_path.lstrip("/")), os.path.join(root_path, restored_file_path.lstrip("/")), shallow=False):
313
322
  args.verbose and logger.info(f"Success: file '{restored_file_path}' matches the original")
314
323
  else:
315
- raise BackupError(f"Failure: file '{restored_file_path}' did not match the original")
324
+ result = False
325
+ logger.error(f"Failure: file '{restored_file_path}' did not match the original")
316
326
  except PermissionError:
317
327
  result = False
318
328
  logger.exception(f"Permission error while comparing files, continuing....")
@@ -523,6 +533,10 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
523
533
 
524
534
  # Perform backup
525
535
  backup_result = generic_backup(backup_type, command, backup_file, backup_definition_path, args.darrc, config_settings, args)
536
+ if not isinstance(backup_result, list) or not all(isinstance(i, tuple) and len(i) == 2 for i in backup_result):
537
+ logger.error("Unexpected return format from generic_backup")
538
+ backup_result = [("Unexpected return format from generic_backup", 1)]
539
+
526
540
  results.extend(backup_result)
527
541
 
528
542
  logger.info("Starting verification...")
@@ -637,14 +651,6 @@ def filter_darrc_file(darrc_path):
637
651
 
638
652
 
639
653
 
640
- def show_version():
641
- script_name = os.path.basename(argv[0])
642
- print(f"{script_name} {about.__version__}")
643
- print(f"dar-backup.py source code is here: https://github.com/per2jensen/dar-backup")
644
- print('''Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
645
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
646
- See section 15 and section 16 in the supplied "LICENSE" file.''')
647
-
648
654
 
649
655
  def show_examples():
650
656
  examples = """
@@ -752,15 +758,15 @@ def main():
752
758
  parser.add_argument('-F', '--full-backup', action='store_true', help="Perform a full backup.")
753
759
  parser.add_argument('-D', '--differential-backup', action='store_true', help="Perform differential backup.")
754
760
  parser.add_argument('-I', '--incremental-backup', action='store_true', help="Perform incremental backup.")
755
- parser.add_argument('-d', '--backup-definition', help="Specific 'recipe' to select directories and files.")
756
- parser.add_argument('--alternate-reference-archive', help="DIFF or INCR compared to specified archive.")
761
+ parser.add_argument('-d', '--backup-definition', help="Specific 'recipe' to select directories and files.").completer = backup_definition_completer
762
+ parser.add_argument('--alternate-reference-archive', help="DIFF or INCR compared to specified archive.").completer = list_archive_completer
757
763
  parser.add_argument('-c', '--config-file', type=str, help="Path to 'dar-backup.conf'", default='~/.config/dar-backup/dar-backup.conf')
758
764
  parser.add_argument('--darrc', type=str, help='Optional path to .darrc')
759
- parser.add_argument('-l', '--list', action='store_true', help="List available archives.")
760
- parser.add_argument('--list-contents', help="List the contents of the specified archive.")
765
+ parser.add_argument('-l', '--list', action='store_true', help="List available archives.").completer = list_archive_completer
766
+ parser.add_argument('--list-contents', help="List the contents of the specified archive.").completer = list_archive_completer
761
767
  parser.add_argument('--selection', help="dar file selection for listing/restoring specific files/directories.")
762
768
  # parser.add_argument('-r', '--restore', nargs=1, type=str, help="Restore specified archive.")
763
- parser.add_argument('-r', '--restore', type=str, help="Restore specified archive.")
769
+ parser.add_argument('-r', '--restore', type=str, help="Restore specified archive.").completer = list_archive_completer
764
770
  parser.add_argument('--restore-dir', type=str, help="Directory to restore files to.")
765
771
  parser.add_argument('--verbose', action='store_true', help="Print various status messages to screen")
766
772
  parser.add_argument('--suppress-dar-msg', action='store_true', help="cancel dar options in .darrc: -vt, -vs, -vd, -vf and -va")
@@ -773,6 +779,8 @@ def main():
773
779
  parser.add_argument("--changelog", action="store_true", help="Print Changelog.md to stdout and exit.")
774
780
  parser.add_argument("--changelog-pretty", action="store_true", help="Print Changelog.md to stdout with Markdown styling and exit.")
775
781
  parser.add_argument('-v', '--version', action='store_true', help="Show version and license information.")
782
+
783
+ argcomplete.autocomplete(parser)
776
784
  args = parser.parse_args()
777
785
 
778
786
  if args.version:
@@ -834,32 +842,40 @@ def main():
834
842
  args.darrc = filter_darrc_file(args.darrc)
835
843
  logger.debug(f"Filtered .darrc file: {args.darrc}")
836
844
 
845
+ start_msgs: List[Tuple[str, str]] = []
846
+
837
847
  start_time=int(time())
838
- logger.info(f"=====================================")
839
- logger.info(f"dar-backup.py started, version: {about.__version__}")
848
+ start_msgs.append(('dar-backup.py:', about.__version__))
840
849
  logger.info(f"START TIME: {start_time}")
841
- logger.debug(f"`args`:\n{args}")
842
- logger.debug(f"`config_settings`:\n{config_settings}")
850
+ logger.debug(f"{'`Args`:\n'}{args}")
851
+ logger.debug(f"{'`Config_settings`:\n'}{config_settings}")
852
+ dar_properties = get_binary_info(command='dar')
853
+ start_msgs.append(('dar path:', dar_properties['path']))
854
+ start_msgs.append(('dar version:', dar_properties['version']))
843
855
 
844
856
  file_dir = os.path.normpath(os.path.dirname(__file__))
845
- args.verbose and (print(f"Script directory: {file_dir}"))
846
- args.verbose and (print(f"Config file: {args.config_file}"))
847
- args.verbose and args.full_backup and (print(f"Type of backup: FULL"))
848
- args.verbose and args.differential_backup and (print(f"Type of backup: DIFF"))
849
- args.verbose and args.incremental_backup and (print(f"Type of backup: INCR"))
850
- args.verbose and args.backup_definition and (print(f"Backup definition: '{args.backup_definition}'"))
857
+ start_msgs.append(('Script directory:', os.path.abspath(file_dir)))
858
+ start_msgs.append(('Config file:', os.path.abspath(args.config_file)))
859
+ start_msgs.append((".darrc location:", args.darrc))
860
+
861
+ args.verbose and args.full_backup and start_msgs.append(("Type of backup:", "FULL"))
862
+ args.verbose and args.differential_backup and start_msgs.append(("Type of backup:", "DIFF"))
863
+ args.verbose and args.incremental_backup and start_msgs.append(("Type of backup:", "INCR"))
864
+ args.verbose and args.backup_definition and start_msgs.append(("Backup definition:", args.backup_definition))
851
865
  if args.alternate_reference_archive:
852
- args.verbose and (print(f"Alternate ref archive: {args.alternate_reference_archive}"))
853
- args.verbose and (print(f"Backup.d dir: {config_settings.backup_d_dir}"))
854
- args.verbose and (print(f"Backup dir: {config_settings.backup_dir}"))
866
+ args.verbose and start_msgs.append(("Alternate ref archive:", args.alternate_reference_archive))
867
+ args.verbose and start_msgs.append(("Backup.d dir:", config_settings.backup_d_dir))
868
+ args.verbose and start_msgs.append(("Backup dir:", config_settings.backup_dir))
855
869
 
856
870
  restore_dir = args.restore_dir if args.restore_dir else config_settings.test_restore_dir
857
- args.verbose and (print(f"Restore dir: {restore_dir}"))
871
+ args.verbose and start_msgs.append(("Restore dir:", restore_dir))
872
+
873
+ args.verbose and start_msgs.append(("Logfile location:", config_settings.logfile_location))
874
+ args.verbose and start_msgs.append(("PAR2 enabled:", config_settings.par2_enabled))
875
+ args.verbose and start_msgs.append(("--do-not-compare:", args.do_not_compare))
858
876
 
859
- args.verbose and (print(f"Logfile location: {config_settings.logfile_location}"))
860
- args.verbose and (print(f".darrc location: {args.darrc}"))
861
- args.verbose and (print(f"PAR2 enabled: {config_settings.par2_enabled}"))
862
- args.verbose and (print(f"--do-not-compare: {args.do_not_compare}"))
877
+ dangerous_keywords = ["--do-not", "alternate"] # TODO: add more dangerous keywords
878
+ print_aligned_settings(start_msgs)
863
879
 
864
880
  # sanity check
865
881
  if args.backup_definition and not os.path.exists(os.path.join(config_settings.backup_d_dir, args.backup_definition)):
@@ -921,12 +937,17 @@ def main():
921
937
  else:
922
938
  logger.error(f"not correct result type: {result}, which must be a tuple (<msg>, <exit_code>)")
923
939
  i=i+1
940
+
941
+ console = Console()
924
942
  if error:
925
- args.verbose and print("\033[1m\033[31mErrors\033[0m encountered")
943
+ if args.verbose:
944
+ console.print(Text("Errors encountered", style="bold red"))
926
945
  exit(1)
927
946
  else:
928
- args.verbose and print("\033[1m\033[32mSuccess\033[0m all backups completed")
947
+ if args.verbose:
948
+ console.print(Text("Success: all backups completed", style="bold green"))
929
949
  exit(0)
950
+
930
951
 
931
952
  if __name__ == "__main__":
932
953
  main()
dar_backup/demo.py ADDED
@@ -0,0 +1,138 @@
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
+
67
+ def main():
68
+ parser = argparse.ArgumentParser(
69
+ description="Set up `dar-backup` on your system.",
70
+ )
71
+ parser.add_argument(
72
+ "-i", "--install",
73
+ action="store_true",
74
+ help="Deploy a simple config file, use ~/dar-backup/ for log file, archives and restore tests."
75
+ )
76
+ parser.add_argument(
77
+ "-v", "--version",
78
+ action="version",
79
+ version=f"%(prog)s version {about.__version__}, {LICENSE}"
80
+ )
81
+
82
+ args = parser.parse_args()
83
+
84
+ if args.install:
85
+ errors = []
86
+ if os.path.exists(CONFIG_DIR):
87
+ errors.append(f"Config directory '{CONFIG_DIR}' already exists.")
88
+ if os.path.exists(DAR_BACKUP_DIR):
89
+ errors.append(f"Directory '{DAR_BACKUP_DIR}' already exists.")
90
+
91
+ if errors:
92
+ for error in errors:
93
+ print(f"Error: {error}")
94
+ sys.exit(1)
95
+
96
+ try:
97
+ os.makedirs(DAR_BACKUP_DIR, exist_ok=False)
98
+ os.makedirs(os.path.join(DAR_BACKUP_DIR, "backups"), exist_ok=False)
99
+ os.makedirs(os.path.join(DAR_BACKUP_DIR, "restore"), exist_ok=False)
100
+ os.makedirs(CONFIG_DIR, exist_ok=False)
101
+ os.makedirs(os.path.join(CONFIG_DIR, "backup.d"), exist_ok=False)
102
+ print(f"Directories created: `{DAR_BACKUP_DIR}` and `{CONFIG_DIR}`")
103
+
104
+ script_dir = Path(__file__).parent
105
+ source_file = script_dir / "dar-backup.conf"
106
+ destination_file = Path(CONFIG_DIR) / "dar-backup.conf"
107
+
108
+ try:
109
+ shutil.copy2(source_file, destination_file)
110
+ print(f"Config file deployed to {destination_file}")
111
+ except Exception as e:
112
+ print(f"Error: Could not copy config file: {e}")
113
+ sys.exit(1)
114
+
115
+
116
+ backup_definition = BACKUP_DEFINITION.replace("@@HOME_DIR@@", os.path.expanduser("~"))
117
+
118
+ try:
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
+ except Exception as e:
123
+ print(f"Error: Could not write default backup definition: {e}")
124
+ sys.exit(1)
125
+ except Exception as e:
126
+ print(f"Installation failed: {e}")
127
+ sys.exit(1)
128
+
129
+ print("1. Now run `manager --create` to create the catalog database.")
130
+ print("2. Then you can run `dar-backup --full-backup` to create a backup.")
131
+ print("3. List backups with `dar-backup --list`")
132
+ print("4. List contents of a backup with `dar-backup --list-contents <backup-name>`")
133
+
134
+ sys.exit(0)
135
+
136
+
137
+ if __name__ == "__main__":
138
+ main()
@@ -0,0 +1,3 @@
1
+ class ConfigSettingsError(Exception):
2
+ """Raised when ConfigSettings encounters a critical error."""
3
+ pass
dar_backup/installer.py CHANGED
@@ -1,138 +1,58 @@
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
1
  import argparse
17
2
  import os
18
- import shutil
19
- import sys
20
-
21
- from . import __about__ as about
22
3
  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
-
67
- def main():
68
- parser = argparse.ArgumentParser(
69
- description="Set up `dar-backup` on your system.",
70
- )
71
- parser.add_argument(
72
- "-i", "--install",
73
- action="store_true",
74
- help="Deploy a simple config file, use ~/dar-backup/ for log file, archives and restore tests."
75
- )
76
- parser.add_argument(
77
- "-v", "--version",
78
- action="version",
79
- version=f"%(prog)s version {about.__version__}, {LICENSE}"
4
+ from dar_backup.config_settings import ConfigSettings
5
+ from dar_backup.util import setup_logging, get_logger
6
+ from dar_backup.command_runner import CommandRunner
7
+ from dar_backup.manager import create_db
8
+
9
+
10
+ def run_installer(config_file: str, create_db_flag: bool):
11
+ config_file = os.path.expanduser(os.path.expandvars(config_file))
12
+ config_settings = ConfigSettings(config_file)
13
+
14
+ # Set up logging based on the config's specified log file
15
+ command_log = config_settings.logfile_location.replace("dar-backup.log", "dar-backup-commands.log")
16
+ logger = setup_logging(
17
+ config_settings.logfile_location,
18
+ command_log,
19
+ log_level="info",
20
+ log_stdout=True,
80
21
  )
81
-
22
+ command_logger = get_logger(command_output_logger=True)
23
+ runner = CommandRunner(logger=logger, command_logger=command_logger)
24
+
25
+ # Create directories listed in config
26
+ for attr in ["backup_dir", "test_restore_dir", "backup_d_dir", "manager_db_dir"]:
27
+ path = getattr(config_settings, attr, None)
28
+ if path:
29
+ dir_path = Path(path).expanduser()
30
+ if not dir_path.exists():
31
+ dir_path.mkdir(parents=True, exist_ok=True)
32
+ print(f"Created directory: {dir_path}")
33
+ else:
34
+ print(f"Directory already exists: {dir_path}")
35
+
36
+ # Optionally create databases
37
+ if create_db_flag:
38
+ for file in os.listdir(config_settings.backup_d_dir):
39
+ backup_def = os.path.basename(file)
40
+ print(f"Creating catalog for: {backup_def}")
41
+ result = create_db(backup_def, config_settings, logger)
42
+ if result == 0:
43
+ print(f"✔️ Catalog created (or already existed): {backup_def}")
44
+ else:
45
+ print(f"❌ Failed to create catalog: {backup_def}")
46
+
47
+
48
+ def installer_main():
49
+ parser = argparse.ArgumentParser(description="dar-backup installer")
50
+ parser.add_argument("--config", required=True, help="Path to config file")
51
+ parser.add_argument("--create-db", action="store_true", help="Create catalog databases")
82
52
  args = parser.parse_args()
83
53
 
84
- if args.install:
85
- errors = []
86
- if os.path.exists(CONFIG_DIR):
87
- errors.append(f"Config directory '{CONFIG_DIR}' already exists.")
88
- if os.path.exists(DAR_BACKUP_DIR):
89
- errors.append(f"Directory '{DAR_BACKUP_DIR}' already exists.")
90
-
91
- if errors:
92
- for error in errors:
93
- print(f"Error: {error}")
94
- sys.exit(1)
95
-
96
- try:
97
- os.makedirs(DAR_BACKUP_DIR, exist_ok=False)
98
- os.makedirs(os.path.join(DAR_BACKUP_DIR, "backups"), exist_ok=False)
99
- os.makedirs(os.path.join(DAR_BACKUP_DIR, "restore"), exist_ok=False)
100
- os.makedirs(CONFIG_DIR, exist_ok=False)
101
- os.makedirs(os.path.join(CONFIG_DIR, "backup.d"), exist_ok=False)
102
- print(f"Directories created: `{DAR_BACKUP_DIR}` and `{CONFIG_DIR}`")
103
-
104
- script_dir = Path(__file__).parent
105
- source_file = script_dir / "dar-backup.conf"
106
- destination_file = Path(CONFIG_DIR) / "dar-backup.conf"
107
-
108
- try:
109
- shutil.copy2(source_file, destination_file)
110
- print(f"Config file deployed to {destination_file}")
111
- except Exception as e:
112
- print(f"Error: Could not copy config file: {e}")
113
- sys.exit(1)
114
-
115
-
116
- backup_definition = BACKUP_DEFINITION.replace("@@HOME_DIR@@", os.path.expanduser("~"))
117
-
118
- try:
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
- except Exception as e:
123
- print(f"Error: Could not write default backup definition: {e}")
124
- sys.exit(1)
125
- except Exception as e:
126
- print(f"Installation failed: {e}")
127
- sys.exit(1)
128
-
129
- print("1. Now run `manager --create` to create the catalog database.")
130
- print("2. Then you can run `dar-backup --full-backup` to create a backup.")
131
- print("3. List backups with `dar-backup --list`")
132
- print("4. List contents of a backup with `dar-backup --list-contents <backup-name>`")
133
-
134
- sys.exit(0)
54
+ run_installer(args.config, args.create_db)
135
55
 
136
56
 
137
57
  if __name__ == "__main__":
138
- main()
58
+ installer_main()