prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Empty hook file causes cryptic error
  If you have a pre_gen_project.sh or a post_gen_project.sh file with no data in it, cookiecutter fails with an unhelpful traceback.
  
  ```
  Traceback (most recent call last):
    File "/usr/local/bin/cookiecutter", line 11, in <module>
      sys.exit(main())
    File "/usr/local/lib/python2.7/site-packages/click/core.py", line 716, in __call__
      return self.main(*args, **kwargs)
    File "/usr/local/lib/python2.7/site-packages/click/core.py", line 696, in main
      rv = self.invoke(ctx)
    File "/usr/local/lib/python2.7/site-packages/click/core.py", line 889, in invoke
      return ctx.invoke(self.callback, **ctx.params)
    File "/usr/local/lib/python2.7/site-packages/click/core.py", line 534, in invoke
      return callback(*args, **kwargs)
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/cli.py", line 100, in main
      config_file=user_config
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/main.py", line 140, in cookiecutter
      output_dir=output_dir
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/generate.py", line 273, in generate_files
      _run_hook_from_repo_dir(repo_dir, 'pre_gen_project', project_dir, context)
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/generate.py", line 232, in _run_hook_from_repo_dir
      run_hook(hook_name, project_dir, context)
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py", line 116, in run_hook
      run_script_with_context(script, project_dir, context)
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py", line 101, in run_script_with_context
      run_script(temp.name, cwd)
    File "/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py", line 73, in run_script
      cwd=cwd
    File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 656, in __init__
      _cleanup()
    File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1335, in _execute_child
      raise child_exception
  OSError: [Errno 8] Exec format error
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `cookiecutter/hooks.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 
  4 """
  5 cookiecutter.hooks
  6 ------------------
  7 
  8 Functions for discovering and executing various cookiecutter hooks.
  9 """
  10 
  11 import io
  12 import logging
  13 import os
  14 import subprocess
  15 import sys
  16 import tempfile
  17 
  18 from jinja2 import Template
  19 
  20 from cookiecutter import utils
  21 from .exceptions import FailedHookException
  22 
  23 
  24 _HOOKS = [
  25     'pre_gen_project',
  26     'post_gen_project',
  27     # TODO: other hooks should be listed here
  28 ]
  29 EXIT_SUCCESS = 0
  30 
  31 
  32 def find_hooks():
  33     """
  34     Must be called with the project template as the current working directory.
  35     Returns a dict of all hook scripts provided.
  36     Dict's key will be the hook/script's name, without extension, while
  37     values will be the absolute path to the script.
  38     Missing scripts will not be included in the returned dict.
  39     """
  40     hooks_dir = 'hooks'
  41     r = {}
  42     logging.debug('hooks_dir is {0}'.format(hooks_dir))
  43     if not os.path.isdir(hooks_dir):
  44         logging.debug('No hooks/ dir in template_dir')
  45         return r
  46     for f in os.listdir(hooks_dir):
  47         basename = os.path.splitext(os.path.basename(f))[0]
  48         if basename in _HOOKS:
  49             r[basename] = os.path.abspath(os.path.join(hooks_dir, f))
  50     return r
  51 
  52 
  53 def run_script(script_path, cwd='.'):
  54     """
  55     Executes a script from a working directory.
  56 
  57     :param script_path: Absolute path to the script to run.
  58     :param cwd: The directory to run the script from.
  59     """
  60     run_thru_shell = sys.platform.startswith('win')
  61     if script_path.endswith('.py'):
  62         script_command = [sys.executable, script_path]
  63     else:
  64         script_command = [script_path]
  65 
  66     utils.make_executable(script_path)
  67 
  68     proc = subprocess.Popen(
  69         script_command,
  70         shell=run_thru_shell,
  71         cwd=cwd
  72     )
  73     exit_status = proc.wait()
  74     if exit_status != EXIT_SUCCESS:
  75         raise FailedHookException(
  76             "Hook script failed (exit status: %d)" % exit_status)
  77 
  78 
  79 def run_script_with_context(script_path, cwd, context):
  80     """
  81     Executes a script after rendering with it Jinja.
  82 
  83     :param script_path: Absolute path to the script to run.
  84     :param cwd: The directory to run the script from.
  85     :param context: Cookiecutter project template context.
  86     """
  87     _, extension = os.path.splitext(script_path)
  88 
  89     contents = io.open(script_path, 'r', encoding='utf-8').read()
  90 
  91     with tempfile.NamedTemporaryFile(
  92         delete=False,
  93         mode='wb',
  94         suffix=extension
  95     ) as temp:
  96         output = Template(contents).render(**context)
  97         temp.write(output.encode('utf-8'))
  98 
  99     run_script(temp.name, cwd)
  100 
  101 
  102 def run_hook(hook_name, project_dir, context):
  103     """
  104     Try to find and execute a hook from the specified project directory.
  105 
  106     :param hook_name: The hook to execute.
  107     :param project_dir: The directory to execute the script from.
  108     :param context: Cookiecutter project context.
  109     """
  110     script = find_hooks().get(hook_name)
  111     if script is None:
  112         logging.debug('No hooks found')
  113         return
  114     run_script_with_context(script, project_dir, context)
  115
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py
  --- a/cookiecutter/hooks.py
  +++ b/cookiecutter/hooks.py
  @@ -8,6 +8,7 @@
   Functions for discovering and executing various cookiecutter hooks.
   """
   
  +import errno
   import io
   import logging
   import os
  @@ -65,15 +66,23 @@
   
       utils.make_executable(script_path)
   
  -    proc = subprocess.Popen(
  -        script_command,
  -        shell=run_thru_shell,
  -        cwd=cwd
  -    )
  -    exit_status = proc.wait()
  -    if exit_status != EXIT_SUCCESS:
  +    try:
  +        proc = subprocess.Popen(
  +            script_command,
  +            shell=run_thru_shell,
  +            cwd=cwd
  +        )
  +        exit_status = proc.wait()
  +        if exit_status != EXIT_SUCCESS:
  +            raise FailedHookException(
  +                "Hook script failed (exit status: %d)" % exit_status)
  +    except OSError as oe:
  +        if oe.errno == errno.ENOEXEC:
  +            raise FailedHookException(
  +                "Hook script failed, might be an "
  +                "empty file or missing a shebang")
           raise FailedHookException(
  -            "Hook script failed (exit status: %d)" % exit_status)
  +            "Hook script failed (error: %s)" % oe)
   
   
   def run_script_with_context(script_path, cwd, context):
  
verification_info: {"golden_diff": "diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py\n--- a/cookiecutter/hooks.py\n+++ b/cookiecutter/hooks.py\n@@ -8,6 +8,7 @@\n Functions for discovering and executing various cookiecutter hooks.\n \"\"\"\n \n+import errno\n import io\n import logging\n import os\n@@ -65,15 +66,23 @@\n \n     utils.make_executable(script_path)\n \n-    proc = subprocess.Popen(\n-        script_command,\n-        shell=run_thru_shell,\n-        cwd=cwd\n-    )\n-    exit_status = proc.wait()\n-    if exit_status != EXIT_SUCCESS:\n+    try:\n+        proc = subprocess.Popen(\n+            script_command,\n+            shell=run_thru_shell,\n+            cwd=cwd\n+        )\n+        exit_status = proc.wait()\n+        if exit_status != EXIT_SUCCESS:\n+            raise FailedHookException(\n+                \"Hook script failed (exit status: %d)\" % exit_status)\n+    except OSError as oe:\n+        if oe.errno == errno.ENOEXEC:\n+            raise FailedHookException(\n+                \"Hook script failed, might be an \"\n+                \"empty file or missing a shebang\")\n         raise FailedHookException(\n-            \"Hook script failed (exit status: %d)\" % exit_status)\n+            \"Hook script failed (error: %s)\" % oe)\n \n \n def run_script_with_context(script_path, cwd, context):\n", "issue": "Empty hook file causes cryptic error\nIf you have a pre_gen_project.sh or a post_gen_project.sh file with no data in it, cookiecutter fails with an unhelpful traceback.\n\n```\nTraceback (most recent call last):\n  File \"/usr/local/bin/cookiecutter\", line 11, in <module>\n    sys.exit(main())\n  File \"/usr/local/lib/python2.7/site-packages/click/core.py\", line 716, in __call__\n    return self.main(*args, **kwargs)\n  File \"/usr/local/lib/python2.7/site-packages/click/core.py\", line 696, in main\n    rv = self.invoke(ctx)\n  File \"/usr/local/lib/python2.7/site-packages/click/core.py\", line 889, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File \"/usr/local/lib/python2.7/site-packages/click/core.py\", line 534, in invoke\n    return callback(*args, **kwargs)\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/cli.py\", line 100, in main\n    config_file=user_config\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/main.py\", line 140, in cookiecutter\n    output_dir=output_dir\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/generate.py\", line 273, in generate_files\n    _run_hook_from_repo_dir(repo_dir, 'pre_gen_project', project_dir, context)\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/generate.py\", line 232, in _run_hook_from_repo_dir\n    run_hook(hook_name, project_dir, context)\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py\", line 116, in run_hook\n    run_script_with_context(script, project_dir, context)\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py\", line 101, in run_script_with_context\n    run_script(temp.name, cwd)\n  File \"/usr/local/lib/python2.7/site-packages/cookiecutter/hooks.py\", line 73, in run_script\n    cwd=cwd\n  File \"/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py\", line 656, in __init__\n    _cleanup()\n  File \"/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py\", line 1335, in _execute_child\n    raise child_exception\nOSError: [Errno 8] Exec format error\n```\n\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\ncookiecutter.hooks\n------------------\n\nFunctions for discovering and executing various cookiecutter hooks.\n\"\"\"\n\nimport io\nimport logging\nimport os\nimport subprocess\nimport sys\nimport tempfile\n\nfrom jinja2 import Template\n\nfrom cookiecutter import utils\nfrom .exceptions import FailedHookException\n\n\n_HOOKS = [\n    'pre_gen_project',\n    'post_gen_project',\n    # TODO: other hooks should be listed here\n]\nEXIT_SUCCESS = 0\n\n\ndef find_hooks():\n    \"\"\"\n    Must be called with the project template as the current working directory.\n    Returns a dict of all hook scripts provided.\n    Dict's key will be the hook/script's name, without extension, while\n    values will be the absolute path to the script.\n    Missing scripts will not be included in the returned dict.\n    \"\"\"\n    hooks_dir = 'hooks'\n    r = {}\n    logging.debug('hooks_dir is {0}'.format(hooks_dir))\n    if not os.path.isdir(hooks_dir):\n        logging.debug('No hooks/ dir in template_dir')\n        return r\n    for f in os.listdir(hooks_dir):\n        basename = os.path.splitext(os.path.basename(f))[0]\n        if basename in _HOOKS:\n            r[basename] = os.path.abspath(os.path.join(hooks_dir, f))\n    return r\n\n\ndef run_script(script_path, cwd='.'):\n    \"\"\"\n    Executes a script from a working directory.\n\n    :param script_path: Absolute path to the script to run.\n    :param cwd: The directory to run the script from.\n    \"\"\"\n    run_thru_shell = sys.platform.startswith('win')\n    if script_path.endswith('.py'):\n        script_command = [sys.executable, script_path]\n    else:\n        script_command = [script_path]\n\n    utils.make_executable(script_path)\n\n    proc = subprocess.Popen(\n        script_command,\n        shell=run_thru_shell,\n        cwd=cwd\n    )\n    exit_status = proc.wait()\n    if exit_status != EXIT_SUCCESS:\n        raise FailedHookException(\n            \"Hook script failed (exit status: %d)\" % exit_status)\n\n\ndef run_script_with_context(script_path, cwd, context):\n    \"\"\"\n    Executes a script after rendering with it Jinja.\n\n    :param script_path: Absolute path to the script to run.\n    :param cwd: The directory to run the script from.\n    :param context: Cookiecutter project template context.\n    \"\"\"\n    _, extension = os.path.splitext(script_path)\n\n    contents = io.open(script_path, 'r', encoding='utf-8').read()\n\n    with tempfile.NamedTemporaryFile(\n        delete=False,\n        mode='wb',\n        suffix=extension\n    ) as temp:\n        output = Template(contents).render(**context)\n        temp.write(output.encode('utf-8'))\n\n    run_script(temp.name, cwd)\n\n\ndef run_hook(hook_name, project_dir, context):\n    \"\"\"\n    Try to find and execute a hook from the specified project directory.\n\n    :param hook_name: The hook to execute.\n    :param project_dir: The directory to execute the script from.\n    :param context: Cookiecutter project context.\n    \"\"\"\n    script = find_hooks().get(hook_name)\n    if script is None:\n        logging.debug('No hooks found')\n        return\n    run_script_with_context(script, project_dir, context)\n", "path": "cookiecutter/hooks.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\ncookiecutter.hooks\n------------------\n\nFunctions for discovering and executing various cookiecutter hooks.\n\"\"\"\n\nimport errno\nimport io\nimport logging\nimport os\nimport subprocess\nimport sys\nimport tempfile\n\nfrom jinja2 import Template\n\nfrom cookiecutter import utils\nfrom .exceptions import FailedHookException\n\n\n_HOOKS = [\n    'pre_gen_project',\n    'post_gen_project',\n    # TODO: other hooks should be listed here\n]\nEXIT_SUCCESS = 0\n\n\ndef find_hooks():\n    \"\"\"\n    Must be called with the project template as the current working directory.\n    Returns a dict of all hook scripts provided.\n    Dict's key will be the hook/script's name, without extension, while\n    values will be the absolute path to the script.\n    Missing scripts will not be included in the returned dict.\n    \"\"\"\n    hooks_dir = 'hooks'\n    r = {}\n    logging.debug('hooks_dir is {0}'.format(hooks_dir))\n    if not os.path.isdir(hooks_dir):\n        logging.debug('No hooks/ dir in template_dir')\n        return r\n    for f in os.listdir(hooks_dir):\n        basename = os.path.splitext(os.path.basename(f))[0]\n        if basename in _HOOKS:\n            r[basename] = os.path.abspath(os.path.join(hooks_dir, f))\n    return r\n\n\ndef run_script(script_path, cwd='.'):\n    \"\"\"\n    Executes a script from a working directory.\n\n    :param script_path: Absolute path to the script to run.\n    :param cwd: The directory to run the script from.\n    \"\"\"\n    run_thru_shell = sys.platform.startswith('win')\n    if script_path.endswith('.py'):\n        script_command = [sys.executable, script_path]\n    else:\n        script_command = [script_path]\n\n    utils.make_executable(script_path)\n\n    try:\n        proc = subprocess.Popen(\n            script_command,\n            shell=run_thru_shell,\n            cwd=cwd\n        )\n        exit_status = proc.wait()\n        if exit_status != EXIT_SUCCESS:\n            raise FailedHookException(\n                \"Hook script failed (exit status: %d)\" % exit_status)\n    except OSError as oe:\n        if oe.errno == errno.ENOEXEC:\n            raise FailedHookException(\n                \"Hook script failed, might be an \"\n                \"empty file or missing a shebang\")\n        raise FailedHookException(\n            \"Hook script failed (error: %s)\" % oe)\n\n\ndef run_script_with_context(script_path, cwd, context):\n    \"\"\"\n    Executes a script after rendering with it Jinja.\n\n    :param script_path: Absolute path to the script to run.\n    :param cwd: The directory to run the script from.\n    :param context: Cookiecutter project template context.\n    \"\"\"\n    _, extension = os.path.splitext(script_path)\n\n    contents = io.open(script_path, 'r', encoding='utf-8').read()\n\n    with tempfile.NamedTemporaryFile(\n        delete=False,\n        mode='wb',\n        suffix=extension\n    ) as temp:\n        output = Template(contents).render(**context)\n        temp.write(output.encode('utf-8'))\n\n    run_script(temp.name, cwd)\n\n\ndef run_hook(hook_name, project_dir, context):\n    \"\"\"\n    Try to find and execute a hook from the specified project directory.\n\n    :param hook_name: The hook to execute.\n    :param project_dir: The directory to execute the script from.\n    :param context: Cookiecutter project context.\n    \"\"\"\n    script = find_hooks().get(hook_name)\n    if script is None:\n        logging.debug('No hooks found')\n        return\n    run_script_with_context(script, project_dir, context)\n", "path": "cookiecutter/hooks.py"}]}