Python's shutil.copy2 fails on Android

Python's shutil.copy2 fails on Android when copying a file's meta data (perm bits, access times) onto certain filesystems. This is documented as python issue28141 https://bugs.python.org/issue28141

These commits workaround that bug by

+ creating a new function copy_file_metadata in utils.py
+ wrapping calls to copy2 in a try/except clause that logs any errors that occur but keep execution going
+ changing the calls to shutil.copy2 to calls to the new function
This commit is contained in:
Jerry Asher 2016-09-23 17:16:46 -07:00
commit f8031203d2
2 changed files with 18 additions and 6 deletions

View file

@ -5,7 +5,6 @@ import calendar
import fnmatch import fnmatch
import logging import logging
import os import os
import shutil
from codecs import open from codecs import open
from collections import defaultdict from collections import defaultdict
from functools import partial from functools import partial
@ -21,8 +20,9 @@ from pelican import signals
from pelican.cache import FileStampDataCacher from pelican.cache import FileStampDataCacher
from pelican.contents import Article, Draft, Page, Static, is_valid_content from pelican.contents import Article, Draft, Page, Static, is_valid_content
from pelican.readers import Readers from pelican.readers import Readers
from pelican.utils import (DateFormatter, copy, mkdir_p, posixize_path, from pelican.utils import (DateFormatter, copy, copy_file_metadata, mkdir_p,
process_translations, python_2_unicode_compatible) posixize_path, process_translations,
python_2_unicode_compatible)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -727,8 +727,8 @@ class StaticGenerator(Generator):
source_path = os.path.join(self.path, sc.source_path) source_path = os.path.join(self.path, sc.source_path)
save_as = os.path.join(self.output_path, sc.save_as) save_as = os.path.join(self.output_path, sc.save_as)
mkdir_p(os.path.dirname(save_as)) mkdir_p(os.path.dirname(save_as))
shutil.copy2(source_path, save_as)
logger.info('Copying %s to %s', sc.source_path, sc.save_as) logger.info('Copying %s to %s', sc.source_path, sc.save_as)
copy_file_metadata(source_path, save_as)
class SourceFileGenerator(Generator): class SourceFileGenerator(Generator):

View file

@ -337,7 +337,7 @@ def copy(source, destination, ignores=None):
logger.info('Creating directory %s', dst_dir) logger.info('Creating directory %s', dst_dir)
os.makedirs(dst_dir) os.makedirs(dst_dir)
logger.info('Copying %s to %s', source_, destination_) logger.info('Copying %s to %s', source_, destination_)
shutil.copy2(source_, destination_) copy_file_metadata(source_, destination_)
elif os.path.isdir(source_): elif os.path.isdir(source_):
if not os.path.exists(destination_): if not os.path.exists(destination_):
@ -367,13 +367,25 @@ def copy(source, destination, ignores=None):
dst_path = os.path.join(dst_dir, o) dst_path = os.path.join(dst_dir, o)
if os.path.isfile(src_path): if os.path.isfile(src_path):
logger.info('Copying %s to %s', src_path, dst_path) logger.info('Copying %s to %s', src_path, dst_path)
shutil.copy2(src_path, dst_path) copy_file_metadata(src_path, dst_path)
else: else:
logger.warning('Skipped copy %s (not a file or ' logger.warning('Skipped copy %s (not a file or '
'directory) to %s', 'directory) to %s',
src_path, dst_path) src_path, dst_path)
def copy_file_metadata(source, destination):
'''Copy a file and its metadata (perm bits, access times, ...)'''
# This function is a workaround for Android python copystat
# bug ([issue28141]) https://bugs.python.org/issue28141
try:
shutil.copy2(source, destination)
except OSError as e:
logger.warning("A problem occurred copying file %s to %s; %s",
source, destination, e)
def clean_output_dir(path, retention): def clean_output_dir(path, retention):
"""Remove all files from output directory except those in retention list""" """Remove all files from output directory except those in retention list"""