Repository: borgbackup/borg

Issue:
Incorrect borg prune --stats output with --dry-run
With `borg 1.1.7` on `ubuntu 18.10`:
```
borg prune <borg_dir> --dry-run --list --stats --keep-last 1 
...
                       Original size      Compressed size    Deduplicated size
Deleted data:                    0 B                  0 B                  0 B
All archives:              981.25 GB            793.40 GB            112.32 GB

                       Unique chunks         Total chunks
Chunk index:                  250054              2164226
```
```
borg prune <borg_dir> --list --stats --keep-last 1 
...
                       Original size      Compressed size    Deduplicated size
Deleted data:             -820.45 GB           -669.72 GB             -9.60 GB
All archives:              160.80 GB            123.69 GB            102.72 GB

                       Unique chunks         Total chunks
Chunk index:                  237044               371408
```
Pruning worked as I wanted it to, but the dry run stats do not give an accurate preview.


Discussion:
Likely, that is simply not implemented (just guessing, needs to be checked in the src).

Resolving patch:
diff --git a/src/borg/archive.py b/src/borg/archive.py
--- a/src/borg/archive.py
+++ b/src/borg/archive.py
@@ -999,6 +999,7 @@ def process_stdin(self, path, cache):
 
     def process_file(self, path, st, cache):
         with self.create_helper(path, st, None) as (item, status, hardlinked, hardlink_master):  # no status yet
+            item.update(self.stat_simple_attrs(st))
             is_special_file = is_special(st.st_mode)
             if not hardlinked or hardlink_master:
                 if not is_special_file:
@@ -1023,7 +1024,6 @@ def process_file(self, path, st, cache):
                 else:
                     status = 'M' if known else 'A'  # regular file, modified or added
                 item.hardlink_master = hardlinked
-                item.update(self.stat_simple_attrs(st))
                 # Only chunkify the file if needed
                 if chunks is not None:
                     item.chunks = chunks
@@ -1037,7 +1037,7 @@ def process_file(self, path, st, cache):
                         # block or char device will change without its mtime/size/inode changing.
                         cache.memorize_file(path_hash, st, [c.id for c in item.chunks])
                 self.stats.nfiles += 1
-            item.update(self.stat_attrs(st, path))
+            item.update(self.stat_ext_attrs(st, path))
             item.get_size(memorize=True)
             if is_special_file:
                 # we processed a special file like a regular file. reflect that in mode,
diff --git a/src/borg/archiver.py b/src/borg/archiver.py
--- a/src/borg/archiver.py
+++ b/src/borg/archiver.py
@@ -4360,6 +4360,9 @@ def run(self, args):
         args.progress |= is_serve
         self._setup_implied_logging(vars(args))
         self._setup_topic_debugging(args)
+        if getattr(args, 'stats', False) and getattr(args, 'dry_run', False):
+            logger.error("--stats does not work with --dry-run.")
+            return self.exit_code
         if args.show_version:
             logging.getLogger('borg.output.show-version').info('borgbackup version %s' % __version__)
         self.prerun_checks(logger)
diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py
--- a/src/borg/testsuite/archiver.py
+++ b/src/borg/testsuite/archiver.py
@@ -1844,10 +1844,9 @@ def test_prune_repository_save_space(self):
         self.cmd('init', '--encryption=repokey', self.repository_location)
         self.cmd('create', self.repository_location + '::test1', src_dir)
         self.cmd('create', self.repository_location + '::test2', src_dir)
-        output = self.cmd('prune', '--list', '--stats', '--dry-run', self.repository_location, '--keep-daily=2')
+        output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=2')
         self.assert_in('Keeping archive: test2', output)
         self.assert_in('Would prune:     test1', output)
-        self.assert_in('Deleted data:', output)
         output = self.cmd('list', self.repository_location)
         self.assert_in('test1', output)
         self.assert_in('test2', output)


Test patch: