Commit 886b9e8d authored by Robert Bradshaw's avatar Robert Bradshaw

Fix cycache when there are multiple outputs.

This fixes #1399.
parent c808bec0
...@@ -14,6 +14,7 @@ from io import open as io_open ...@@ -14,6 +14,7 @@ from io import open as io_open
from os.path import relpath as _relpath from os.path import relpath as _relpath
from distutils.extension import Extension from distutils.extension import Extension
from distutils.util import strtobool from distutils.util import strtobool
import zipfile
try: try:
import gzip import gzip
...@@ -23,6 +24,12 @@ except ImportError: ...@@ -23,6 +24,12 @@ except ImportError:
gzip_open = open gzip_open = open
gzip_ext = '' gzip_ext = ''
try:
import zlib
zipfile_compression_mode = zipfile.ZIP_DEFLATED
except ImportError:
zipfile_compression_mode = zipfile.ZIP_STORED
try: try:
import pythran import pythran
import pythran.config import pythran.config
...@@ -32,7 +39,7 @@ except: ...@@ -32,7 +39,7 @@ except:
from .. import Utils from .. import Utils
from ..Utils import (cached_function, cached_method, path_exists, from ..Utils import (cached_function, cached_method, path_exists,
safe_makedirs, copy_file_to_dir_if_newer, is_package_dir) safe_makedirs, copy_file_to_dir_if_newer, is_package_dir, replace_suffix)
from ..Compiler.Main import Context, CompilationOptions, default_options from ..Compiler.Main import Context, CompilationOptions, default_options
join_path = cached_function(os.path.join) join_path = cached_function(os.path.join)
...@@ -1101,21 +1108,24 @@ def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, ...@@ -1101,21 +1108,24 @@ def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None,
safe_makedirs(options.cache) safe_makedirs(options.cache)
# Cython-generated c files are highly compressible. # Cython-generated c files are highly compressible.
# (E.g. a compression ratio of about 10 for Sage). # (E.g. a compression ratio of about 10 for Sage).
fingerprint_file = join_path( fingerprint_file_base = join_path(
options.cache, "%s-%s%s" % (os.path.basename(c_file), fingerprint, gzip_ext)) options.cache, "%s-%s" % (os.path.basename(c_file), fingerprint))
if os.path.exists(fingerprint_file): gz_fingerprint_file = fingerprint_file_base + gzip_ext
zip_fingerprint_file = fingerprint_file_base + '.zip'
if os.path.exists(gz_fingerprint_file) or os.path.exists(zip_fingerprint_file):
if not quiet: if not quiet:
print("%sFound compiled %s in cache" % (progress, pyx_file)) print("%sFound compiled %s in cache" % (progress, pyx_file))
os.utime(fingerprint_file, None) if os.path.exists(gz_fingerprint_file):
g = gzip_open(fingerprint_file, 'rb') os.utime(gz_fingerprint_file, None)
try: with gzip_open(gz_fingerprint_file, 'rb') as g:
f = open(c_file, 'wb') with open(c_file, 'wb') as f:
try: shutil.copyfileobj(g, f)
shutil.copyfileobj(g, f) else:
finally: os.utime(zip_fingerprint_file, None)
f.close() dirname = os.path.dirname(c_file)
finally: with zipfile.ZipFile(zip_fingerprint_file) as z:
g.close() for artifact in z.namelist():
z.extract(artifact, os.path.join(dirname, artifact))
return return
if not quiet: if not quiet:
print("%sCythonizing %s" % (progress, pyx_file)) print("%sCythonizing %s" % (progress, pyx_file))
...@@ -1147,16 +1157,20 @@ def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, ...@@ -1147,16 +1157,20 @@ def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None,
elif os.path.exists(c_file): elif os.path.exists(c_file):
os.remove(c_file) os.remove(c_file)
elif fingerprint: elif fingerprint:
f = open(c_file, 'rb') artifacts = filter(None, [
try: getattr(result, attr, None)
g = gzip_open(fingerprint_file + '.tmp', 'wb') for attr in ('c_file', 'h_file', 'api_file', 'i_file')])
try: if len(artifacts) == 1:
shutil.copyfileobj(f, g) fingerprint_file = gz_fingerprint_file
finally: with open(c_file, 'rb') as f:
g.close() with gzip_open(fingerprint_file + '.tmp', 'wb') as g:
os.rename(fingerprint_file + '.tmp', fingerprint_file) shutil.copyfileobj(f, g)
finally: else:
f.close() fingerprint_file = zip_fingerprint_file
with zipfile.ZipFile(fingerprint_file + '.tmp', 'w', zipfile_compression_mode) as zip:
for artifact in artifacts:
zip.write(artifact, os.path.basename(artifact))
os.rename(fingerprint_file + '.tmp', fingerprint_file)
def cythonize_one_helper(m): def cythonize_one_helper(m):
......
...@@ -55,7 +55,7 @@ class TestInline(CythonTest): ...@@ -55,7 +55,7 @@ class TestInline(CythonTest):
def test_cycache_uses_cache(self): def test_cycache_uses_cache(self):
a_pyx = os.path.join(self.src_dir, 'a.pyx') a_pyx = os.path.join(self.src_dir, 'a.pyx')
a_c = a_pyx[:-4] + '.c' a_c = a_pyx[:-4] + '.c'
open(a_pyx, 'w').write("pass") open(a_pyx, 'w').write('pass')
self.fresh_cythonize(a_pyx, cache=self.cache_dir) self.fresh_cythonize(a_pyx, cache=self.cache_dir)
a_cache = os.path.join(self.cache_dir, os.listdir(self.cache_dir)[0]) a_cache = os.path.join(self.cache_dir, os.listdir(self.cache_dir)[0])
gzip.GzipFile(a_cache, 'wb').write('fake stuff') gzip.GzipFile(a_cache, 'wb').write('fake stuff')
...@@ -63,3 +63,18 @@ class TestInline(CythonTest): ...@@ -63,3 +63,18 @@ class TestInline(CythonTest):
self.fresh_cythonize(a_pyx, cache=self.cache_dir) self.fresh_cythonize(a_pyx, cache=self.cache_dir)
a_contents = open(a_c).read() a_contents = open(a_c).read()
self.assertEqual(a_contents, 'fake stuff') self.assertEqual(a_contents, 'fake stuff')
def test_multi_file_output(self):
a_pyx = os.path.join(self.src_dir, 'a.pyx')
a_c = a_pyx[:-4] + '.c'
a_h = a_pyx[:-4] + '.h'
a_api_h = a_pyx[:-4] + '_api.h'
open(a_pyx, 'w').write('cdef public api int foo(int x): return x\n')
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
expected = [a_c, a_h, a_api_h]
for output in expected:
self.assertTrue(os.path.exists(output), output)
os.unlink(output)
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
for output in expected:
self.assertTrue(os.path.exists(output), output)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment