108 lines
2.8 KiB
Python
108 lines
2.8 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
"""
|
||
|
cookiecutter.hooks
|
||
|
------------------
|
||
|
|
||
|
Functions for discovering and executing various cookiecutter hooks.
|
||
|
"""
|
||
|
|
||
|
import io
|
||
|
import logging
|
||
|
import os
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import tempfile
|
||
|
|
||
|
from jinja2 import Template
|
||
|
|
||
|
from cookiecutter import utils
|
||
|
|
||
|
_HOOKS = [
|
||
|
'pre_gen_project',
|
||
|
'post_gen_project',
|
||
|
# TODO: other hooks should be listed here
|
||
|
]
|
||
|
|
||
|
|
||
|
def find_hooks():
|
||
|
"""
|
||
|
Must be called with the project template as the current working directory.
|
||
|
Returns a dict of all hook scripts provided.
|
||
|
Dict's key will be the hook/script's name, without extension, while
|
||
|
values will be the absolute path to the script.
|
||
|
Missing scripts will not be included in the returned dict.
|
||
|
"""
|
||
|
hooks_dir = 'hooks'
|
||
|
r = {}
|
||
|
logging.debug('hooks_dir is {0}'.format(hooks_dir))
|
||
|
if not os.path.isdir(hooks_dir):
|
||
|
logging.debug('No hooks/ dir in template_dir')
|
||
|
return r
|
||
|
for f in os.listdir(hooks_dir):
|
||
|
basename = os.path.splitext(os.path.basename(f))[0]
|
||
|
if basename in _HOOKS:
|
||
|
r[basename] = os.path.abspath(os.path.join(hooks_dir, f))
|
||
|
return r
|
||
|
|
||
|
|
||
|
def run_script(script_path, cwd='.'):
|
||
|
"""
|
||
|
Executes a script from a working directory.
|
||
|
|
||
|
:param script_path: Absolute path to the script to run.
|
||
|
:param cwd: The directory to run the script from.
|
||
|
"""
|
||
|
run_thru_shell = sys.platform.startswith('win')
|
||
|
if script_path.endswith('.py'):
|
||
|
script_command = [sys.executable, script_path]
|
||
|
else:
|
||
|
script_command = [script_path]
|
||
|
|
||
|
utils.make_executable(script_path)
|
||
|
|
||
|
proc = subprocess.Popen(
|
||
|
script_command,
|
||
|
shell=run_thru_shell,
|
||
|
cwd=cwd
|
||
|
)
|
||
|
proc.wait()
|
||
|
|
||
|
|
||
|
def run_script_with_context(script_path, cwd, context):
|
||
|
"""
|
||
|
Executes a script after rendering with it Jinja.
|
||
|
|
||
|
:param script_path: Absolute path to the script to run.
|
||
|
:param cwd: The directory to run the script from.
|
||
|
:param context: Cookiecutter project template context.
|
||
|
"""
|
||
|
_, extension = os.path.splitext(script_path)
|
||
|
|
||
|
contents = io.open(script_path, 'r', encoding='utf-8').read()
|
||
|
|
||
|
with tempfile.NamedTemporaryFile(
|
||
|
delete=False,
|
||
|
mode='w',
|
||
|
suffix=extension
|
||
|
) as temp:
|
||
|
temp.write(Template(contents).render(**context))
|
||
|
|
||
|
run_script(temp.name, cwd)
|
||
|
|
||
|
|
||
|
def run_hook(hook_name, project_dir, context):
|
||
|
"""
|
||
|
Try to find and execute a hook from the specified project directory.
|
||
|
|
||
|
:param hook_name: The hook to execute.
|
||
|
:param project_dir: The directory to execute the script from.
|
||
|
:param context: Cookiecutter project context.
|
||
|
"""
|
||
|
script = find_hooks().get(hook_name)
|
||
|
if script is None:
|
||
|
logging.debug('No hooks found')
|
||
|
return
|
||
|
return run_script_with_context(script, project_dir, context)
|