dar-backup 0.6.20__py3-none-any.whl → 0.6.20.1__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/Changelog.md CHANGED
@@ -1,6 +1,15 @@
1
1
  <!-- markdownlint-disable MD024 -->
2
2
  # dar-backup Changelog
3
3
 
4
+ ## v2-beta-0.6.20.1 - 2025-05-04
5
+
6
+ Github link: [v2-beta-0.6.20.1](https://github.com/per2jensen/dar-backup/tree/v2-beta-0.6.20.1/v2)
7
+
8
+ ### Added
9
+
10
+ - FIX: bash/zsh completers fixed to support MANAGER_DB_DIR config if set
11
+ - `cleanup` and `manager` completer now sorts archives by \<backup-definition> and \<archive date> (so not using \<type>)
12
+
4
13
  ## v2-beta-0.6.20 - 2025-05-03
5
14
 
6
15
  Github link: [v2-beta-0.6.20](https://github.com/per2jensen/dar-backup/tree/v2-beta-0.6.20/v2)
dar_backup/__about__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.6.20"
1
+ __version__ = "0.6.20.1"
dar_backup/manager.py CHANGED
@@ -535,7 +535,6 @@ def main():
535
535
 
536
536
  args.config_file = os.path.expanduser(os.path.expandvars(args.config_file))
537
537
  config_settings = ConfigSettings(args.config_file)
538
- print(f"Config settings: {config_settings}")
539
538
 
540
539
  if not os.path.dirname(config_settings.logfile_location):
541
540
  print(f"Directory for log file '{config_settings.logfile_location}' does not exist, exiting")
dar_backup/util.py CHANGED
@@ -102,6 +102,24 @@ def get_logger(command_output_logger: bool = False) -> logging.Logger:
102
102
 
103
103
  return secondary_logger if command_output_logger else logger
104
104
 
105
+
106
+ # Setup completer logger only once
107
+ def _setup_completer_logger(logfile="/tmp/dar_backup_completer.log"):
108
+ logger = logging.getLogger("completer")
109
+ if not logger.handlers:
110
+ handler = logging.FileHandler(logfile)
111
+ formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
112
+ handler.setFormatter(formatter)
113
+ logger.addHandler(handler)
114
+ logger.setLevel(logging.DEBUG)
115
+ return logger
116
+
117
+ # Singleton logger for completer debugging
118
+ completer_logger = _setup_completer_logger()
119
+ completer_logger.debug("Completer logger initialized.")
120
+
121
+
122
+
105
123
  def show_version():
106
124
  script_name = os.path.basename(sys.argv[0])
107
125
  print(f"{script_name} {about.__version__}")
@@ -346,6 +364,7 @@ def extract_backup_definition_fallback() -> str:
346
364
 
347
365
 
348
366
 
367
+
349
368
  def list_archive_completer(prefix, parsed_args, **kwargs):
350
369
  import os
351
370
  import configparser
@@ -369,12 +388,39 @@ def list_archive_completer(prefix, parsed_args, **kwargs):
369
388
  files = os.listdir(backup_dir)
370
389
  archive_re = re.compile(rf"^{re.escape(backup_def)}_.+_\d{{4}}-\d{{2}}-\d{{2}}\.1\.dar$") if backup_def else re.compile(r".+_\d{4}-\d{2}-\d{2}\.1\.dar$")
371
390
 
372
- return [
391
+ completions = [
373
392
  f.rsplit(".1.dar", 1)[0]
374
393
  for f in files
375
394
  if archive_re.match(f)
376
395
  ]
377
396
 
397
+ completions = sorted(set(completions), key=sort_key)
398
+ return completions or ["[no matching archives]"]
399
+
400
+
401
+
402
+ def sort_key(archive_name: str):
403
+ """
404
+ Sort by backup definition and then by date extracted from the archive name.
405
+ Handles formats like: <def>_<TYPE>_<YYYY-MM-DD>.<N>.dar
406
+ """
407
+ try:
408
+ base = archive_name.split('.')[0] # remove .1.dar
409
+ parts = base.split('_')
410
+ if len(parts) < 3:
411
+ return (archive_name, datetime.min) # fallback for non-matching formats
412
+
413
+ # Correct assumption: last two parts are TYPE and DATE
414
+ def_name = '_'.join(parts[:-2]) # everything before _TYPE_DATE
415
+ date_str = parts[-1]
416
+ date = datetime.strptime(date_str, "%Y-%m-%d")
417
+ completer_logger.debug(f"Archive: {archive_name}, Def: {def_name}, Date: {date}")
418
+ return (def_name, date)
419
+ except Exception:
420
+ return (archive_name, datetime.min)
421
+
422
+
423
+
378
424
 
379
425
  def archive_content_completer(prefix, parsed_args, **kwargs):
380
426
  """
@@ -392,14 +438,15 @@ def archive_content_completer(prefix, parsed_args, **kwargs):
392
438
  # Expand config path
393
439
  config_file = expand_path(getattr(parsed_args, "config_file", "~/.config/dar-backup/dar-backup.conf"))
394
440
  config = ConfigSettings(config_file=config_file)
395
- backup_dir = config.backup_dir
441
+ #db_dir = expand_path((getattr(config, 'manager_db_dir', config.backup_dir))) # use manager_db_dir if set, else backup_dir
442
+ db_dir = expand_path(getattr(config, 'manager_db_dir', None) or config.backup_dir)
396
443
 
397
444
  # Which db files to inspect?
398
445
  backup_def = getattr(parsed_args, "backup_def", None)
399
446
  db_files = (
400
- [os.path.join(backup_dir, f"{backup_def}.db")]
447
+ [os.path.join( db_dir, f"{backup_def}.db")]
401
448
  if backup_def
402
- else [os.path.join(backup_dir, f) for f in os.listdir(backup_dir) if f.endswith(".db")]
449
+ else [os.path.join( db_dir, f) for f in os.listdir( db_dir) if f.endswith(".db")]
403
450
  )
404
451
 
405
452
  completions = []
@@ -426,13 +473,6 @@ def archive_content_completer(prefix, parsed_args, **kwargs):
426
473
  if archive.startswith(prefix):
427
474
  completions.append(archive)
428
475
 
429
- # Sort: first by name (before first '_'), then by date (YYYY-MM-DD)
430
- def sort_key(archive):
431
- name_part = archive.split("_")[0]
432
- date_match = re.search(r"\d{4}-\d{2}-\d{2}", archive)
433
- date = datetime.strptime(date_match.group(0), "%Y-%m-%d") if date_match else datetime.min
434
- return (name_part, date)
435
-
436
476
  completions = sorted(set(completions), key=sort_key)
437
477
  return completions or ["[no matching archives]"]
438
478
 
@@ -452,6 +492,8 @@ def add_specific_archive_completer(prefix, parsed_args, **kwargs):
452
492
 
453
493
  config_file = expand_path(getattr(parsed_args, "config_file", "~/.config/dar-backup/dar-backup.conf"))
454
494
  config = ConfigSettings(config_file=config_file)
495
+ #db_dir = expand_path((getattr(config, 'manager_db_dir', config.backup_dir))) # use manager_db_dir if set, else backup_dir
496
+ db_dir = expand_path(getattr(config, 'manager_db_dir') or config.backup_dir)
455
497
  backup_dir = config.backup_dir
456
498
  backup_def = getattr(parsed_args, "backup_def", None)
457
499
 
@@ -469,7 +511,7 @@ def add_specific_archive_completer(prefix, parsed_args, **kwargs):
469
511
  all_archives.add(base)
470
512
 
471
513
  # Step 2: exclude ones already present in the .db
472
- db_path = os.path.join(backup_dir, f"{backup_def}.db") if backup_def else None
514
+ db_path = os.path.join(db_dir, f"{backup_def}.db") if backup_def else None
473
515
  existing = set()
474
516
 
475
517
  if db_path and os.path.exists(db_path):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dar-backup
3
- Version: 0.6.20
3
+ Version: 0.6.20.1
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: GPG Public Key, https://keys.openpgp.org/search?q=dar-backup@pm.me
6
6
  Project-URL: Homepage, https://github.com/per2jensen/dar-backup/tree/main/v2
@@ -1,7 +1,7 @@
1
1
  dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
2
- dar_backup/Changelog.md,sha256=hFz5NoZyezxgKza9i4VBv57aPnCuzhIQM9yK_2cxAZ8,9107
2
+ dar_backup/Changelog.md,sha256=D993XIep6ECnK42XdH6ayE8RlXDJVCbpr-SeCqEFRH8,9448
3
3
  dar_backup/README.md,sha256=PcZQRaBw9i_GbRoA786OFKI0PwY87E7D30UzovWqEQQ,44902
4
- dar_backup/__about__.py,sha256=bhh1JgaMOqVsHTPoLk0PdjZxyDSXmYzOzEaRGXYuakc,22
4
+ dar_backup/__about__.py,sha256=rQMac36Uw_nIjFumz9vuaDITRsJHLv1bbxAZYx-Ka4E,24
5
5
  dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  dar_backup/clean_log.py,sha256=uQ_9HomK7RRkskXrgMPbAC84RgNlCFJ8RHL9KHeAMvc,5447
7
7
  dar_backup/cleanup.py,sha256=4IG736gdmvjurcQQ_DC-B5CoA3Ix9u5C3WfwmMmFIpc,12500
@@ -13,11 +13,11 @@ dar_backup/dar_backup_systemd.py,sha256=oehD_t9CFu0CsMgDWRH-Gt74Ynl1m29yqQEh5Kxv
13
13
  dar_backup/demo.py,sha256=fl2LHHWxuXRT814M_zuZh_YqqLk6nuNg9BI9HpLzdUU,4841
14
14
  dar_backup/exceptions.py,sha256=6fpHpnhkbtFcFZVDMqCsdESg-kQNCjF40EROGKeq8yU,113
15
15
  dar_backup/installer.py,sha256=gISJ3inz1uTjM5235gNtwjDUG-Fq6b3OZzMQuJl5eRg,2252
16
- dar_backup/manager.py,sha256=UyEcm9ydkok47slgSlpPEKP_mAdkvcwCghLCXdNlGpc,26622
16
+ dar_backup/manager.py,sha256=JL-JX2C6RiDIj64Gw9pxNLUpxFqij1OBPp1BaUvV5sM,26573
17
17
  dar_backup/rich_progress.py,sha256=jTwM-4VlqHHzKqIfyXjL1pWEriobSJwCdN3YXzXzRdo,3105
18
- dar_backup/util.py,sha256=2Uwd1bf3N-AEzIvc69gvwEnGXNYNzZ-RqxUfbvmOUAc,20079
19
- dar_backup-0.6.20.dist-info/METADATA,sha256=dO6-9MvI9M_munyvCVFGNrq33NBbDDxn6UAIRLwVb5U,86624
20
- dar_backup-0.6.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
- dar_backup-0.6.20.dist-info/entry_points.txt,sha256=jFMqGdvGO8NeHrmcB0pxY7__PCSQAWRCFzsschMXsec,248
22
- dar_backup-0.6.20.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
23
- dar_backup-0.6.20.dist-info/RECORD,,
18
+ dar_backup/util.py,sha256=u_l6Hti6ZAHxaOqTZlSWBDspoKmkdoyzfZjhQgJqyOQ,21643
19
+ dar_backup-0.6.20.1.dist-info/METADATA,sha256=bD9ou-yK2zva5xz8vPVd57xqkEsjN9OaNAWZeoxDajE,86626
20
+ dar_backup-0.6.20.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ dar_backup-0.6.20.1.dist-info/entry_points.txt,sha256=jFMqGdvGO8NeHrmcB0pxY7__PCSQAWRCFzsschMXsec,248
22
+ dar_backup-0.6.20.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
23
+ dar_backup-0.6.20.1.dist-info/RECORD,,