From 9d583961e700667b7f1e78c4f2e0c88954becf15 Mon Sep 17 00:00:00 2001 From: bmcorser Date: Wed, 21 Aug 2013 19:57:55 +0100 Subject: [PATCH 1/7] Fix for THEME_STATIC_PATHS by copying sensitively If more than one path is defined in THEME_STATIC_PATHS, the theme's static directory in output is deleted and replaced by the following path's files. Using `shutil.rmtree` to remove the entire destination tree if overwrite is `True` assumes that we didn't want anything at all that was there. We should recurse through the directory and their subdirs instead, leaving things put there by the previous path where they were. I lazily copied almost verbatim the solution for recursively copying a diectory from http://stackoverflow.com/a/1994840. The reason for this is patch is that without it, my plugin is broken! It also makes my code a lot less crazy: https://github.com/bmcorser/pelicanfly/commit/a83f066 --- pelican/utils.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/pelican/utils.py b/pelican/utils.py index 054c1f40..e028c84c 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -275,16 +275,24 @@ def copy(path, source, destination, destination_path=None, overwrite=False): destination_ = os.path.abspath( os.path.expanduser(os.path.join(destination, destination_path))) + def recurse(source, destination): + for entry in os.listdir(source): + entry_path = os.path.join(source, entry) + if os.path.isdir(entry_path): + entry_dest = os.path.join(destination, entry) + if os.path.exists(entry_dest): + if not os.path.isdir(entry_dest): + raise IOError('Failed to copy {0} a directory.' + .format(entry_dest)) + recurse(entry_path, entry_dest) + else: + shutil.copytree(entry_path, entry_dest) + else: + shutil.copy(entry_path, destination) + + if os.path.isdir(source_): - try: - shutil.copytree(source_, destination_) - logger.info('copying %s to %s' % (source_, destination_)) - except OSError: - if overwrite: - shutil.rmtree(destination_) - shutil.copytree(source_, destination_) - logger.info('replacement of %s with %s' % (source_, - destination_)) + recurse(source_, destination_) elif os.path.isfile(source_): dest_dir = os.path.dirname(destination_) From d22b0892418b60b752551ebc95c4616926bb513f Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 24 Aug 2013 13:41:22 +0100 Subject: [PATCH 2/7] Adding placeholder files for regression test --- samples/theme_standard/a_stylesheet | 0 samples/theme_standard/a_template | 0 samples/very/exciting/new/files/bap! | 0 samples/very/exciting/new/files/boom! | 0 samples/very/exciting/new/files/wow! | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 samples/theme_standard/a_stylesheet create mode 100644 samples/theme_standard/a_template create mode 100644 samples/very/exciting/new/files/bap! create mode 100644 samples/very/exciting/new/files/boom! create mode 100644 samples/very/exciting/new/files/wow! diff --git a/samples/theme_standard/a_stylesheet b/samples/theme_standard/a_stylesheet new file mode 100644 index 00000000..e69de29b diff --git a/samples/theme_standard/a_template b/samples/theme_standard/a_template new file mode 100644 index 00000000..e69de29b diff --git a/samples/very/exciting/new/files/bap! b/samples/very/exciting/new/files/bap! new file mode 100644 index 00000000..e69de29b diff --git a/samples/very/exciting/new/files/boom! b/samples/very/exciting/new/files/boom! new file mode 100644 index 00000000..e69de29b diff --git a/samples/very/exciting/new/files/wow! b/samples/very/exciting/new/files/wow! new file mode 100644 index 00000000..e69de29b From 0f4058a3170724cc1709837c1d8f89d364c08bf5 Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 24 Aug 2013 13:42:55 +0100 Subject: [PATCH 3/7] Add regressison test for recursively copying files --- pelican/tests/test_pelican.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py index d6c0d8e9..db2d0e6b 100644 --- a/pelican/tests/test_pelican.py +++ b/pelican/tests/test_pelican.py @@ -92,3 +92,22 @@ class TestPelican(LoggedTestCase): mute(True)(pelican.run)() dcmp = dircmp(self.temp_path, os.path.join(OUTPUT_PATH, 'custom')) self.assertFilesEqual(recursiveDiff(dcmp)) + + def test_theme_static_paths_copy(self): + # the same thing with a specified set of settings should work + settings = read_settings(path=SAMPLE_CONFIG, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'very'), + os.path.join(SAMPLES_PATH, 'theme_standard')] + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + theme_output = os.path.join(self.temp_path, 'theme') + extra_path = os.path.join(theme_output, 'exciting', 'new', 'files') + + for file in ['a_stylesheet', 'a_template']: + self.assertTrue(os.path.exists(os.path.join(theme_output, file))) + + for file in ['wow!', 'boom!', 'bap!']: + self.assertTrue(os.path.exists(os.path.join(extra_path, file))) From b144c3cfbd6ea0e5bd1bba5d30d6bf3605499794 Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 24 Aug 2013 14:38:06 +0100 Subject: [PATCH 4/7] Hack out `overwrite` param --- pelican/generators.py | 2 +- pelican/utils.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pelican/generators.py b/pelican/generators.py index 26fa40ea..d695c7c8 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -544,7 +544,7 @@ class StaticGenerator(Generator): """Copy all the paths from source to destination""" for path in paths: copy(path, source, os.path.join(output_path, destination), - final_path, overwrite=True) + final_path) def generate_context(self): self.staticfiles = [] diff --git a/pelican/utils.py b/pelican/utils.py index e028c84c..d306de65 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -256,7 +256,7 @@ def slugify(value, substitutions=()): return value.decode('ascii') -def copy(path, source, destination, destination_path=None, overwrite=False): +def copy(path, source, destination, destination_path=None): """Copy path from origin to destination. The function is able to copy either files or directories. @@ -265,8 +265,6 @@ def copy(path, source, destination, destination_path=None, overwrite=False): :param source: the source dir :param destination: the destination dir :param destination_path: the destination path (optional) - :param overwrite: whether to overwrite the destination if already exists - or not """ if not destination_path: destination_path = path From ef16c915d4dfec668788bcff367a860214d01e55 Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 31 Aug 2013 21:48:19 +0100 Subject: [PATCH 5/7] Clarification of THEME_STATIC_PATHS behaviour --- docs/settings.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index c709a339..075bea83 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -597,7 +597,10 @@ Setting name (default value) What does it do? `THEME_STATIC_PATHS`. Default is `theme`. `THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default value is `static`, but if your theme has - other static paths, you can put them here. + other static paths, you can put them here. If files + or directories with the same names are included in + the paths defined in this settings, they will be + progressively overwritten. `CSS_FILE` (``'main.css'``) Specify the CSS file you want to load. ================================================ ===================================================== From 10c62b27dd3ca59972978ee4d57022739769bb2b Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 31 Aug 2013 22:00:52 +0100 Subject: [PATCH 6/7] More exciting files --- samples/kinda/exciting/new/files/zap! | 0 samples/kinda/exciting/old | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 samples/kinda/exciting/new/files/zap! create mode 100644 samples/kinda/exciting/old diff --git a/samples/kinda/exciting/new/files/zap! b/samples/kinda/exciting/new/files/zap! new file mode 100644 index 00000000..e69de29b diff --git a/samples/kinda/exciting/old b/samples/kinda/exciting/old new file mode 100644 index 00000000..e69de29b From 089059aec611b0827b925b987cb0f59bbfe4c485 Mon Sep 17 00:00:00 2001 From: bmcorser Date: Sat, 31 Aug 2013 22:11:03 +0100 Subject: [PATCH 7/7] Clarify revised functinality --- pelican/tests/test_pelican.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py index db2d0e6b..e829e1a5 100644 --- a/pelican/tests/test_pelican.py +++ b/pelican/tests/test_pelican.py @@ -99,6 +99,7 @@ class TestPelican(LoggedTestCase): 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'very'), + os.path.join(SAMPLES_PATH, 'kinda'), os.path.join(SAMPLES_PATH, 'theme_standard')] }) pelican = Pelican(settings=settings) @@ -109,5 +110,5 @@ class TestPelican(LoggedTestCase): for file in ['a_stylesheet', 'a_template']: self.assertTrue(os.path.exists(os.path.join(theme_output, file))) - for file in ['wow!', 'boom!', 'bap!']: + for file in ['wow!', 'boom!', 'bap!', 'zap!']: self.assertTrue(os.path.exists(os.path.join(extra_path, file)))