gen_docu: fix missing attributes, show generation time at the end
[libfirm] / scripts / jinja2 / bccache.py
index 2c57616..0b0ccad 100644 (file)
     Situations where this is useful are often forking web applications that
     are initialized on the first request.
 
-    :copyright: Copyright 2008 by Armin Ronacher.
+    :copyright: (c) 2010 by the Jinja Team.
     :license: BSD.
 """
 from os import path, listdir
+import sys
 import marshal
 import tempfile
 import cPickle as pickle
 import fnmatch
-from cStringIO import StringIO
 try:
     from hashlib import sha1
 except ImportError:
@@ -27,8 +27,36 @@ except ImportError:
 from jinja2.utils import open_if_exists
 
 
-bc_version = 1
-bc_magic = 'j2' + pickle.dumps(bc_version, 2)
+# marshal works better on 3.x, one hack less required
+if sys.version_info > (3, 0):
+    from io import BytesIO
+    marshal_dump = marshal.dump
+    marshal_load = marshal.load
+else:
+    from cStringIO import StringIO as BytesIO
+
+    def marshal_dump(code, f):
+        if isinstance(f, file):
+            marshal.dump(code, f)
+        else:
+            f.write(marshal.dumps(code))
+
+    def marshal_load(f):
+        if isinstance(f, file):
+            return marshal.load(f)
+        return marshal.loads(f.read())
+
+
+bc_version = 2
+
+# magic version used to only change with new jinja versions.  With 2.6
+# we change this to also take Python version changes into account.  The
+# reason for this is that Python tends to segfault if fed earlier bytecode
+# versions because someone thought it would be a good idea to reuse opcodes
+# or make Python incompatible with earlier versions.
+bc_magic = 'j2'.encode('ascii') + \
+    pickle.dumps(bc_version, 2) + \
+    pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
 
 
 class Bucket(object):
@@ -62,12 +90,7 @@ class Bucket(object):
         if self.checksum != checksum:
             self.reset()
             return
-        # now load the code.  Because marshal is not able to load
-        # from arbitrary streams we have to work around that
-        if isinstance(f, file):
-            self.code = marshal.load(f)
-        else:
-            self.code = marshal.loads(f.read())
+        self.code = marshal_load(f)
 
     def write_bytecode(self, f):
         """Dump the bytecode into the file or file like object passed."""
@@ -75,18 +98,15 @@ class Bucket(object):
             raise TypeError('can\'t write empty bucket')
         f.write(bc_magic)
         pickle.dump(self.checksum, f, 2)
-        if isinstance(f, file):
-            marshal.dump(self.code, f)
-        else:
-            f.write(marshal.dumps(self.code))
+        marshal_dump(self.code, f)
 
     def bytecode_from_string(self, string):
         """Load bytecode from a string."""
-        self.load_bytecode(StringIO(string))
+        self.load_bytecode(BytesIO(string))
 
     def bytecode_to_string(self):
         """Return the bytecode as string."""
-        out = StringIO()
+        out = BytesIO()
         self.write_bytecode(out)
         return out.getvalue()
 
@@ -108,12 +128,12 @@ class BytecodeCache(object):
             def load_bytecode(self, bucket):
                 filename = path.join(self.directory, bucket.key)
                 if path.exists(filename):
-                    with file(filename, 'rb') as f:
+                    with open(filename, 'rb') as f:
                         bucket.load_bytecode(f)
 
             def dump_bytecode(self, bucket):
                 filename = path.join(self.directory, bucket.key)
-                with file(filename, 'wb') as f:
+                with open(filename, 'wb') as f:
                     bucket.write_bytecode(f)
 
     A more advanced version of a filesystem based bytecode cache is part of
@@ -144,9 +164,10 @@ class BytecodeCache(object):
         """Returns the unique hash key for this template name."""
         hash = sha1(name.encode('utf-8'))
         if filename is not None:
+            filename = '|' + filename
             if isinstance(filename, unicode):
                 filename = filename.encode('utf-8')
-            hash.update('|' + filename)
+            hash.update(filename)
         return hash.hexdigest()
 
     def get_source_checksum(self, source):
@@ -202,7 +223,7 @@ class FileSystemBytecodeCache(BytecodeCache):
                 f.close()
 
     def dump_bytecode(self, bucket):
-        f = file(self._get_cache_filename(bucket), 'wb')
+        f = open(self._get_cache_filename(bucket), 'wb')
         try:
             bucket.write_bytecode(f)
         finally: