dar-backup 0.6.17__py3-none-any.whl → 0.6.19__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.
@@ -0,0 +1,119 @@
1
+ from pathlib import Path
2
+ import subprocess
3
+ import argparse
4
+
5
+ SERVICE_TEMPLATE = """[Unit]
6
+ Description=dar-backup {mode}
7
+ StartLimitIntervalSec=120
8
+ StartLimitBurst=1
9
+
10
+ [Service]
11
+ Type=oneshot
12
+ TimeoutSec=infinity
13
+ RemainAfterExit=no
14
+ ExecStart=/bin/bash -c '{exec_command}'
15
+ """
16
+
17
+ TIMER_TEMPLATE = """[Unit]
18
+ Description=dar-backup {mode} timer
19
+
20
+ [Timer]
21
+ OnCalendar={calendar}
22
+ Persistent=true
23
+
24
+ [Install]
25
+ WantedBy=timers.target
26
+ """
27
+
28
+ CLEANUP_SERVICE_TEMPLATE = """[Unit]
29
+ Description=cleanup up old DIFF & INCR backups
30
+ StartLimitIntervalSec=120
31
+ StartLimitBurst=1
32
+
33
+ [Service]
34
+ Type=oneshot
35
+ TimeoutSec=60
36
+ RemainAfterExit=no
37
+ ExecStart=/bin/bash -c '{exec_command}'
38
+ """
39
+
40
+ CLEANUP_TIMER = """[Unit]
41
+ Description=dar-cleanup DIFF & INCR timer
42
+
43
+ [Timer]
44
+ OnCalendar=*-*-* 21:07:00
45
+
46
+ [Install]
47
+ WantedBy=timers.target
48
+ """
49
+
50
+ TIMINGS = {
51
+ "FULL": "*-12-30 10:03:00",
52
+ "DIFF": "*-*-01 19:03:00",
53
+ "INCR": "*-*-04/3 19:03:00"
54
+ }
55
+
56
+ FLAGS = {
57
+ "FULL": "-F",
58
+ "DIFF": "-D",
59
+ "INCR": "-I"
60
+ }
61
+
62
+ def build_exec_command(venv, flag, dar_path=None, tool='dar-backup'):
63
+ if dar_path:
64
+ return f"PATH={dar_path}:$PATH && . {venv}/bin/activate && {tool} {flag} --verbose --log-stdout"
65
+ return f". {venv}/bin/activate && {tool} {flag} --verbose --log-stdout"
66
+
67
+ def generate_service(mode, venv, dar_path):
68
+ exec_command = build_exec_command(venv, FLAGS[mode], dar_path)
69
+ return SERVICE_TEMPLATE.format(mode=mode, exec_command=exec_command)
70
+
71
+ def generate_timer(mode):
72
+ return TIMER_TEMPLATE.format(mode=mode, calendar=TIMINGS[mode])
73
+
74
+ def generate_cleanup_service(venv, dar_path):
75
+ exec_command = build_exec_command(venv, "", dar_path, tool='cleanup').strip()
76
+ return CLEANUP_SERVICE_TEMPLATE.format(exec_command=exec_command)
77
+
78
+ def write_unit_file(path, filename, content):
79
+ file_path = path / filename
80
+ file_path.write_text(content)
81
+ print(f"Generated {filename}")
82
+
83
+ def enable_and_start_unit(unit_name):
84
+ subprocess.run(["systemctl", "--user", "enable", unit_name], check=False)
85
+ subprocess.run(["systemctl", "--user", "start", unit_name], check=False)
86
+
87
+ def write_unit_files(venv, dar_path, install=False):
88
+ output_path = Path.home() / ".config/systemd/user" if install else Path.cwd()
89
+ output_path.mkdir(parents=True, exist_ok=True)
90
+
91
+ for mode in FLAGS:
92
+ service_name = f"dar-{mode.lower()}-backup.service"
93
+ timer_name = f"dar-{mode.lower()}-backup.timer"
94
+ write_unit_file(output_path, service_name, generate_service(mode, venv, dar_path))
95
+ write_unit_file(output_path, timer_name, generate_timer(mode))
96
+ print(f" → Fires on: {TIMINGS[mode]}")
97
+
98
+ write_unit_file(output_path, "dar-cleanup.service", generate_cleanup_service(venv, dar_path))
99
+ write_unit_file(output_path, "dar-cleanup.timer", CLEANUP_TIMER)
100
+ print(f" → Fires on: *-*-* 21:07:00")
101
+
102
+ if install:
103
+ for mode in FLAGS:
104
+ enable_and_start_unit(f"dar-{mode.lower()}-backup.timer")
105
+ enable_and_start_unit("dar-cleanup.timer")
106
+ subprocess.run(["systemctl", "--user", "daemon-reexec"], check=False)
107
+ subprocess.run(["systemctl", "--user", "daemon-reload"], check=False)
108
+ print("Systemd `dar-backup` units and timers installed and user daemon reloaded.")
109
+
110
+ def main():
111
+ parser = argparse.ArgumentParser(description="Generate systemd service and timer units for dar-backup.")
112
+ parser.add_argument("--venv", required=True, help="Path to the Python venv with dar-backup")
113
+ parser.add_argument("--dar-path", help="Optional path to dar binary's directory")
114
+ parser.add_argument("--install", action="store_true", help="Install the units to ~/.config/systemd/user")
115
+ args = parser.parse_args()
116
+ write_unit_files(args.venv, args.dar_path, install=args.install)
117
+
118
+ if __name__ == "__main__":
119
+ main()
dar_backup/installer.py CHANGED
@@ -63,6 +63,7 @@ BACKUP_DEFINITION = '''
63
63
  --cache-directory-tagging
64
64
  '''
65
65
 
66
+
66
67
  def main():
67
68
  parser = argparse.ArgumentParser(
68
69
  description="Set up `dar-backup` on your system.",
@@ -72,7 +73,6 @@ def main():
72
73
  action="store_true",
73
74
  help="Deploy a simple config file, use ~/dar-backup/ for log file, archives and restore tests."
74
75
  )
75
-
76
76
  parser.add_argument(
77
77
  "-v", "--version",
78
78
  action="version",
@@ -85,38 +85,54 @@ def main():
85
85
  errors = []
86
86
  if os.path.exists(CONFIG_DIR):
87
87
  errors.append(f"Config directory '{CONFIG_DIR}' already exists.")
88
-
89
88
  if os.path.exists(DAR_BACKUP_DIR):
90
89
  errors.append(f"Directory '{DAR_BACKUP_DIR}' already exists.")
91
90
 
92
- if len(errors) > 0:
91
+ if errors:
93
92
  for error in errors:
94
93
  print(f"Error: {error}")
95
- sys.exit(1)
96
-
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
- shutil.copy(source_file, destination_file)
108
- print(f"Config file deployed to {destination_file}")
109
-
110
-
111
- backup_definition = BACKUP_DEFINITION.replace("@@HOME_DIR@@", os.path.expanduser("~"))
112
- with open(os.path.join(CONFIG_DIR, "backup.d", "default"), "w") as f:
113
- f.write(backup_definition)
114
- print(f"Default backup definition file deployed to {os.path.join(CONFIG_DIR, 'backup.d', 'default')}")
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
+
115
129
  print("1. Now run `manager --create` to create the catalog database.")
116
130
  print("2. Then you can run `dar-backup --full-backup` to create a backup.")
117
131
  print("3. List backups with `dar-backup --list`")
118
132
  print("4. List contents of a backup with `dar-backup --list-contents <backup-name>`")
119
133
 
134
+ sys.exit(0)
135
+
120
136
 
121
137
  if __name__ == "__main__":
122
138
  main()