diff --git a/pelican/generators.py b/pelican/generators.py index d9923e35..2107e338 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -5,7 +5,6 @@ import calendar import fnmatch import logging import os -import shutil from codecs import open from collections import defaultdict from functools import partial @@ -21,8 +20,9 @@ from pelican import signals from pelican.cache import FileStampDataCacher from pelican.contents import Article, Draft, Page, Static, is_valid_content from pelican.readers import Readers -from pelican.utils import (DateFormatter, copy, mkdir_p, posixize_path, - process_translations, python_2_unicode_compatible) +from pelican.utils import (DateFormatter, copy, copy_file_metadata, mkdir_p, + posixize_path, process_translations, + python_2_unicode_compatible) logger = logging.getLogger(__name__) @@ -727,8 +727,8 @@ class StaticGenerator(Generator): source_path = os.path.join(self.path, sc.source_path) save_as = os.path.join(self.output_path, sc.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) + copy_file_metadata(source_path, save_as) class SourceFileGenerator(Generator): diff --git a/pelican/utils.py b/pelican/utils.py index 06290d16..f1558fda 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -337,7 +337,7 @@ def copy(source, destination, ignores=None): logger.info('Creating directory %s', dst_dir) os.makedirs(dst_dir) logger.info('Copying %s to %s', source_, destination_) - shutil.copy2(source_, destination_) + copy_file_metadata(source_, destination_) elif os.path.isdir(source_): if not os.path.exists(destination_): @@ -367,13 +367,25 @@ def copy(source, destination, ignores=None): dst_path = os.path.join(dst_dir, o) if os.path.isfile(src_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: logger.warning('Skipped copy %s (not a file or ' 'directory) to %s', 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): """Remove all files from output directory except those in retention list"""