Repository: borgbackup/borg

Issue:
borg delete (archives): commit only once
see do_prune: it also deletes multiple archives, but commits only once.

if we can do that for borg prune, we can also do it for borg delete (and be quicker).


---

:moneybag: [there is a bounty for this](https://www.bountysource.com/issues/58448740-borg-delete-archives-commit-only-once)


Discussion:
Is this available for bounty hunters from bountysource.com?

@nemaniarjun I planned to work on it, but if you like, you can try first (so: "yes").
@nemaniarjun if you want to work on it, tell so - here and on bountysource.
Hey, yes I am working on this! 

Need a bit of help setting up the development env though, 
I am using pipenv to manage my virtualenv, the installation runs fine but when I run,
`fakeroot -u tox` it gives me error, unable to install dependencies.
Also when I run 
`py.test` directly the test `test_prune_split[hourly-3-expected_ids4] ` fails.  

I will try again with venv
@nemaniarjun are you talking about master or 1.1-maint branch?

About `unable to install dependencies` - file a bug please with all the details.

Beside some spurious failures (usually `IsADirectoryError`) caused by fakeroot, the tests should work.

It is taking me longer than expected to get to this, is it fine if this is done by next week? If not, feel free to unassign me.
Dear @nemaniarjun, I would need the solution rather soon because our backup space is full. So if you would not mind, then I'd prefer to open up the task again for @ThomasWaldmann or others to work on it.
Considering above, I'll also work on it.

Resolving patch:
diff --git a/src/borg/archiver.py b/src/borg/archiver.py
--- a/src/borg/archiver.py
+++ b/src/borg/archiver.py
@@ -1262,27 +1262,21 @@ def _delete_archives(self, args, repository):
                 logger.warning('Aborted.')
             return self.exit_code
 
-        stats_logger = logging.getLogger('borg.output.stats')
-        if args.stats:
-            log_multi(DASHES, STATS_HEADER, logger=stats_logger)
-
+        stats = Statistics()
         with Cache(repository, key, manifest, progress=args.progress, lock_wait=self.lock_wait) as cache:
             for i, archive_name in enumerate(archive_names, 1):
-                logger.info('Deleting {} ({}/{}):'.format(archive_name, i, len(archive_names)))
-                archive = Archive(repository, key, manifest, archive_name, cache=cache)
-                stats = Statistics()
-                archive.delete(stats, progress=args.progress, forced=args.forced)
-                manifest.write()
-                repository.commit(save_space=args.save_space)
-                cache.commit()
-                logger.info("Archive deleted.")
-                if args.stats:
-                    log_multi(stats.summary.format(label='Deleted data:', stats=stats),
-                              DASHES, logger=stats_logger)
-                if args.forced == 0 and self.exit_code:
-                    break
+                logger.info('Deleting archive: {} ({}/{})'.format(archive_name, i, len(archive_names)))
+                Archive(repository, key, manifest, archive_name, cache=cache).delete(
+                    stats, progress=args.progress, forced=args.forced)
+            manifest.write()
+            repository.commit(save_space=args.save_space)
+            cache.commit()
             if args.stats:
-                stats_logger.info(str(cache))
+                log_multi(DASHES,
+                          STATS_HEADER,
+                          stats.summary.format(label='Deleted data:', stats=stats),
+                          str(cache),
+                          DASHES, logger=logging.getLogger('borg.output.stats'))
 
         return self.exit_code
 


Test patch: