[svn] There's now an entirely new object hierarchy for handlers, because the trunk

Sun, 31 Dec 2006 19:27:23 -0500

author
brett
date
Sun, 31 Dec 2006 19:27:23 -0500
branch
trunk
changeset 16
29794d4d41aa
parent 15
28dbd52a8bb8
child 17
481a2b4be471

[svn] There's now an entirely new object hierarchy for handlers, because the
number of corner cases, switches, etc. was starting to get out of hand.
This makes it easier to tell what's going on in a given case.

scripts/x file | annotate | diff | comparison | revisions
tests/tests.yml file | annotate | diff | comparison | revisions
--- a/scripts/x	Sun Dec 31 19:25:16 2006 -0500
+++ b/scripts/x	Sun Dec 31 19:27:23 2006 -0500
@@ -47,7 +47,7 @@
 # ONE_DIRECTORY = 2
 BOMB = 3
 EMPTY = 4
-DECOMPRESSED = 5
+COMPRESSED = 5
 
 mimetypes.encodings_map.setdefault('.bz2', 'bzip2')
 mimetypes.types_map['.exe'] = 'application/x-msdos-program'
@@ -308,7 +308,7 @@
         yield self.basename()
 
     def check_contents(self):
-        return DECOMPRESSED
+        return COMPRESSED
 
     def extract(self, path):
         output = open(path, 'w')
@@ -323,25 +323,27 @@
         self.contents = contents
         self.options = options
 
+##     def extract(self):
+##         raise NotImplementedError
+##         checker = self.extractor.name_checker(self.extractor.basename())
+##         if self.options.flat:
+##             self.target = '.'
+##             return self.do_extract('.')
+##         elif self.options.overwrite or checker.is_free():
+##             self.target = self.extractor.basename()
+##             return self.overwrite()
+##         else:
+##             self.target = checker.check()
+##             return self.safe_extract()
+
     def extract(self):
-        checker = self.extractor.name_checker(self.extractor.basename())
-        if self.options.flat:
-            self.target = '.'
-            return self.do_extract('.')
-        elif self.options.overwrite or checker.is_free():
-            self.target = self.extractor.basename()
-            return self.overwrite()
-        else:
-            self.target = checker.check()
-            return self.safe_extract()
-
-    def do_extract(self, directory):
         try:
-            self.extractor.extract(directory)
+            self.extractor.extract(self.target)
         except ExtractorError, error:
             return str(error)
         
     def cleanup(self):
+        raise NotImplementedError
         if self.options.flat:
             self.cleanup_files()
         else:
@@ -366,35 +368,90 @@
             return "%s returned with exit status %s" % (command, status)
 
 
-class MatchHandler(BaseHandler):
-    def overwrite(self):
-        return self.do_extract('.')
+# The "where to extract" table, with options and archive types.
+# This dictates the contents of each can_handle method.
+#
+#         Flat           Overwrite            None
+# File    basename       basename             FilenameChecked
+# Match   .              .                    tempdir + checked
+# Bomb    .              basename             DirectoryChecked
+
+
+class FlatHandler(BaseHandler):
+    def can_handle(contents, options):
+        return ((options.flat and (contents != COMPRESSED)) or
+                (options.overwrite and (contents == MATCHING_DIRECTORY)))
+    can_handle = staticmethod(can_handle)
+
+    target = '.'
+    cleanup = BaseHandler.cleanup_files
+
 
-    def safe_extract(self):
-        tempdir = tempfile.mkdtemp()
-        result = self.do_extract(tempdir)
+class OverwriteHandler(BaseHandler):
+    def can_handle(contents, options):
+        return ((options.flat and (contents == COMPRESSED)) or
+                (options.overwrite and (contents != MATCHING_DIRECTORY)))
+    can_handle = staticmethod(can_handle)
+
+    def __init__(self, extractor, contents, options):
+        BaseHandler.__init__(self, extractor, contents, options)
+        self.target = self.extractor.basename()
+
+    cleanup = BaseHandler.cleanup_directory
+        
+
+class MatchHandler(BaseHandler):
+    def can_handle(contents, options):
+        return contents == MATCHING_DIRECTORY
+    can_handle = staticmethod(can_handle)
+
+    def extract(self):
+        basename = self.extractor.basename()
+        self.target = tempfile.mkdtemp()
+        result = BaseHandler.extract(self)
         if result is None:
-            os.rename(os.path.join(tempdir, self.extractor.basename()),
-                      self.target)
+            tempdir = self.target
+            checker = self.extractor.name_checker(basename)
+            self.target = checker.check()
+            os.rename(os.path.join(tempdir, basename), self.target)
             os.rmdir(tempdir)
         return result
-        
-        
-class BombHandler(BaseHandler):
-    def safe_extract(self):
-        return self.do_extract(self.target)
 
-    def overwrite(self):
-        self.target = self.extractor.basename()
-        return self.do_extract(self.target)
+    cleanup = BaseHandler.cleanup_directory
 
 
 class EmptyHandler(object):
+    def can_handle(contents, options):
+        return contents == EMPTY
+    can_handle = staticmethod(can_handle)
+
     def __init__(self, extractor, contents, options): pass
     def extract(self): pass
     def cleanup(self): pass
 
 
+class BombHandler(BaseHandler):
+    def can_handle(contents, options):
+        return True
+    can_handle = staticmethod(can_handle)
+
+    def __init__(self, extractor, contents, options):
+        BaseHandler.__init__(self, extractor, contents, options)
+        checker = self.extractor.name_checker(self.extractor.basename())
+        self.target = checker.check()
+
+    cleanup = BaseHandler.cleanup_directory
+
+        
+## class BombHandler(BaseHandler):
+##     def safe_extract(self):
+##         return self.do_extract(self.target)
+
+##     def overwrite(self):
+##         self.target = self.extractor.basename()
+##         return self.do_extract(self.target)
+
+
 extractor_map = {'application/x-tar': TarExtractor,
                  'application/zip': ZipExtractor,
                  'application/x-msdos-program': ZipExtractor,
@@ -403,9 +460,8 @@
                  'application/x-rpm': RPMExtractor,
                  'application/x-cpio': CpioExtractor}
 
-handler_map = {EMPTY: EmptyHandler,
-               MATCHING_DIRECTORY: MatchHandler,
-               DECOMPRESSED: BombHandler}
+handlers = [FlatHandler, OverwriteHandler, MatchHandler, EmptyHandler,
+            BombHandler]
 
 class ExtractorApplication(object):
     def __init__(self, arguments):
@@ -459,15 +515,18 @@
         except KeyError:
             if encoding:
                 extractor = CompressionExtractor
+                contents = COMPRESSED
             else:
                 return "not a known archive type"
         try:
             self.current_extractor = extractor(self.current_filename, mimetype,
                                                encoding)
             content = self.current_extractor.check_contents()
-            handler = handler_map.get(content, BombHandler)
-            self.current_handler = handler(self.current_extractor, content,
-                                           self.options)
+            for handler in handlers:
+                if handler.can_handle(content, self.options):
+                    self.current_handler = handler(self.current_extractor,
+                                                   content, self.options)
+                    break
         except ExtractorError, error:
             return str(error)
 
--- a/tests/tests.yml	Sun Dec 31 19:25:16 2006 -0500
+++ b/tests/tests.yml	Sun Dec 31 19:27:23 2006 -0500
@@ -61,6 +61,13 @@
   baseline: |
     zcat $1 >test-text
 
+- name: decompression with -fr
+  directory: inside-dir
+  filename: ../test-text.gz
+  options: -fr
+  baseline: |
+    zcat $1 >test-text
+
 - name: overwrite protection
   filename: test-1.23.tar.bz2
   baseline: |

mercurial