diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 96d89ad9a..e5d1e7f52 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: - id: check-xml - id: check-yaml exclude: "not_rendered.yml|invalid-config.yaml" - - repo: https://gitlab.com/pycqa/flake8 + - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 diff --git a/.python-version b/.python-version deleted file mode 100644 index c8e988bc2..000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -cookiecutter diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py index 26ae2faa9..8551df32d 100644 --- a/cookiecutter/hooks.py +++ b/cookiecutter/hooks.py @@ -105,19 +105,36 @@ def run_script_with_context(script_path, cwd, context): with open(script_path, encoding='utf-8') as file: contents = file.read() - temp_name = None + temp_name = None # Just to make sure it's defined in this scope. with tempfile.NamedTemporaryFile(delete=False, mode='wb', suffix=extension) as temp: env = StrictEnvironment(context=context, keep_trailing_newline=True) template = env.from_string(contents) output = template.render(**context) - if os.getenv('COOKIECUTTER_DEBUG_HOOKS', None): + debug_hooks_path = os.getenv('COOKIECUTTER_DEBUG_HOOKS', None) + if debug_hooks_path: import pathlib - temp = tempfile.NamedTemporaryFile(delete=False, mode='wb', suffix=extension, dir='/tmp', prefix=os.path.basename(_)+'+') - temp = pathlib.Path(temp.name) - temp.unlink() - temp = pathlib.Path(os.path.join(temp.parent, temp.stem.split('+')[0]+temp.suffix)) - temp.write_text(output, encoding='utf-8') - temp_name = str(temp) + + debug_hooks_path = pathlib.Path(debug_hooks_path) + if not debug_hooks_path.exists(): + debug_hooks_path = tempfile.gettempdir() + os.environ['COOKIECUTTER_DEBUG_HOOKS'] = debug_hooks_path + with tempfile.NamedTemporaryFile( + delete=False, + mode='wb', + suffix=extension, + dir=debug_hooks_path, + prefix=os.path.basename(_) + '+', + ) as debug_temp: + debug_temp = pathlib.Path(debug_temp.name) + debug_temp = pathlib.Path( + os.path.join( + debug_temp.parent, + debug_temp.stem.split('+')[0] + debug_temp.suffix, + ) + ) + debug_temp.write_text(output, encoding='utf-8') + temp_name = str(debug_temp) + sys.stderr.write(f"DEBUG: Hook {script_path} rendered to {debug_temp}") else: temp.write(output.encode('utf-8')) temp_name = temp.name diff --git a/cookiecutter/main.py b/cookiecutter/main.py index d4c6dbb99..ba1df1b6c 100644 --- a/cookiecutter/main.py +++ b/cookiecutter/main.py @@ -117,8 +117,6 @@ def cookiecutter( dump(config_dict['replay_dir'], template_name, context) - from cookiecutter import __version__ as cookiecutter__version__ - context['__version__'] = cookiecutter__version__ # Create project from local context and project template. with import_patch: result = generate_files( diff --git a/tests/test_hooks.py b/tests/test_hooks.py index 9abd66af2..03795cab5 100644 --- a/tests/test_hooks.py +++ b/tests/test_hooks.py @@ -1,4 +1,8 @@ """Tests for `cookiecutter.hooks` module.""" +import pathlib +import shutil +import tempfile + import errno import os import stat @@ -216,6 +220,35 @@ def test_run_hook(self): hooks.run_hook('post_gen_project', tests_dir, {}) assert os.path.isfile(os.path.join(tests_dir, 'shell_post.txt')) + def test_run_hook_debug(self): + """Execute hook from specified template in specified output \ + directory.""" + tests_dir = os.path.join(self.repo_path, 'input{{hooks}}') + assert os.path.isdir(tempfile.gettempdir()), tempfile.gettempdir() + debug_hooks_dir = os.path.join( + tempfile.gettempdir(), 'cookiecutter-debug-hooks' + ) + if os.path.isdir(debug_hooks_dir): + shutil.rmtree(debug_hooks_dir) + os.mkdir(debug_hooks_dir) + for location in (debug_hooks_dir, '1'): + os.environ['COOKIECUTTER_DEBUG_HOOKS'] = location + with utils.work_in(self.repo_path): + hooks.run_hook('pre_gen_project', tests_dir, {}) + assert os.path.isfile(os.path.join(tests_dir, 'python_pre.txt')) + assert os.path.isfile(os.path.join(tests_dir, 'shell_pre.txt')) + + hooks.run_hook('post_gen_project', tests_dir, {}) + assert os.path.isfile(os.path.join(tests_dir, 'shell_post.txt')) + hook_traces = list( + pathlib.Path(os.environ['COOKIECUTTER_DEBUG_HOOKS']).glob('*') + ) + assert len(hook_traces) > 2, os.system( + "ls -l " + os.environ['COOKIECUTTER_DEBUG_HOOKS'] + ) + del os.environ['COOKIECUTTER_DEBUG_HOOKS'] + shutil.rmtree(debug_hooks_dir) + def test_run_failing_hook(self): """Test correct exception raise if hook exit code is not zero.""" hook_path = os.path.join(self.hooks_path, 'pre_gen_project.py')