Răsfoiți Sursa

Improved error handling.

Jonas Borgström 12 ani în urmă
părinte
comite
da0e3c4ec8
5 a modificat fișierele cu 61 adăugiri și 28 ștergeri
  1. 2 2
      darc/archive.py
  2. 20 3
      darc/archiver.py
  3. 16 17
      darc/remote.py
  4. 8 5
      darc/store.py
  5. 15 1
      darc/test.py

+ 2 - 2
darc/archive.py

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

+ 20 - 3
darc/archiver.py

@@ -411,9 +411,26 @@ class Archiver(object):
 
 
 def main():
 def main():
     archiver = Archiver()
     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)
     sys.exit(exit_code)
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':

+ 16 - 17
darc/remote.py

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

+ 8 - 5
darc/store.py

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

+ 15 - 1
darc/test.py

@@ -3,6 +3,7 @@ import doctest
 import filecmp
 import filecmp
 import os
 import os
 from StringIO import StringIO
 from StringIO import StringIO
+import stat
 import sys
 import sys
 import shutil
 import shutil
 import tempfile
 import tempfile
@@ -84,7 +85,7 @@ class Test(unittest.TestCase):
             path2 = os.path.join(dir2, filename)
             path2 = os.path.join(dir2, filename)
             s1 = os.lstat(path1)
             s1 = os.lstat(path1)
             s2 = os.lstat(path2)
             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
             # We can't restore symlink atime/mtime right now
             if not os.path.islink(path1):
             if not os.path.islink(path1):
                 attrs.append('st_mtime')
                 attrs.append('st_mtime')
@@ -95,15 +96,28 @@ class Test(unittest.TestCase):
             self.assertEqual(d1, d2)
             self.assertEqual(d1, d2)
 
 
     def test_basic_functionality(self):
     def test_basic_functionality(self):
+        # File
         self.create_regual_file('file1', size=1024 * 80)
         self.create_regual_file('file1', size=1024 * 80)
+        # Directory
         self.create_regual_file('dir2/file2', size=1024 * 80)
         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/file1', 0600)
         os.chmod('input/dir2', 0700)
         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 = xattr(os.path.join(self.input_path, 'file1'))
         x.set('user.foo', 'bar')
         x.set('user.foo', 'bar')
+        # Hard link
         os.link(os.path.join(self.input_path, 'file1'),
         os.link(os.path.join(self.input_path, 'file1'),
                 os.path.join(self.input_path, 'hardlink'))
                 os.path.join(self.input_path, 'hardlink'))
+        # Symlink
         os.symlink('somewhere', os.path.join(self.input_path, 'link1'))
         os.symlink('somewhere', os.path.join(self.input_path, 'link1'))
+        # FIFO node
         os.mkfifo(os.path.join(self.input_path, 'fifo1'))
         os.mkfifo(os.path.join(self.input_path, 'fifo1'))
         self.darc('init', self.store_location)
         self.darc('init', self.store_location)
         self.darc('create', self.store_location + '::test', 'input')
         self.darc('create', self.store_location + '::test', 'input')