update: log errors on bad graphics, and then ignore the file

Python PIL is not so tolerant, so bad EXIF causes crashes:

  File "/var/lib/jenkins/userContent/reproducible/reproducible_fdroid_build_apps/fdroidserver/update.py", line 2088, in main
    insert_localized_app_metadata(apps)
  File "/var/lib/jenkins/userContent/reproducible/reproducible_fdroid_build_apps/fdroidserver/update.py", line 978, in insert_localized_app_metadata
    _strip_and_copy_image(os.path.join(root, f), destdir)
  File "/var/lib/jenkins/userContent/reproducible/reproducible_fdroid_build_apps/fdroidserver/update.py", line 754, in _strip_and_copy_image
    in_image = Image.open(fp)
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2687, in open
    % (filename if filename else fp))
OSError: cannot identify image file <_io.BufferedReader name='build/org.sw24softwares.starkeverben/fastlane/metadata/android/en-US/images/featureGraphic.png'>
This commit is contained in:
Hans-Christoph Steiner 2019-09-26 19:38:24 +02:00
parent c738ad54ec
commit c7048f2c39
3 changed files with 34 additions and 10 deletions

View File

@ -733,6 +733,8 @@ def _strip_and_copy_image(in_file, outpath):
outpath can be path to either a file or dir. The dir that outpath outpath can be path to either a file or dir. The dir that outpath
refers to must exist before calling this. refers to must exist before calling this.
Potential source of Python code to strip JPEGs without dependencies:
http://www.fetidcascade.com/public/minimal_exif_writer.py
""" """
logging.debug('copying ' + in_file + ' ' + outpath) logging.debug('copying ' + in_file + ' ' + outpath)
@ -750,17 +752,25 @@ def _strip_and_copy_image(in_file, outpath):
extension = common.get_extension(in_file)[1] extension = common.get_extension(in_file)[1]
if extension == 'png': if extension == 'png':
with open(in_file, 'rb') as fp: try:
in_image = Image.open(fp) with open(in_file, 'rb') as fp:
in_image.save(out_file, "PNG", optimize=True, in_image = Image.open(fp)
pnginfo=BLANK_PNG_INFO, icc_profile=None) in_image.save(out_file, "PNG", optimize=True,
pnginfo=BLANK_PNG_INFO, icc_profile=None)
except Exception as e:
logging.error(_("Failed copying {path}: {error}".format(path=in_file, error=e)))
return
elif extension == 'jpg' or extension == 'jpeg': elif extension == 'jpg' or extension == 'jpeg':
with open(in_file, 'rb') as fp: try:
in_image = Image.open(fp) with open(in_file, 'rb') as fp:
data = list(in_image.getdata()) in_image = Image.open(fp)
out_image = Image.new(in_image.mode, in_image.size) data = list(in_image.getdata())
out_image.putdata(data) out_image = Image.new(in_image.mode, in_image.size)
out_image.save(out_file, "JPEG", optimize=True) out_image.putdata(data)
out_image.save(out_file, "JPEG", optimize=True)
except Exception as e:
logging.error(_("Failed copying {path}: {error}".format(path=in_file, error=e)))
return
else: else:
raise FDroidException(_('Unsupported file type "{extension}" for repo graphic') raise FDroidException(_('Unsupported file type "{extension}" for repo graphic')
.format(extension=extension)) .format(extension=extension))

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

View File

@ -851,6 +851,20 @@ class UpdateTest(unittest.TestCase):
icons_src = fdroidserver.update._get_apk_icons_src('urzip-release.apk', None) icons_src = fdroidserver.update._get_apk_icons_src('urzip-release.apk', None)
assert icons_src == {} assert icons_src == {}
def test_strip_and_copy_image(self):
tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
dir=self.tmpdir)
in_file = os.path.join(self.basedir, 'metadata', 'info.guardianproject.urzip', 'en-US', 'images', 'icon.png')
out_file = os.path.join(tmptestsdir, 'icon.png')
fdroidserver.update._strip_and_copy_image(in_file, out_file)
self.assertTrue(os.path.exists(out_file))
in_file = os.path.join(self.basedir, 'corrupt-featureGraphic.png')
out_file = os.path.join(tmptestsdir, 'corrupt-featureGraphic.png')
fdroidserver.update._strip_and_copy_image(in_file, out_file)
self.assertFalse(os.path.exists(out_file))
def test_create_metadata_from_template_empty_keys(self): def test_create_metadata_from_template_empty_keys(self):
apk = {'packageName': 'rocks.janicerand'} apk = {'packageName': 'rocks.janicerand'}
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):