Improved error handling.

This commit is contained in:
Jonas Borgström 2012-12-09 23:06:33 +01:00
parent 0cc09fb761
commit da0e3c4ec8
5 changed files with 61 additions and 28 deletions

View File

@ -100,7 +100,7 @@ class Archive(object):
self.numeric_owner = numeric_owner
if create:
if name in manifest.archives:
raise self.AlreadyExists
raise self.AlreadyExists(name)
self.last_checkpoint = time.time()
i = 0
while True:
@ -112,7 +112,7 @@ class Archive(object):
try:
info = self.manifest.archives[name]
except KeyError:
raise self.DoesNotExist
raise self.DoesNotExist(name)
self.load(info['id'])
def load(self, id):

View File

@ -411,9 +411,26 @@ class Archiver(object):
def main():
archiver = Archiver()
exit_code = archiver.run()
if exit_code:
archiver.print_error('Exiting with failure status due to previous errors')
try:
exit_code = archiver.run()
except Store.DoesNotExist:
archiver.print_error('Error: Store not found')
exit_code = 1
except Store.AlreadyExists:
archiver.print_error('Error: Store already exists')
exit_code = 1
except Archive.AlreadyExists, e:
archiver.print_error('Error: Archive "%s" already exists', e)
exit_code = 1
except Archive.DoesNotExist, e:
archiver.print_error('Error: Archive "%s" does not exist', e)
exit_code = 1
except KeyboardInterrupt:
archiver.print_error('Error: Keyboard interrupt')
exit_code = 1
else:
if exit_code:
archiver.print_error('Exiting with failure status due to previous errors')
sys.exit(exit_code)
if __name__ == '__main__':

View File

@ -61,12 +61,6 @@ class StoreServer(object):
class RemoteStore(object):
class DoesNotExist(Exception):
pass
class AlreadyExists(Exception):
pass
class RPCError(Exception):
def __init__(self, name):
@ -92,7 +86,13 @@ class RemoteStore(object):
version = self.call('negotiate', (1,))
if version != 1:
raise Exception('Server insisted on using unsupported protocol version %d' % version)
self.id = self.call('open', (location.path, create))
try:
self.id = self.call('open', (location.path, create))
except self.RPCError, e:
if e.name == 'DoesNotExist':
raise Store.DoesNotExist
elif e.name == 'AlreadyExists':
raise Store.AlreadyExists
def __del__(self):
self.close()
@ -106,7 +106,10 @@ class RemoteStore(object):
if x:
raise Exception('FD exception occured')
if r:
self.unpacker.feed(os.read(self.stdout_fd, BUFSIZE))
data = os.read(self.stdout_fd, BUFSIZE)
if not data:
raise Exception('Remote host closed connection')
self.unpacker.feed(data)
for type, msgid, error, res in self.unpacker:
if msgid == self.msgid:
assert msgid == self.msgid
@ -130,7 +133,7 @@ class RemoteStore(object):
def _read(self):
data = os.read(self.stdout_fd, BUFSIZE)
if not data:
raise Exception('EOF')
raise Exception('Remote host closed connection')
self.unpacker.feed(data)
to_yield = []
for type, msgid, error, res in self.unpacker:
@ -229,7 +232,7 @@ class RemoteStore(object):
return res
except self.RPCError, e:
if e.name == 'DoesNotExist':
raise self.DoesNotExist
raise Store.DoesNotExist
raise
def get_many(self, ids, peek=None):
@ -241,13 +244,9 @@ class RemoteStore(object):
self.pending.pop(self.cache.pop(key)[0], None)
def put(self, id, data, wait=True):
try:
resp = self.call('put', (id, data), wait=wait)
self._invalidate(id)
return resp
except self.RPCError, e:
if e.name == 'AlreadyExists':
raise self.AlreadyExists
resp = self.call('put', (id, data), wait=wait)
self._invalidate(id)
return resp
def delete(self, id, wait=True):
resp = self.call('delete', (id, ), wait=wait)

View File

@ -36,6 +36,9 @@ class Store(object):
class DoesNotExist(KeyError):
"""Requested key does not exist"""
class AlreadyExists(KeyError):
"""Requested key does not exist"""
def __init__(self, path, create=False):
if create:
self.create(path)
@ -45,7 +48,7 @@ class Store(object):
"""Create a new empty store at `path`
"""
if os.path.exists(path) and (not os.path.isdir(path) or os.listdir(path)):
raise Exception('Path "%s" already exists' % path)
raise self.AlreadyExists(path)
if not os.path.exists(path):
os.mkdir(path)
with open(os.path.join(path, 'README'), 'wb') as fd:
@ -64,7 +67,7 @@ class Store(object):
self.head = None
self.path = path
if not os.path.isdir(path):
raise Exception('%s Does not look like a darc store' % path)
raise self.DoesNotExist(path)
self.lock_fd = open(os.path.join(path, 'README'), 'r+')
fcntl.flock(self.lock_fd, fcntl.LOCK_EX)
self.config = RawConfigParser()
@ -426,11 +429,11 @@ class StoreTestCase(unittest.TestCase):
key50 = '%-32d' % 50
self.assertEqual(self.store.get(key50), 'SOMEDATA')
self.store.delete(key50)
self.assertRaises(self.store.DoesNotExist, lambda: self.store.get(key50))
self.assertRaises(Store.DoesNotExist, lambda: self.store.get(key50))
self.store.commit()
self.store.close()
store2 = self.open()
self.assertRaises(store2.DoesNotExist, lambda: store2.get(key50))
self.assertRaises(Store.DoesNotExist, lambda: store2.get(key50))
for x in range(100):
if x == 50:
continue
@ -457,7 +460,7 @@ class StoreTestCase(unittest.TestCase):
self.store.put('00000000000000000000000000000000', 'bar')
self.assertEqual(self.store.get('00000000000000000000000000000000'), 'bar')
self.store.delete('00000000000000000000000000000000')
self.assertRaises(self.store.DoesNotExist, lambda: self.store.get('00000000000000000000000000000000'))
self.assertRaises(Store.DoesNotExist, lambda: self.store.get('00000000000000000000000000000000'))
def test_consistency2(self):
"""Test cache consistency2

View File

@ -3,6 +3,7 @@ import doctest
import filecmp
import os
from StringIO import StringIO
import stat
import sys
import shutil
import tempfile
@ -84,7 +85,7 @@ class Test(unittest.TestCase):
path2 = os.path.join(dir2, filename)
s1 = os.lstat(path1)
s2 = os.lstat(path2)
attrs = ['st_mode', 'st_uid', 'st_gid']
attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev']
# We can't restore symlink atime/mtime right now
if not os.path.islink(path1):
attrs.append('st_mtime')
@ -95,15 +96,28 @@ class Test(unittest.TestCase):
self.assertEqual(d1, d2)
def test_basic_functionality(self):
# File
self.create_regual_file('file1', size=1024 * 80)
# Directory
self.create_regual_file('dir2/file2', size=1024 * 80)
# File owner
os.chown('input/file1', 100, 200)
# File mode
os.chmod('input/file1', 0600)
os.chmod('input/dir2', 0700)
# Block device
os.mknod('input/bdev', 0600 | stat.S_IFBLK, os.makedev(10, 20))
# Char device
os.mknod('input/cdev', 0600 | stat.S_IFCHR, os.makedev(30, 40))
# xattr
x = xattr(os.path.join(self.input_path, 'file1'))
x.set('user.foo', 'bar')
# Hard link
os.link(os.path.join(self.input_path, 'file1'),
os.path.join(self.input_path, 'hardlink'))
# Symlink
os.symlink('somewhere', os.path.join(self.input_path, 'link1'))
# FIFO node
os.mkfifo(os.path.join(self.input_path, 'fifo1'))
self.darc('init', self.store_location)
self.darc('create', self.store_location + '::test', 'input')