mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-04-26 13:59:59 +00:00
#619: make 'tahoe backup' complain and refuse to run if sqlite is unavailable and --no-backupdb is not passed
This commit is contained in:
parent
7bf7922ea1
commit
f7a263eb0b
@ -50,7 +50,22 @@ def get_backupdb(dbfile, stderr=sys.stderr):
|
|||||||
from pysqlite2 import dbapi2
|
from pysqlite2 import dbapi2
|
||||||
sqlite = dbapi2 # .. when this clause does it too
|
sqlite = dbapi2 # .. when this clause does it too
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print >>stderr, "sqlite unavailable, not using backupdb"
|
print >>stderr, """\
|
||||||
|
The backup command uses a SQLite database to avoid duplicate uploads, but
|
||||||
|
I was unable to import a python sqlite library. You have two options:
|
||||||
|
|
||||||
|
1: Install a python sqlite library. python2.5 and beyond have one built-in.
|
||||||
|
If you are using python2.4, you can install the 'pysqlite' package,
|
||||||
|
perhaps with 'apt-get install python-pysqlite2', or 'easy_install
|
||||||
|
pysqlite', or by installing the 'pysqlite' package from
|
||||||
|
http://pypi.python.org . Make sure you get the version with support for
|
||||||
|
SQLite 3.
|
||||||
|
|
||||||
|
2: run me with the --no-backupdb option to disable use of the database. This
|
||||||
|
will be somewhat slower, since I will be unable to avoid re-uploading
|
||||||
|
files that were uploaded in the past, but the basic functionality will be
|
||||||
|
unimpaired.
|
||||||
|
"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
must_create = not os.path.exists(dbfile)
|
must_create = not os.path.exists(dbfile)
|
||||||
|
@ -193,7 +193,7 @@ class LnOptions(VDriveOptions):
|
|||||||
class BackupOptions(VDriveOptions):
|
class BackupOptions(VDriveOptions):
|
||||||
optFlags = [
|
optFlags = [
|
||||||
("verbose", "v", "Be noisy about what is happening."),
|
("verbose", "v", "Be noisy about what is happening."),
|
||||||
("no-backupdb", None, "Do not use the backup-database (always upload all files)."),
|
("no-backupdb", None, "Do not use the SQLite-based backup-database (always upload all files)."),
|
||||||
("ignore-timestamps", None, "Do not use backupdb timestamps to decide if a local file is unchanged."),
|
("ignore-timestamps", None, "Do not use backupdb timestamps to decide if a local file is unchanged."),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -145,6 +145,11 @@ class BackerUpper:
|
|||||||
"private", "backupdb.sqlite")
|
"private", "backupdb.sqlite")
|
||||||
bdbfile = os.path.abspath(bdbfile)
|
bdbfile = os.path.abspath(bdbfile)
|
||||||
self.backupdb = backupdb.get_backupdb(bdbfile, stderr)
|
self.backupdb = backupdb.get_backupdb(bdbfile, stderr)
|
||||||
|
if not self.backupdb:
|
||||||
|
# get_backupdb() has already delivered a lengthy speech about
|
||||||
|
# where to find pysqlite and how to add --no-backupdb
|
||||||
|
print >>stderr, "ERROR: Unable to import sqlite."
|
||||||
|
return 1
|
||||||
|
|
||||||
rootcap, path = get_alias(options.aliases, options.to_dir, DEFAULT_ALIAS)
|
rootcap, path = get_alias(options.aliases, options.to_dir, DEFAULT_ALIAS)
|
||||||
to_url = nodeurl + "uri/%s/" % urllib.quote(rootcap)
|
to_url = nodeurl + "uri/%s/" % urllib.quote(rootcap)
|
||||||
|
@ -11,7 +11,7 @@ class BackupDB(unittest.TestCase):
|
|||||||
stderr = StringIO()
|
stderr = StringIO()
|
||||||
bdb = backupdb.get_backupdb(dbfile, stderr=stderr)
|
bdb = backupdb.get_backupdb(dbfile, stderr=stderr)
|
||||||
if not bdb:
|
if not bdb:
|
||||||
if "sqlite unavailable" in stderr.getvalue():
|
if "I was unable to import a python sqlite library" in stderr.getvalue():
|
||||||
raise unittest.SkipTest("sqlite unavailable, skipping test")
|
raise unittest.SkipTest("sqlite unavailable, skipping test")
|
||||||
return bdb
|
return bdb
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ class BackupDB(unittest.TestCase):
|
|||||||
stderr_f)
|
stderr_f)
|
||||||
self.failUnlessEqual(bdb, None)
|
self.failUnlessEqual(bdb, None)
|
||||||
stderr = stderr_f.getvalue()
|
stderr = stderr_f.getvalue()
|
||||||
if "sqlite unavailable" in stderr:
|
if "I was unable to import a python sqlite library" in stderr:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self.failUnless("backupdb file is unusable" in stderr)
|
self.failUnless("backupdb file is unusable" in stderr)
|
||||||
@ -47,7 +47,7 @@ class BackupDB(unittest.TestCase):
|
|||||||
bdb = backupdb.get_backupdb(where, stderr_f)
|
bdb = backupdb.get_backupdb(where, stderr_f)
|
||||||
self.failUnlessEqual(bdb, None)
|
self.failUnlessEqual(bdb, None)
|
||||||
stderr = stderr_f.getvalue()
|
stderr = stderr_f.getvalue()
|
||||||
if "sqlite unavailable" in stderr:
|
if "I was unable to import a python sqlite library" in stderr:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self.failUnless(("Unable to create/open backupdb file %s" % where)
|
self.failUnless(("Unable to create/open backupdb file %s" % where)
|
||||||
|
@ -636,13 +636,6 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
mo = re.search(r"(\d)+ files checked, (\d+) directories checked, (\d+) directories read", out)
|
mo = re.search(r"(\d)+ files checked, (\d+) directories checked, (\d+) directories read", out)
|
||||||
return [int(s) for s in mo.groups()]
|
return [int(s) for s in mo.groups()]
|
||||||
|
|
||||||
def nosqlite_is_ok(self, err, have_bdb):
|
|
||||||
if have_bdb:
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
else:
|
|
||||||
self.failUnlessEqual(err.strip(),
|
|
||||||
"sqlite unavailable, not using backupdb")
|
|
||||||
|
|
||||||
def test_backup(self):
|
def test_backup(self):
|
||||||
self.basedir = os.path.dirname(self.mktemp())
|
self.basedir = os.path.dirname(self.mktemp())
|
||||||
|
|
||||||
@ -659,11 +652,28 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
self.writeto("parent/subdir/bar.txt", "bar\n" * 1000)
|
self.writeto("parent/subdir/bar.txt", "bar\n" * 1000)
|
||||||
self.writeto("parent/blah.txt", "blah")
|
self.writeto("parent/blah.txt", "blah")
|
||||||
|
|
||||||
|
def do_backup(use_backupdb=True, verbose=False):
|
||||||
|
cmd = ["backup"]
|
||||||
|
if not have_bdb or not use_backupdb:
|
||||||
|
cmd.append("--no-backupdb")
|
||||||
|
if verbose:
|
||||||
|
cmd.append("--verbose")
|
||||||
|
cmd.append(source)
|
||||||
|
cmd.append("tahoe:backups")
|
||||||
|
return self.do_cli(*cmd)
|
||||||
|
|
||||||
d = self.set_up_nodes()
|
d = self.set_up_nodes()
|
||||||
d.addCallback(lambda res: self.do_cli("create-alias", "tahoe"))
|
d.addCallback(lambda res: self.do_cli("create-alias", "tahoe"))
|
||||||
d.addCallback(lambda res: self.do_cli("backup", source, "tahoe:backups"))
|
|
||||||
|
if not have_bdb:
|
||||||
|
d.addCallback(lambda res: self.do_cli("backup", source, "tahoe:backups"))
|
||||||
|
def _should_complain((rc, out, err)):
|
||||||
|
self.failUnless("I was unable to import a python sqlite library" in err, err)
|
||||||
|
d.addCallback(_should_complain)
|
||||||
|
|
||||||
|
d.addCallback(lambda res: do_backup())
|
||||||
def _check0((rc, out, err)):
|
def _check0((rc, out, err)):
|
||||||
self.nosqlite_is_ok(err, have_bdb)
|
self.failUnlessEqual(err, "")
|
||||||
self.failUnlessEqual(rc, 0)
|
self.failUnlessEqual(rc, 0)
|
||||||
fu, fr, dc, dr = self.count_output(out)
|
fu, fr, dc, dr = self.count_output(out)
|
||||||
# foo.txt, bar.txt, blah.txt
|
# foo.txt, bar.txt, blah.txt
|
||||||
@ -707,11 +717,11 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
d.addCallback(_check4)
|
d.addCallback(_check4)
|
||||||
|
|
||||||
|
|
||||||
d.addCallback(lambda res: self.do_cli("backup", source, "tahoe:backups"))
|
d.addCallback(lambda res: do_backup())
|
||||||
def _check4a((rc, out, err)):
|
def _check4a((rc, out, err)):
|
||||||
# second backup should reuse everything, if the backupdb is
|
# second backup should reuse everything, if the backupdb is
|
||||||
# available
|
# available
|
||||||
self.nosqlite_is_ok(err, have_bdb)
|
self.failUnlessEqual(err, "")
|
||||||
self.failUnlessEqual(rc, 0)
|
self.failUnlessEqual(rc, 0)
|
||||||
if have_bdb:
|
if have_bdb:
|
||||||
fu, fr, dc, dr = self.count_output(out)
|
fu, fr, dc, dr = self.count_output(out)
|
||||||
@ -736,12 +746,11 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
|
|
||||||
d.addCallback(_reset_last_checked)
|
d.addCallback(_reset_last_checked)
|
||||||
|
|
||||||
d.addCallback(lambda res:
|
d.addCallback(lambda res: do_backup(verbose=True))
|
||||||
self.do_cli("backup", "--verbose", source, "tahoe:backups"))
|
|
||||||
def _check4b((rc, out, err)):
|
def _check4b((rc, out, err)):
|
||||||
# we should check all files, and re-use all of them. None of
|
# we should check all files, and re-use all of them. None of
|
||||||
# the directories should have been changed.
|
# the directories should have been changed.
|
||||||
self.nosqlite_is_ok(err, have_bdb)
|
self.failUnlessEqual(err, "")
|
||||||
self.failUnlessEqual(rc, 0)
|
self.failUnlessEqual(rc, 0)
|
||||||
fu, fr, dc, dr = self.count_output(out)
|
fu, fr, dc, dr = self.count_output(out)
|
||||||
fchecked, dchecked, dread = self.count_output2(out)
|
fchecked, dchecked, dread = self.count_output2(out)
|
||||||
@ -782,12 +791,12 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
# turn a directory into a file
|
# turn a directory into a file
|
||||||
os.rmdir(os.path.join(source, "empty"))
|
os.rmdir(os.path.join(source, "empty"))
|
||||||
self.writeto("empty", "imagine nothing being here")
|
self.writeto("empty", "imagine nothing being here")
|
||||||
return self.do_cli("backup", source, "tahoe:backups")
|
return do_backup()
|
||||||
d.addCallback(_modify)
|
d.addCallback(_modify)
|
||||||
def _check5a((rc, out, err)):
|
def _check5a((rc, out, err)):
|
||||||
# second backup should reuse bar.txt (if backupdb is available),
|
# second backup should reuse bar.txt (if backupdb is available),
|
||||||
# and upload the rest. None of the directories can be reused.
|
# and upload the rest. None of the directories can be reused.
|
||||||
self.nosqlite_is_ok(err, have_bdb)
|
self.failUnlessEqual(err, "")
|
||||||
self.failUnlessEqual(rc, 0)
|
self.failUnlessEqual(rc, 0)
|
||||||
if have_bdb:
|
if have_bdb:
|
||||||
fu, fr, dc, dr = self.count_output(out)
|
fu, fr, dc, dr = self.count_output(out)
|
||||||
@ -825,8 +834,7 @@ class Backup(SystemTestMixin, CLITestMixin, unittest.TestCase):
|
|||||||
self.failUnlessEqual(out, "foo")
|
self.failUnlessEqual(out, "foo")
|
||||||
d.addCallback(_check8)
|
d.addCallback(_check8)
|
||||||
|
|
||||||
d.addCallback(lambda res:
|
d.addCallback(lambda res: do_backup(use_backupdb=False))
|
||||||
self.do_cli("backup", "--no-backupdb", source, "tahoe:backups"))
|
|
||||||
def _check9((rc, out, err)):
|
def _check9((rc, out, err)):
|
||||||
# --no-backupdb means re-upload everything. We still get to
|
# --no-backupdb means re-upload everything. We still get to
|
||||||
# re-use the directories, since nothing changed.
|
# re-use the directories, since nothing changed.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user