dar-backup 0.6.13.1__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.13.1"
1
+ __version__ = "0.6.15"
dar_backup/dar_backup.py CHANGED
@@ -27,14 +27,14 @@ from dar_backup.config_settings import ConfigSettings
27
27
  from dar_backup.util import list_backups
28
28
  from dar_backup.util import run_command
29
29
  from dar_backup.util import setup_logging
30
+ from dar_backup.util import get_logger
30
31
  from dar_backup.util import BackupError
31
32
  from dar_backup.util import RestoreError
32
33
 
33
34
 
34
- RESULT = True
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,33 +91,40 @@ 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
- def find_files_with_paths(xml_root: ET.Element):
97
+ def find_files_with_paths(xml_doc: str):
90
98
  """
91
- Finds files within an XML element and returns a list of file paths with their sizes.
99
+ Finds files within an XML element and returns a list of tuples (file path, size).
92
100
 
93
101
  Args:
94
- xml_root (Element): The root element of the XML.
102
+ xml_root: str The XML generated by dar -l <archive> -Txml.
95
103
 
96
104
  Returns:
97
- list: A list of tuples containing file paths and their sizes.
105
+ list: A list of tuples (file path, size).
98
106
  """
99
- logger.debug("Generating list of tuples with file paths and sizes for File elements in dar xml output")
100
- files = []
101
- current_path = []
107
+ #get_logger().debug("Generating list of tuples with file paths and sizes for File elements in dar xml output")
108
+ xml_doc = re.sub(r'<!DOCTYPE[^>]*>', '', xml_doc)
109
+ root = ET.fromstring(xml_doc)
102
110
 
103
- for elem in xml_root.iter():
104
- if elem.tag == "Directory":
105
- current_path.append(elem.get('name'))
106
- elif elem.tag == "File":
107
- file_path = ("/".join(current_path + [elem.get('name')]), elem.get('size'))
108
- files.append(file_path)
109
- elif elem.tag == "Directory" and elem.get('Name') in current_path:
110
- current_path.pop()
111
+ files_list = []
111
112
 
112
- return files
113
+ def iterate_dir(element, current_path=""):
114
+ for child in element:
115
+ if child.tag == 'Directory':
116
+ dir_name = child.get('name')
117
+ new_path = f"{current_path}/{dir_name}" if current_path else dir_name
118
+ iterate_dir(child, new_path)
119
+
120
+ elif child.tag == 'File':
121
+ file_name = child.get('name')
122
+ file_size = child.get('size')
123
+ file_path = f"{current_path}/{file_name}" if current_path else file_name
124
+ files_list.append((file_path, file_size))
125
+
126
+ iterate_dir(root)
127
+ return files_list
113
128
 
114
129
 
115
130
  def find_files_between_min_and_max_size(backed_up_files: list[(str, str)], config_settings: ConfigSettings):
@@ -177,7 +192,7 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
177
192
  """
178
193
  result = True
179
194
  command = ['dar', '-t', backup_file, '-Q']
180
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
195
+ logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
181
196
  process = run_command(command, config_settings.command_timeout_secs)
182
197
  if process.returncode == 0:
183
198
  logger.info("Archive integrity test passed.")
@@ -201,8 +216,9 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
201
216
  root_path = None
202
217
  for line in backup_definition_content:
203
218
  line = line.strip()
204
- if line.startswith("-R"):
205
- 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()
206
222
  break
207
223
  if root_path is None:
208
224
  msg = f"No Root (-R) path found in the backup definition file: '{backup_definition}', restore verification skipped"
@@ -216,18 +232,17 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
216
232
  random_files = random.sample(files, no_files_verification)
217
233
  for restored_file_path in random_files:
218
234
  try:
219
- 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")
220
236
  command = ['dar', '-x', backup_file, '-g', restored_file_path.lstrip("/"), '-R', config_settings.test_restore_dir, '-Q', '-B', args.darrc, 'restore-options']
221
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
237
+ args.verbose and logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
222
238
  process = run_command(command, config_settings.command_timeout_secs)
223
239
  if process.returncode != 0:
224
240
  raise Exception(str(process))
225
241
 
226
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):
227
- 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")
228
244
  else:
229
- logger.error(f"Failure: file '{restored_file_path}' did not match the original")
230
- result = False
245
+ raise BackupError(f"Failure: file '{restored_file_path}' did not match the original")
231
246
  except PermissionError:
232
247
  result = False
233
248
  logger.exception(f"Permission error while comparing files, continuing....")
@@ -246,6 +261,7 @@ def restore_backup(backup_name: str, config_settings: ConfigSettings, restore_di
246
261
  restore_dir (str): The directory where the backup should be restored to.
247
262
  selection (str, optional): A selection criteria to restore specific files or directories. Defaults to None.
248
263
  """
264
+ results: List[tuple] = []
249
265
  try:
250
266
  backup_file = os.path.join(config_settings.backup_dir, backup_name)
251
267
  command = ['dar', '-x', backup_file, '-Q', '-D']
@@ -274,6 +290,7 @@ def restore_backup(backup_name: str, config_settings: ConfigSettings, restore_di
274
290
  except Exception as e:
275
291
  raise RestoreError(f"Unexpected error during restore: {e}") from e
276
292
 
293
+ return results
277
294
 
278
295
 
279
296
  def get_backed_up_files(backup_name: str, backup_dir: str):
@@ -287,20 +304,14 @@ def get_backed_up_files(backup_name: str, backup_dir: str):
287
304
  Returns:
288
305
  list: A list of file paths for all backed up files in the DAR archive.
289
306
  """
290
- 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}'")
291
308
  backup_path = os.path.join(backup_dir, backup_name)
292
309
  try:
293
310
  command = ['dar', '-l', backup_path, '-am', '-as', "-Txml" , '-Q']
294
- logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
295
- process = run_command(command)
311
+ logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
312
+ command_result = run_command(command)
296
313
  # Parse the XML data
297
- root = ET.fromstring(process.stdout)
298
- output = None # help gc
299
- # Extract full paths and file size for all <file> elements
300
- file_paths = find_files_with_paths(root)
301
- root = None # help gc
302
- logger.trace(str(process))
303
- logger.trace(file_paths)
314
+ file_paths = find_files_with_paths(command_result.stdout)
304
315
  return file_paths
305
316
  except subprocess.CalledProcessError as e:
306
317
  logger.error(f"Error listing backed up files from DAR archive: '{backup_name}'")
@@ -371,7 +382,7 @@ def create_backup_command(backup_type: str, backup_file: str, darrc: str, backup
371
382
 
372
383
 
373
384
 
374
- def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, backup_type: str):
385
+ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, backup_type: str) -> List[str]:
375
386
  """
376
387
  Perform backup operation.
377
388
 
@@ -379,21 +390,27 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
379
390
  args: Command-line arguments.
380
391
  config_settings: An instance of the ConfigSettings class.
381
392
  backup_type: Type of backup (FULL, DIFF, INCR).
393
+
394
+ Returns:
395
+ List[tuples] - each tuple consists of (<str message>, <exit code>)
382
396
  """
383
- logger.debug(f"perform_backup({backup_type}) started")
384
397
  backup_definitions = []
398
+ results: List[tuple] = []
385
399
 
386
400
  # Gather backup definitions
387
401
  if args.backup_definition:
388
402
  if '_' in args.backup_definition:
389
- logger.error(f"Skipping backup definition: '{args.backup_definition}' due to '_' in name")
390
- return
403
+ msg = f"Skipping backup definition: '{args.backup_definition}' due to '_' in name"
404
+ logger.error(msg)
405
+ return results.append((msg, 1))
391
406
  backup_definitions.append((os.path.basename(args.backup_definition).split('.')[0], os.path.join(config_settings.backup_d_dir, args.backup_definition)))
392
407
  else:
393
408
  for root, _, files in os.walk(config_settings.backup_d_dir):
394
409
  for file in files:
395
410
  if '_' in file:
396
- logger.error(f"Skipping backup definition: '{file}' due to '_' in name")
411
+ msg = f"Skipping backup definition: '{file} due to '_' in: name"
412
+ logger.error(msg)
413
+ results.append((msg, 1))
397
414
  continue
398
415
  backup_definitions.append((file.split('.')[0], os.path.join(root, file)))
399
416
 
@@ -403,7 +420,9 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
403
420
  backup_file = os.path.join(config_settings.backup_dir, f"{backup_definition}_{backup_type}_{date}")
404
421
 
405
422
  if os.path.exists(backup_file + '.1.dar'):
406
- logger.error(f"Backup file {backup_file}.1.dar already exists. Skipping backup.")
423
+ msg = f"Backup file {backup_file}.1.dar already exists. Skipping backup [1]."
424
+ logger.error(msg)
425
+ results.append((msg, 1))
407
426
  continue
408
427
 
409
428
  latest_base_backup = None
@@ -414,15 +433,18 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
414
433
  latest_base_backup = os.path.join(config_settings.backup_dir, args.alternate_reference_archive)
415
434
  logger.info(f"Using alternate reference archive: {latest_base_backup}")
416
435
  if not os.path.exists(latest_base_backup + '.1.dar'):
417
- logger.error(f"Alternate reference archive: \"{latest_base_backup}.1.dar\" does not exist, exiting.")
418
- exit(1)
436
+ msg = f"Alternate reference archive: \"{latest_base_backup}.1.dar\" does not exist, exiting..."
437
+ logger.error(msg)
438
+ results.append((msg, 1))
439
+ return results
419
440
  else:
420
441
  base_backups = sorted(
421
442
  [f for f in os.listdir(config_settings.backup_dir) if f.startswith(f"{backup_definition}_{base_backup_type}_") and f.endswith('.1.dar')],
422
443
  key=lambda x: datetime.strptime(x.split('_')[-1].split('.')[0], '%Y-%m-%d')
423
444
  )
424
445
  if not base_backups:
425
- logger.warning(f"No {base_backup_type} backup found for {backup_definition}. Skipping {backup_type} backup.")
446
+ msg = f"No {base_backup_type} backup found for {backup_definition}. Skipping {backup_type} backup."
447
+ results.append((msg, 1))
426
448
  continue
427
449
  latest_base_backup = os.path.join(config_settings.backup_dir, base_backups[-1].rsplit('.', 2)[0])
428
450
 
@@ -430,26 +452,27 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
430
452
  command = create_backup_command(backup_type, backup_file, args.darrc, backup_definition_path, latest_base_backup)
431
453
 
432
454
  # Perform backup
433
- 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)
434
457
 
435
458
  logger.info("Starting verification...")
436
459
  verify_result = verify(args, backup_file, backup_definition_path, config_settings)
437
460
  if verify_result:
438
461
  logger.info("Verification completed successfully.")
439
462
  else:
440
- logger.error("Verification failed.")
441
-
442
-
463
+ msg = f"Verification of '{backup_file}' failed."
464
+ logger.error(msg)
465
+ results.append((msg, 1))
443
466
  logger.info("Generate par2 redundancy files.")
444
467
  generate_par2_files(backup_file, config_settings, args)
445
468
  logger.info("par2 files completed successfully.")
446
469
 
447
470
  except Exception as e:
448
- global RESULT
449
- RESULT = False
471
+ results.append((repr(e), 1))
450
472
  logger.exception(f"Error during {backup_type} backup process, continuing to next backup definition.")
451
473
 
452
-
474
+ logger.trace(f"perform_backup() results[]: {results}")
475
+ return results
453
476
 
454
477
  def generate_par2_files(backup_file: str, config_settings: ConfigSettings, args):
455
478
  """
@@ -506,8 +529,14 @@ def filter_darrc_file(darrc_path):
506
529
  The filtered version is stored in a uniquely named file in the home directory of the user running the script.
507
530
  The file permissions are set to 440.
508
531
 
509
- :param darrc_path: Path to the original .darrc file.
510
- :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.
511
540
  """
512
541
  # Define options to filter out
513
542
  options_to_remove = {"-vt", "-vs", "-vd", "-vf", "-va"}
@@ -593,18 +622,23 @@ INCR back of a single backup definition in backup.d
593
622
 
594
623
  def requirements(type: str, config_setting: ConfigSettings):
595
624
  """
596
- Perform PREREQ or POSTREQ requisites.
625
+ Perform PREREQ or POSTREQ requirements.
597
626
 
598
627
  Args:
599
628
  type (str): The type of prereq (PREREQ, POSTREQ).
600
629
  config_settings (ConfigSettings): An instance of the ConfigSettings class.
601
630
 
602
631
  Raises:
603
- RuntimeError: If a subprocess invoked during the backup process exits with a non-zero status.
632
+ RuntimeError: If a subprocess returns anything but zero.
633
+
634
+ subprocess.CalledProcessError: if CalledProcessError is raised in subprocess.run(), let it bobble up.
604
635
  """
605
- if str is None or config_setting is None:
606
- logger.error(f"requirements: {type} or config_setting is None, existing")
607
- raise RuntimeError(f"requirements: {type} or config_setting is None, existing")
636
+ if type is None or config_setting is None:
637
+ raise RuntimeError(f"requirements: 'type' or config_setting is None")
638
+
639
+ allowed_types = ['PREREQ', 'POSTREQ']
640
+ if type not in allowed_types:
641
+ raise RuntimeError(f"requirements: {type} not in: {allowed_types}")
608
642
 
609
643
 
610
644
  logger.info(f"Performing {type}")
@@ -613,8 +647,8 @@ def requirements(type: str, config_setting: ConfigSettings):
613
647
  script = config_setting.config[type][key]
614
648
  try:
615
649
  result = subprocess.run(script, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
616
- logger.info(f"{type} {key}: '{script}' run, return code: {result.returncode}")
617
- 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}")
618
652
  if result.returncode != 0:
619
653
  logger.error(f"{type} stderr:\n{result.stderr}")
620
654
  raise RuntimeError(f"{type} {key}: '{script}' failed, return code: {result.returncode}")
@@ -624,7 +658,8 @@ def requirements(type: str, config_setting: ConfigSettings):
624
658
 
625
659
 
626
660
  def main():
627
- global logger, RESULT
661
+ global logger
662
+ results: List[(str,int)] = [] # a list op tuples (<msg>, <exit code>)
628
663
 
629
664
  MIN_PYTHON_VERSION = (3, 9)
630
665
  if version_info < MIN_PYTHON_VERSION:
@@ -692,9 +727,9 @@ def main():
692
727
  exit(127)
693
728
 
694
729
  if args.suppress_dar_msg:
695
- 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")
696
731
  args.darrc = filter_darrc_file(args.darrc)
697
- logger.debug(f"Filtered .darrc file saved at: {args.darrc}")
732
+ logger.debug(f"Filtered .darrc file: {args.darrc}")
698
733
 
699
734
  start_time=int(time())
700
735
  logger.info(f"=====================================")
@@ -737,39 +772,58 @@ def main():
737
772
  if args.list:
738
773
  list_backups(config_settings.backup_dir, args.backup_definition)
739
774
  elif args.full_backup and not args.differential_backup and not args.incremental_backup:
740
- perform_backup(args, config_settings, "FULL")
775
+ results.extend(perform_backup(args, config_settings, "FULL"))
741
776
  elif args.differential_backup and not args.full_backup and not args.incremental_backup:
742
- perform_backup(args, config_settings, "DIFF")
777
+ results.extend(perform_backup(args, config_settings, "DIFF"))
743
778
  elif args.incremental_backup and not args.full_backup and not args.differential_backup:
744
- perform_backup(args, config_settings, "INCR")
779
+ results.extend(perform_backup(args, config_settings, "INCR"))
780
+ logger.debug(f"results from perform_backup(): {results}")
745
781
  elif args.list_contents:
746
782
  list_contents(args.list_contents, config_settings.backup_dir, args.selection)
747
783
  elif args.restore:
748
784
  logger.debug(f"Restoring {args.restore} to {restore_dir}")
749
- restore_backup(args.restore, config_settings, restore_dir, args.darrc, args.selection)
785
+ results.extend(restore_backup(args.restore, config_settings, restore_dir, args.darrc, args.selection))
750
786
  else:
751
787
  parser.print_help()
752
788
 
789
+ logger.debug(f"results[]: {results}")
790
+
753
791
  requirements('POSTREQ', config_settings)
754
792
 
755
793
  except Exception as e:
756
- logger.exception("An error occurred")
757
794
  logger.error("Exception details:", exc_info=True)
758
- args.verbose and print("\033[1m\033[31mErrors\033[0m encountered")
759
- RESULT = False
795
+ results.append((repr(e), 1))
760
796
  finally:
761
797
  end_time=int(time())
762
798
  logger.info(f"END TIME: {end_time}")
763
799
  # Clean up
764
- 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("~"):
765
801
  if args.darrc.startswith("filtered_darrc_"):
766
802
  os.remove(args.darrc)
767
- logger.info(f"Removed filtered .darrc: {args.darrc}")
768
-
769
-
770
- if RESULT:
771
- exit(0)
772
- else:
803
+ logger.debug(f"Removed filtered .darrc: {args.darrc}")
804
+
805
+
806
+ # Determine exit code
807
+ error = False
808
+ logger.debug(f"results[]: {results}")
809
+ if results:
810
+ i = 0
811
+ for result in results:
812
+ if isinstance(result, tuple) and len(result) == 2:
813
+ msg, exit_code = result
814
+ logger.debug(f"exit code: {exit_code}, msg: {msg}")
815
+ if exit_code > 0:
816
+ error = True
817
+ args.verbose and print(msg)
818
+ else:
819
+ logger.error(f"not correct result type: {result}, which must be a tuple (<msg>, <exit_code>)")
820
+ i=i+1
821
+ if error:
822
+ args.verbose and print("\033[1m\033[31mErrors\033[0m encountered")
773
823
  exit(1)
824
+ else:
825
+ args.verbose and print("\033[1m\033[32mSuccess\033[0m all backups completed")
826
+ exit(0)
827
+
774
828
  if __name__ == "__main__":
775
829
  main()
dar_backup/manager.py CHANGED
@@ -233,7 +233,7 @@ def add_specific_archive(archive: str, config_settings: ConfigSettings, director
233
233
  database_path = os.path.realpath(os.path.join(config_settings.backup_dir, database))
234
234
  logger.info(f'Add "{archive_path}" to catalog: "{database}"')
235
235
 
236
- command = ['dar_manager', '--base', database_path, "--add", archive_path, "-ai", "-Q"]
236
+ command = ['dar_manager', '--base', database_path, "--add", archive_path, "-Q"]
237
237
  process = run_command(command)
238
238
  stdout, stderr = process.stdout, process.stderr
239
239
 
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.13.1
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
@@ -1355,6 +1355,8 @@ In order to not clutter that log file with the output of commands being run, a n
1355
1355
  - FULL, DIFF and INCR backups.
1356
1356
  - cleanup.
1357
1357
 
1358
+ - fix --log-stdout spams console with command output
1359
+
1358
1360
  ## Reference
1359
1361
 
1360
1362
  ### dar-backup
@@ -0,0 +1,16 @@
1
+ dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
2
+ dar_backup/__about__.py,sha256=9pegTLVQP2o3JePGrLB6muzXif64umv9ihLnS7LsH8E,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=1g2si9-jPEL8T4OKaiGSKFGsF6rWh-Ke1-zQHE7HaPc,11703
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=TrYMYNbQ9jWabWGc7GA5p2ezprLqMUu9O0zt6CQ1QSA,37867
9
+ dar_backup/installer.py,sha256=ehp4KSgTc8D9Edsyve5v3NY2MuDbuTFYQQPgou8woV8,4331
10
+ dar_backup/manager.py,sha256=sQl0xdWwBgui11S9Ekg0hOSC4gt89nz_Z8Bt8IPXCDw,21640
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,,
@@ -1,16 +0,0 @@
1
- dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
2
- dar_backup/__about__.py,sha256=WhY38gJ9InHtiokbumhF5t6Q_JtwytMg5oigYIZ6CZ0,24
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=1g2si9-jPEL8T4OKaiGSKFGsF6rWh-Ke1-zQHE7HaPc,11703
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=yJjDqyPBWsjsMZeMbEgLzLt0N8R2y-YZGdfxvZjm8gs,35723
9
- dar_backup/installer.py,sha256=ehp4KSgTc8D9Edsyve5v3NY2MuDbuTFYQQPgou8woV8,4331
10
- dar_backup/manager.py,sha256=VBeZEIETDL_Lxhmo-T47xSQAxbOPGU-ZLI7GFXJx-Go,21647
11
- dar_backup/util.py,sha256=lfgfxC_C6x3I8f9vzyxpQE7P-7rm6tTEr3P-2uWlVtQ,12278
12
- dar_backup-0.6.13.1.dist-info/METADATA,sha256=zWP8JXewEWB5x-dbTjnDBJ8PBFiFdwBPtkptaSP9Fg4,72698
13
- dar_backup-0.6.13.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
- dar_backup-0.6.13.1.dist-info/entry_points.txt,sha256=Z7P5BUbhtJxo8_nB9qNIMay2eGDbsMKB3Fjwv3GMa4g,202
15
- dar_backup-0.6.13.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
- dar_backup-0.6.13.1.dist-info/RECORD,,