]> arthur.barton.de Git - bup.git/commitdiff
index: always return at least the root for filter prefixes
authorRob Browning <rlb@defaultvalue.org>
Mon, 21 Dec 2015 19:35:24 +0000 (13:35 -0600)
committerRob Browning <rlb@defaultvalue.org>
Mon, 22 Feb 2016 00:16:10 +0000 (18:16 -0600)
Return at least an entry for the prefix itself for each prefix passed
to filter.  Otherwise something like "bup save ... x/y" will fail when
x is up to date because filter will return nothing, save will traverse
nothing in its main loop, and bup will crash with an assertion
failure:

  File "/home/rlb/src/bup/main/cmd/bup-save", line 440, in <module>
    assert(len(shalists) == 1)

Instead "bup save ... x/y" should (and now will) produce a new save
containing x/y.

Thanks to Simon Persson for helping formulate a good test case.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
Makefile
lib/bup/index.py
t/test-save-with-valid-parent.sh [new file with mode: 0755]

index 51d04acbe559cd0516f0cc82dd65ed8801432e68..79fbcb36e9e04e41efc03f36e06c5aea67653ac5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -165,6 +165,7 @@ cmdline_tests := \
   t/test-restore-map-owner.sh \
   t/test-restore-single-file.sh \
   t/test-rm-between-index-and-save.sh \
+  t/test-save-with-valid-parent.sh \
   t/test-sparse-files.sh \
   t/test-command-without-init-fails.sh \
   t/test-redundant-saves.sh \
index 0829764824b0cea02cd44972ac154d403d6b71da..8eabfbbc7bb7fa88353b90abdff113dff7b7e12e 100644 (file)
@@ -406,6 +406,11 @@ class Reader:
     def __iter__(self):
         return self.iter()
 
+    def find(self, name):
+        return next((e for e in self.iter(name, wantrecurse=lambda x : True)
+                     if e.name == name),
+                    None)
+
     def exists(self):
         return self.m
 
@@ -422,11 +427,20 @@ class Reader:
 
     def filter(self, prefixes, wantrecurse=None):
         for (rp, path) in reduce_paths(prefixes):
+            any_entries = False
             for e in self.iter(rp, wantrecurse=wantrecurse):
+                any_entries = True
                 assert(e.name.startswith(rp))
                 name = path + e.name[len(rp):]
                 yield (name, e)
-
+            if not any_entries:
+                # Always return at least the top for each prefix.
+                # Otherwise something like "save x/y" will produce
+                # nothing if x is up to date.
+                pe = self.find(rp)
+                assert(pe)
+                name = path + pe.name[len(rp):]
+                yield (name, pe)
 
 # FIXME: this function isn't very generic, because it splits the filename
 # in an odd way and depends on a terminating '/' to indicate directories.
diff --git a/t/test-save-with-valid-parent.sh b/t/test-save-with-valid-parent.sh
new file mode 100755 (executable)
index 0000000..f817165
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+. ./wvtest-bup.sh || exit $?
+. t/lib.sh || exit $?
+
+set -o pipefail
+
+top="$(WVPASS pwd)" || exit $?
+tmpdir="$(WVPASS wvmktempdir)" || exit $?
+
+export BUP_DIR="$tmpdir/bup"
+export GIT_DIR="$tmpdir/bup"
+
+bup() { "$top/bup" "$@"; }
+compare-trees() { "$top/t/compare-trees" "$@"; }
+
+WVPASS cd "$tmpdir"
+
+# Make sure that we can explicitly save a path whose parent is up to
+# date.
+
+WVSTART "save path with up to date parent"
+WVPASS bup init
+
+WVPASS mkdir -p src/a src/b
+WVPASS touch src/a/1 src/b/2
+WVPASS bup index -u src
+WVPASS bup save -n src src
+
+WVPASS bup save -n src src/b
+WVPASS bup restore -C restore "src/latest/$(pwd)/"
+WVPASS test ! -e restore/src/a
+WVPASS "$top/t/compare-trees" -c src/b/ restore/src/b/
+
+WVPASS bup save -n src src/a/1
+WVPASS rm -r restore
+WVPASS bup restore -C restore "src/latest/$(pwd)/"
+WVPASS test ! -e restore/src/b
+WVPASS "$top/t/compare-trees" -c src/a/ restore/src/a/
+
+WVPASS rm -rf "$tmpdir"