Repository: borgbackup/borg

Issue:
traceback when trying to delete non-existent archive
From the borgbackup mailing list:

I am testing out borg, and accidentally did:

```
borg create borgrepo::test4 ~
```

after 3 previous test archives were created using an --exclude-if-present .nobackup option.

When I noticed the missing --exclude-if-present in the above create (because it was taking too
long), I ^C'ed it, then tried:

```
borg delete borgrepo::test4
```

and got this failure (<...> obfuscations added):

```
Local Exception
Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/borg/archiver.py", line 4501, in main
    exit_code = archiver.run(args)
  File "/usr/lib/python3.7/site-packages/borg/archiver.py", line 4433, in run
    return set_ec(func(args))
  File "/usr/lib/python3.7/site-packages/borg/archiver.py", line 166, in wrapper
    return method(self, args, repository=repository, **kwargs)
  File "/usr/lib/python3.7/site-packages/borg/archiver.py", line 1257, in do_delete
    return self._delete_archives(args, repository)
  File "/usr/lib/python3.7/site-packages/borg/archiver.py", line 1304, in _delete_archives
    logger.info(msg.format(format_archive(manifest.archives[archive_name]), i, len(archive_names)))
  File "/usr/lib/python3.7/site-packages/borg/helpers.py", line 244, in __getitem__
    raise KeyError
KeyError

Platform: Linux <...> 5.3.6-1-MANJARO #1 SMP PREEMPT Sat Oct 12 09:30:05
UTC 2019 x86_64 Linux: arch Manjaro Linux
Borg: 1.1.10  Python: CPython 3.7.4 msgpack: 0.5.6
PID: 10547  CWD: <...>
sys.argv: ['/usr/bin/borg', 'delete', 'borgrepo::test4']
SSH_ORIGINAL_COMMAND: None
```

Is this borgrepo now fried?  If not, how can I recover it?



Discussion:
No, the repo is not fried, everything is fine.

But that is a rather unpretty way to say "archive test4 not found".
i just stumbled across this issue and wondered if the text shouldn't be the same as when the `list` command was issued on a non-existinng archive ?
Which is ''Archive XYZ does not exist' rather than "Archive XYZ not found".
 
Yeah, using the same message is of course preferable for consistency reasons.

Resolving patch:
diff --git a/src/borg/archiver.py b/src/borg/archiver.py
--- a/src/borg/archiver.py
+++ b/src/borg/archiver.py
@@ -1144,13 +1144,20 @@ def _delete_archives(self, args, repository):
 
         stats = Statistics()
         with Cache(repository, key, manifest, progress=args.progress, lock_wait=self.lock_wait) as cache:
+            msg_delete = 'Would delete archive: {} ({}/{})' if dry_run else 'Deleting archive: {} ({}/{})'
+            msg_not_found = 'Archive {} not found ({}/{}).'
             for i, archive_name in enumerate(archive_names, 1):
-                msg = 'Would delete archive: {} ({}/{})' if dry_run else 'Deleting archive: {} ({}/{})'
-                logger.info(msg.format(format_archive(manifest.archives[archive_name]), i, len(archive_names)))
-                if not dry_run:
-                    archive = Archive(repository, key, manifest, archive_name, cache=cache,
-                                      consider_part_files=args.consider_part_files)
-                    archive.delete(stats, progress=args.progress, forced=args.forced)
+                try:
+                    archive_info = manifest.archives[archive_name]
+                except KeyError:
+                    logger.warning(msg_not_found.format(archive_name, i, len(archive_names)))
+                else:
+                    logger.info(msg_delete.format(format_archive(archive_info), i, len(archive_names)))
+                    if not dry_run:
+                        archive = Archive(repository, key, manifest, archive_name, cache=cache,
+                                          consider_part_files=args.consider_part_files)
+                        archive.delete(stats, progress=args.progress, forced=args.forced)
+
             if not dry_run:
                 manifest.write()
                 repository.commit(compact=False, save_space=args.save_space)


Test patch: