Have the lbs-util command check the version of a snapshot when it is read,
and signal an error if the version is newer than what is supported, so that
silent failures do not occur if the format is changed in the future.
from optparse import OptionParser
import lbs
from optparse import OptionParser
import lbs
+# We support up to "LBS Snapshot v0.2" formats, but are also limited by the lbs
+# module.
+FORMAT_VERSION = min(lbs.FORMAT_VERSION, (0, 2))
+
+def check_version(format):
+ ver = lbs.parse_metadata_version(format)
+ if ver > FORMAT_VERSION:
+ raise RuntimeError("Unsupported LBS format: " + format)
+
parser = OptionParser(usage="%prog [option]... command [arg]...")
parser.add_option("-v", action="store_true", dest="verbose", default=False,
help="increase verbosity")
parser = OptionParser(usage="%prog [option]... command [arg]...")
parser.add_option("-v", action="store_true", dest="verbose", default=False,
help="increase verbosity")
previous = set()
for s in sorted(lowlevel.list_snapshots()):
d = lbs.parse_full(store.load_snapshot(s))
previous = set()
for s in sorted(lowlevel.list_snapshots()):
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
segments = d['Segments'].split()
(size, added, removed) = (0, 0, 0)
for seg in segments:
segments = d['Segments'].split()
(size, added, removed) = (0, 0, 0)
for seg in segments:
store = lbs.ObjectStore(lowlevel)
for s in snapshots:
d = lbs.parse_full(store.load_snapshot(s))
store = lbs.ObjectStore(lowlevel)
for s in snapshots:
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
print d
print d['Segments'].split()
store.cleanup()
print d
print d['Segments'].split()
store.cleanup()
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
d = lbs.parse_full(store.load_snapshot(snapshot))
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
d = lbs.parse_full(store.load_snapshot(snapshot))
+ check_version(d['Format'])
metadata = lbs.read_metadata(store, d['Root'])
for l in metadata:
sys.stdout.write(l)
metadata = lbs.read_metadata(store, d['Root'])
for l in metadata:
sys.stdout.write(l)
for s in snapshots:
print "#### Snapshot", s
d = lbs.parse_full(store.load_snapshot(s))
for s in snapshots:
print "#### Snapshot", s
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
print "## Root:", d['Root']
metadata = lbs.iterate_metadata(store, d['Root'])
for m in metadata:
print "## Root:", d['Root']
metadata = lbs.iterate_metadata(store, d['Root'])
for m in metadata:
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
snapshot = lbs.parse_full(store.load_snapshot(args[0]))
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
snapshot = lbs.parse_full(store.load_snapshot(args[0]))
+ check_version(snapshot['Format'])
destdir = args[1]
paths = args[2:]
destdir = args[1]
paths = args[2:]
import os, re, sha, tarfile, tempfile, thread
from pysqlite2 import dbapi2 as sqlite3
import os, re, sha, tarfile, tempfile, thread
from pysqlite2 import dbapi2 as sqlite3
+# The largest supported snapshot format that can be understood.
+FORMAT_VERSION = (0, 2) # LBS Snapshot v0.2
+
# Maximum number of nested indirect references allowed in a snapshot.
MAX_RECURSION_DEPTH = 3
# Maximum number of nested indirect references allowed in a snapshot.
MAX_RECURSION_DEPTH = 3
except StopIteration:
return {}
except StopIteration:
return {}
+def parse_metadata_version(s):
+ """Convert a string with the snapshot version format to a tuple."""
+
+ m = re.match(r"^LBS Snapshot v(\d+(\.\d+)*)$", s)
+ if m is None:
+ return ()
+ else:
+ return tuple([int(d) for d in m.group(1).split(".")])
+
def read_metadata(object_store, root):
"""Iterate through all lines in the metadata log, following references."""
def read_metadata(object_store, root):
"""Iterate through all lines in the metadata log, following references."""