dar-backup 0.6.14__py3-none-any.whl → 0.6.15__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.6.14"
1
+ __version__ = "0.6.15"
dar_backup/dar_backup.py CHANGED
@@ -34,7 +34,7 @@ from dar_backup.util import RestoreError
34
34
 
35
35
  logger = None
36
36
 
37
- def generic_backup(type: str, command: List[str], backup_file: str, backup_definition: str, darrc: str, config_settings: ConfigSettings, args: argparse.Namespace):
37
+ def generic_backup(type: str, command: List[str], backup_file: str, backup_definition: str, darrc: str, config_settings: ConfigSettings, args: argparse.Namespace) -> List[str]:
38
38
  """
39
39
  Performs a backup using the 'dar' command.
40
40
 
@@ -54,10 +54,14 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
54
54
  config_settings (ConfigSettings): An instance of the ConfigSettings class.
55
55
 
56
56
 
57
-
58
57
  Raises:
59
- BackupError: If an error occurs during the backup process.
58
+ BackupError: If an error leading to a bad backup occurs during the backup process.
59
+
60
+ Returns:
61
+ List of tuples (<msg>, <exit_code>) of errors not considered critical enough for raising an exception
60
62
  """
63
+ result: List[tuple] = []
64
+
61
65
  logger.info(f"===> Starting {type} backup for {backup_definition}")
62
66
  logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
63
67
  try:
@@ -75,7 +79,11 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
75
79
  if command_result.returncode == 0:
76
80
  logger.info(f"Catalog for archive '{backup_file}' added successfully to its manager.")
77
81
  else:
78
- logger.error(f"Catalog for archive '{backup_file}' not added.")
82
+ msg = f"Catalog for archive '{backup_file}' not added."
83
+ logger.error(msg)
84
+ result.append((msg, 1))
85
+
86
+ return result
79
87
 
80
88
  except subprocess.CalledProcessError as e:
81
89
  logger.error(f"Backup command failed: {e}")
@@ -83,7 +91,7 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
83
91
  except Exception as e:
84
92
  logger.exception(f"Unexpected error during backup")
85
93
  raise BackupError(f"Unexpected error during backup: {e}") from e
86
-
94
+
87
95
 
88
96
 
89
97
  def find_files_with_paths(xml_doc: str):
@@ -184,7 +192,7 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
184
192
  """
185
193
  result = True
186
194
  command = ['dar', '-t', backup_file, '-Q']
187
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
195
+ logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
188
196
  process = run_command(command, config_settings.command_timeout_secs)
189
197
  if process.returncode == 0:
190
198
  logger.info("Archive integrity test passed.")
@@ -208,8 +216,9 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
208
216
  root_path = None
209
217
  for line in backup_definition_content:
210
218
  line = line.strip()
211
- if line.startswith("-R"):
212
- root_path = line.split("-R", 1)[1].strip()
219
+ match = re.match(r'^\s*-R\s+(.*)', line)
220
+ if match:
221
+ root_path = match.group(1).strip()
213
222
  break
214
223
  if root_path is None:
215
224
  msg = f"No Root (-R) path found in the backup definition file: '{backup_definition}', restore verification skipped"
@@ -223,15 +232,15 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
223
232
  random_files = random.sample(files, no_files_verification)
224
233
  for restored_file_path in random_files:
225
234
  try:
226
- logger.info(f"Restoring file: '{restored_file_path}' from backup to: '{config_settings.test_restore_dir}' for file comparing")
235
+ args.verbose and logger.info(f"Restoring file: '{restored_file_path}' from backup to: '{config_settings.test_restore_dir}' for file comparing")
227
236
  command = ['dar', '-x', backup_file, '-g', restored_file_path.lstrip("/"), '-R', config_settings.test_restore_dir, '-Q', '-B', args.darrc, 'restore-options']
228
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
237
+ args.verbose and logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
229
238
  process = run_command(command, config_settings.command_timeout_secs)
230
239
  if process.returncode != 0:
231
240
  raise Exception(str(process))
232
241
 
233
242
  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):
234
- logger.info(f"Success: file '{restored_file_path}' matches the original")
243
+ args.verbose and logger.info(f"Success: file '{restored_file_path}' matches the original")
235
244
  else:
236
245
  raise BackupError(f"Failure: file '{restored_file_path}' did not match the original")
237
246
  except PermissionError:
@@ -295,11 +304,11 @@ def get_backed_up_files(backup_name: str, backup_dir: str):
295
304
  Returns:
296
305
  list: A list of file paths for all backed up files in the DAR archive.
297
306
  """
298
- logger.debug(f"Getting backed up files from DAR archive in xml: '{backup_name}'")
307
+ logger.debug(f"Getting backed up files in xml from DAR archive: '{backup_name}'")
299
308
  backup_path = os.path.join(backup_dir, backup_name)
300
309
  try:
301
310
  command = ['dar', '-l', backup_path, '-am', '-as', "-Txml" , '-Q']
302
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
311
+ logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
303
312
  command_result = run_command(command)
304
313
  # Parse the XML data
305
314
  file_paths = find_files_with_paths(command_result.stdout)
@@ -383,7 +392,7 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
383
392
  backup_type: Type of backup (FULL, DIFF, INCR).
384
393
 
385
394
  Returns:
386
- List[tuples] - each tuple consists of (<str message>, <exit code>)
395
+ List[tuples] - each tuple consists of (<str message>, <exit code>)
387
396
  """
388
397
  backup_definitions = []
389
398
  results: List[tuple] = []
@@ -443,7 +452,8 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
443
452
  command = create_backup_command(backup_type, backup_file, args.darrc, backup_definition_path, latest_base_backup)
444
453
 
445
454
  # Perform backup
446
- generic_backup(backup_type, command, backup_file, backup_definition_path, args.darrc, config_settings, args)
455
+ backup_result = generic_backup(backup_type, command, backup_file, backup_definition_path, args.darrc, config_settings, args)
456
+ results.extend(backup_result)
447
457
 
448
458
  logger.info("Starting verification...")
449
459
  verify_result = verify(args, backup_file, backup_definition_path, config_settings)
@@ -458,7 +468,7 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
458
468
  logger.info("par2 files completed successfully.")
459
469
 
460
470
  except Exception as e:
461
- results.aapend((repr(e), 1))
471
+ results.append((repr(e), 1))
462
472
  logger.exception(f"Error during {backup_type} backup process, continuing to next backup definition.")
463
473
 
464
474
  logger.trace(f"perform_backup() results[]: {results}")
@@ -519,8 +529,14 @@ def filter_darrc_file(darrc_path):
519
529
  The filtered version is stored in a uniquely named file in the home directory of the user running the script.
520
530
  The file permissions are set to 440.
521
531
 
522
- :param darrc_path: Path to the original .darrc file.
523
- :return: Path to the filtered .darrc file.
532
+ Params:
533
+ darrc_path: Path to the original .darrc file.
534
+
535
+ Raises:
536
+ RuntimeError if something went wrong
537
+
538
+ Returns:
539
+ Path to the filtered .darrc file.
524
540
  """
525
541
  # Define options to filter out
526
542
  options_to_remove = {"-vt", "-vs", "-vd", "-vf", "-va"}
@@ -631,8 +647,8 @@ def requirements(type: str, config_setting: ConfigSettings):
631
647
  script = config_setting.config[type][key]
632
648
  try:
633
649
  result = subprocess.run(script, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
634
- logger.info(f"{type} {key}: '{script}' run, return code: {result.returncode}")
635
- logger.info(f"{type} stdout:\n{result.stdout}")
650
+ logger.debug(f"{type} {key}: '{script}' run, return code: {result.returncode}")
651
+ logger.debug(f"{type} stdout:\n{result.stdout}")
636
652
  if result.returncode != 0:
637
653
  logger.error(f"{type} stderr:\n{result.stderr}")
638
654
  raise RuntimeError(f"{type} {key}: '{script}' failed, return code: {result.returncode}")
@@ -711,9 +727,9 @@ def main():
711
727
  exit(127)
712
728
 
713
729
  if args.suppress_dar_msg:
714
- logger.info("Suppressing dar messages: -vt, -vs, -vd, -vf and -va")
730
+ logger.info("Suppressing dar messages, do not use options: -vt, -vs, -vd, -vf, -va")
715
731
  args.darrc = filter_darrc_file(args.darrc)
716
- logger.debug(f"Filtered .darrc file saved at: {args.darrc}")
732
+ logger.debug(f"Filtered .darrc file: {args.darrc}")
717
733
 
718
734
  start_time=int(time())
719
735
  logger.info(f"=====================================")
@@ -781,12 +797,13 @@ def main():
781
797
  end_time=int(time())
782
798
  logger.info(f"END TIME: {end_time}")
783
799
  # Clean up
784
- if args.suppress_dar_msg and os.path.exists(args.darrc) and os.path.dirname(args.darrc) == os.path.expanduser("~"):
800
+ if os.path.exists(args.darrc) and os.path.dirname(args.darrc) == os.path.expanduser("~"):
785
801
  if args.darrc.startswith("filtered_darrc_"):
786
802
  os.remove(args.darrc)
787
- logger.info(f"Removed filtered .darrc: {args.darrc}")
803
+ logger.debug(f"Removed filtered .darrc: {args.darrc}")
788
804
 
789
805
 
806
+ # Determine exit code
790
807
  error = False
791
808
  logger.debug(f"results[]: {results}")
792
809
  if results:
@@ -795,7 +812,7 @@ def main():
795
812
  if isinstance(result, tuple) and len(result) == 2:
796
813
  msg, exit_code = result
797
814
  logger.debug(f"exit code: {exit_code}, msg: {msg}")
798
- if exit_code == 1:
815
+ if exit_code > 0:
799
816
  error = True
800
817
  args.verbose and print(msg)
801
818
  else:
dar_backup/util.py CHANGED
@@ -72,7 +72,7 @@ def setup_logging(log_file: str, command_output_log_file: str, log_level: str =
72
72
  stdout_handler = logging.StreamHandler(sys.stdout)
73
73
  stdout_handler.setFormatter(formatter)
74
74
  logger.addHandler(stdout_handler)
75
- secondary_logger.addHandler(stdout_handler)
75
+ #secondary_logger.addHandler(stdout_handler)
76
76
 
77
77
  return logger
78
78
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dar-backup
3
- Version: 0.6.14
3
+ Version: 0.6.15
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
@@ -1,16 +1,16 @@
1
1
  dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
2
- dar_backup/__about__.py,sha256=gpxZhHkmXQLM1tz9VrFJMN82NzCMmjk_6Z0FrzPb8BE,22
2
+ dar_backup/__about__.py,sha256=9pegTLVQP2o3JePGrLB6muzXif64umv9ihLnS7LsH8E,22
3
3
  dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  dar_backup/clean_log.py,sha256=cGhtKYnQJ2ceNQfw5XcCln_WNBasbmlfhO3kRydjDNk,5196
5
5
  dar_backup/cleanup.py,sha256=1g2si9-jPEL8T4OKaiGSKFGsF6rWh-Ke1-zQHE7HaPc,11703
6
6
  dar_backup/config_settings.py,sha256=uicCq6FnpxPFzbv7xfYSXNnQf1tfLk1Z3VIO9M71fsE,4659
7
7
  dar_backup/dar-backup.conf,sha256=-wXqP4vj5TS7cCfMJN1nbk-1Sqkq00Tg22ySQXynUF4,902
8
- dar_backup/dar_backup.py,sha256=8RcSVsqRy-BUCjJBroo0oKC8ZabZ5HXZrRFwxZV82b4,37360
8
+ dar_backup/dar_backup.py,sha256=TrYMYNbQ9jWabWGc7GA5p2ezprLqMUu9O0zt6CQ1QSA,37867
9
9
  dar_backup/installer.py,sha256=ehp4KSgTc8D9Edsyve5v3NY2MuDbuTFYQQPgou8woV8,4331
10
10
  dar_backup/manager.py,sha256=sQl0xdWwBgui11S9Ekg0hOSC4gt89nz_Z8Bt8IPXCDw,21640
11
- dar_backup/util.py,sha256=lfgfxC_C6x3I8f9vzyxpQE7P-7rm6tTEr3P-2uWlVtQ,12278
12
- dar_backup-0.6.14.dist-info/METADATA,sha256=P8yWZZJ8WDrSMmN8UCbEoKZU2y76L_-05Y2vPmubNOA,72750
13
- dar_backup-0.6.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
- dar_backup-0.6.14.dist-info/entry_points.txt,sha256=Z7P5BUbhtJxo8_nB9qNIMay2eGDbsMKB3Fjwv3GMa4g,202
15
- dar_backup-0.6.14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
- dar_backup-0.6.14.dist-info/RECORD,,
11
+ dar_backup/util.py,sha256=F6U-e-WugxCxLPVoiWsM6_YO8VrDw1wdgGvtnGnig2I,12279
12
+ dar_backup-0.6.15.dist-info/METADATA,sha256=JwTNDXCElF0elUKBhwjrDUASEkpLIjgdtfEML5NvXUY,72750
13
+ dar_backup-0.6.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ dar_backup-0.6.15.dist-info/entry_points.txt,sha256=Z7P5BUbhtJxo8_nB9qNIMay2eGDbsMKB3Fjwv3GMa4g,202
15
+ dar_backup-0.6.15.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
+ dar_backup-0.6.15.dist-info/RECORD,,