We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
spack install broken on python3
Using 1e18ace6472c94893cc567ca757032269e02460f and python3 I still get:
```
$ spack install pax-utils
==> Installing pax-utils
==> Fetching https://dev.gentoo.org/~vapier/dist/pax-utils-1.2.2.tar.xz
######################################################################## 100.0%
==> Staging archive: /Users/junghans/spack/var/spack/stage/pax-utils-1.2.2-xiaxjymvkqyzqrlkwwxr33nggcitgidv/pax-utils-1.2.2.tar.xz
==> Created stage in /Users/junghans/spack/var/spack/stage/pax-utils-1.2.2-xiaxjymvkqyzqrlkwwxr33nggcitgidv
==> Ran patch() for pax-utils
==> Building pax-utils [AutotoolsPackage]
==> Executing phase : 'autoreconf'
==> Executing phase : 'configure'
==> Executing phase : 'build'
==> Executing phase : 'install'
==> Error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf8 in position 40: invalid start byte
/Users/junghans/spack/lib/spack/spack/package.py:1291, in build_process:
     1219         def build_process(input_stream):
     1220             """Forked for each build. Has its own process and python
     1221                module space set up by build_environment.fork()."""
     1222
     1223             # We are in the child process. This means that our sys.stdin is
     1224             # equal to open(os.devnull). Python did this to prevent our process
     1225             # and the parent process from possible simultaneous reading from
     1226             # the original standard input. But we assume that the parent
     1227             # process is not going to read from it till we are done here,
     1228             # otherwise it should not have passed us the copy of the stream.
     1229             # Thus, we are free to work with the the copy (input_stream)
     1230             # however we want. For example, we might want to call functions
     1231             # (e.g. input()) that implicitly read from whatever stream is
     1232             # assigned to sys.stdin. Since we want them to work with the
     1233             # original input stream, we are making the following assignment:
     1234             sys.stdin = input_stream
     1235
     1236             start_time = time.time()
     1237             if not fake:
     1238                 if not skip_patch:
     1239                     self.do_patch()
     1240                 else:
     1241                     self.do_stage()
     1242
     1243             tty.msg(
     1244                 'Building {0} [{1}]'.format(self.name, self.build_system_class)
     1245             )
     1246
     1247             self.stage.keep = keep_stage
     1248             with self._stage_and_write_lock():
     1249                 # Run the pre-install hook in the child process after
     1250                 # the directory is created.
     1251                 spack.hooks.pre_install(self.spec)
     1252                 if fake:
     1253                     self.do_fake_install()
     1254                 else:
     1255                     # Do the real install in the source directory.
     1256                     self.stage.chdir_to_source()
     1257
     1258                     # Save the build environment in a file before building.
     1259                     env_path = join_path(os.getcwd(), 'spack-build.env')
     1260
     1261                     # Redirect I/O to a build log (and optionally to
     1262                     # the terminal)
     1263                     log_path = join_path(os.getcwd(), 'spack-build.out')
     1264
     1265                     # FIXME : refactor this assignment
     1266                     self.log_path = log_path
     1267                     self.env_path = env_path
     1268                     dump_environment(env_path)
     1269
     1270                     # Spawn a daemon that reads from a pipe and redirects
     1271                     # everything to log_path
     1272                     redirection_context = log_output(
     1273                         log_path,
     1274                         echo=verbose,
     1275                         force_color=sys.stdout.isatty(),
     1276                         debug=True,
     1277                         input_stream=input_stream
     1278                     )
     1279                     with redirection_context as log_redirection:
     1280                         for phase_name, phase in zip(
     1281                                 self.phases, self._InstallPhase_phases):
     1282                             tty.msg(
     1283                                 'Executing phase : \'{0}\''.format(phase_name)
     1284                             )
     1285                             # Redirect stdout and stderr to daemon pipe
     1286                             with log_redirection:
     1287                                 getattr(self, phase)(
     1288                                     self.spec, self.prefix)
     1289                     self.log()
     1290                 # Run post install hooks before build stage is removed.
  >> 1291                 spack.hooks.post_install(self.spec)
     1292
     1293             # Stop timer.
     1294             self._total_time = time.time() - start_time
     1295             build_time = self._total_time - self._fetch_time
     1296
     1297             tty.msg("Successfully installed %s" % self.name,
     1298                     "Fetch: %s.  Build: %s.  Total: %s." %
     1299                     (_hms(self._fetch_time), _hms(build_time),
     1300                      _hms(self._total_time)))
     1301             print_pkg(self.prefix)

See build log for details:
  /tmp/junghans/spack-stage/spack-stage-vsdhukt3/pax-utils-1.2.2/spack-build.out
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/spack/spack/hooks/sbang.py`
Content:
```
1 ##############################################################################
2 # Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
3 # Produced at the Lawrence Livermore National Laboratory.
4 #
5 # This file is part of Spack.
6 # Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
7 # LLNL-CODE-647188
8 #
9 # For details, see https://github.com/llnl/spack
10 # Please also see the LICENSE file for our notice and the LGPL.
11 #
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU Lesser General Public License (as
14 # published by the Free Software Foundation) version 2.1, February 1999.
15 #
16 # This program is distributed in the hope that it will be useful, but
17 # WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
19 # conditions of the GNU Lesser General Public License for more details.
20 #
21 # You should have received a copy of the GNU Lesser General Public
22 # License along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ##############################################################################
25 import os
26 import stat
27 import re
28 
29 import llnl.util.tty as tty
30 
31 import spack
32 import spack.modules
33 
34 # Character limit for shebang line.  Using Linux's 127 characters
35 # here, as it is the shortest I could find on a modern OS.
36 shebang_limit = 127
37 
38 
39 def shebang_too_long(path):
40     """Detects whether a file has a shebang line that is too long."""
41     with open(path, 'r') as script:
42         bytes = script.read(2)
43         if bytes != '#!':
44             return False
45 
46         line = bytes + script.readline()
47         return len(line) > shebang_limit
48 
49 
50 def filter_shebang(path):
51     """Adds a second shebang line, using sbang, at the beginning of a file."""
52     with open(path, 'r') as original_file:
53         original = original_file.read()
54 
55     # This line will be prepended to file
56     new_sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.spack_root
57 
58     # Skip files that are already using sbang.
59     if original.startswith(new_sbang_line):
60         return
61 
62     # Use --! instead of #! on second line for lua.
63     if re.search(r'^#!(/[^/]*)*lua\b', original):
64         original = re.sub(r'^#', '--', original)
65 
66     # Change non-writable files to be writable if needed.
67     saved_mode = None
68     if not os.access(path, os.W_OK):
69         st = os.stat(path)
70         saved_mode = st.st_mode
71         os.chmod(path, saved_mode | stat.S_IWRITE)
72 
73     with open(path, 'w') as new_file:
74         new_file.write(new_sbang_line)
75         new_file.write(original)
76 
77     # Restore original permissions.
78     if saved_mode is not None:
79         os.chmod(path, saved_mode)
80 
81     tty.warn("Patched overlong shebang in %s" % path)
82 
83 
84 def filter_shebangs_in_directory(directory, filenames=None):
85     if filenames is None:
86         filenames = os.listdir(directory)
87     for file in filenames:
88         path = os.path.join(directory, file)
89 
90         # only handle files
91         if not os.path.isfile(path):
92             continue
93 
94         # only handle links that resolve within THIS package's prefix.
95         if os.path.islink(path):
96             real_path = os.path.realpath(path)
97             if not real_path.startswith(directory + os.sep):
98                 continue
99 
100         # test the file for a long shebang, and filter
101         if shebang_too_long(path):
102             filter_shebang(path)
103 
104 
105 def post_install(spec):
106     """This hook edits scripts so that they call /bin/bash
107     $spack_prefix/bin/sbang instead of something longer than the
108     shebang limit.
109     """
110     if spec.external:
111         tty.debug('SKIP: shebang filtering [external package]')
112         return
113 
114     for directory, _, filenames in os.walk(spec.prefix):
115         filter_shebangs_in_directory(directory, filenames)
116
```
--- 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()

```

diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py
--- a/lib/spack/spack/hooks/sbang.py
+++ b/lib/spack/spack/hooks/sbang.py
@@ -38,9 +38,12 @@
 
 def shebang_too_long(path):
     """Detects whether a file has a shebang line that is too long."""
-    with open(path, 'r') as script:
+    if not os.path.isfile(path):
+        return False
+
+    with open(path, 'rb') as script:
         bytes = script.read(2)
-        if bytes != '#!':
+        if bytes != b'#!':
             return False
 
         line = bytes + script.readline()

{"golden_diff": "diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py\n--- a/lib/spack/spack/hooks/sbang.py\n+++ b/lib/spack/spack/hooks/sbang.py\n@@ -38,9 +38,12 @@\n \n def shebang_too_long(path):\n     \"\"\"Detects whether a file has a shebang line that is too long.\"\"\"\n-    with open(path, 'r') as script:\n+    if not os.path.isfile(path):\n+        return False\n+\n+    with open(path, 'rb') as script:\n         bytes = script.read(2)\n-        if bytes != '#!':\n+        if bytes != b'#!':\n             return False\n \n         line = bytes + script.readline()\n", "issue": "spack install broken on python3\nUsing 1e18ace6472c94893cc567ca757032269e02460f and python3 I still get:\r\n```\r\n$ spack install pax-utils\r\n==> Installing pax-utils\r\n==> Fetching https://dev.gentoo.org/~vapier/dist/pax-utils-1.2.2.tar.xz\r\n######################################################################## 100.0%\r\n==> Staging archive: /Users/junghans/spack/var/spack/stage/pax-utils-1.2.2-xiaxjymvkqyzqrlkwwxr33nggcitgidv/pax-utils-1.2.2.tar.xz\r\n==> Created stage in /Users/junghans/spack/var/spack/stage/pax-utils-1.2.2-xiaxjymvkqyzqrlkwwxr33nggcitgidv\r\n==> Ran patch() for pax-utils\r\n==> Building pax-utils [AutotoolsPackage]\r\n==> Executing phase : 'autoreconf'\r\n==> Executing phase : 'configure'\r\n==> Executing phase : 'build'\r\n==> Executing phase : 'install'\r\n==> Error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf8 in position 40: invalid start byte\r\n/Users/junghans/spack/lib/spack/spack/package.py:1291, in build_process:\r\n     1219         def build_process(input_stream):\r\n     1220             \"\"\"Forked for each build. Has its own process and python\r\n     1221                module space set up by build_environment.fork().\"\"\"\r\n     1222\r\n     1223             # We are in the child process. This means that our sys.stdin is\r\n     1224             # equal to open(os.devnull). Python did this to prevent our process\r\n     1225             # and the parent process from possible simultaneous reading from\r\n     1226             # the original standard input. But we assume that the parent\r\n     1227             # process is not going to read from it till we are done here,\r\n     1228             # otherwise it should not have passed us the copy of the stream.\r\n     1229             # Thus, we are free to work with the the copy (input_stream)\r\n     1230             # however we want. For example, we might want to call functions\r\n     1231             # (e.g. input()) that implicitly read from whatever stream is\r\n     1232             # assigned to sys.stdin. Since we want them to work with the\r\n     1233             # original input stream, we are making the following assignment:\r\n     1234             sys.stdin = input_stream\r\n     1235\r\n     1236             start_time = time.time()\r\n     1237             if not fake:\r\n     1238                 if not skip_patch:\r\n     1239                     self.do_patch()\r\n     1240                 else:\r\n     1241                     self.do_stage()\r\n     1242\r\n     1243             tty.msg(\r\n     1244                 'Building {0} [{1}]'.format(self.name, self.build_system_class)\r\n     1245             )\r\n     1246\r\n     1247             self.stage.keep = keep_stage\r\n     1248             with self._stage_and_write_lock():\r\n     1249                 # Run the pre-install hook in the child process after\r\n     1250                 # the directory is created.\r\n     1251                 spack.hooks.pre_install(self.spec)\r\n     1252                 if fake:\r\n     1253                     self.do_fake_install()\r\n     1254                 else:\r\n     1255                     # Do the real install in the source directory.\r\n     1256                     self.stage.chdir_to_source()\r\n     1257\r\n     1258                     # Save the build environment in a file before building.\r\n     1259                     env_path = join_path(os.getcwd(), 'spack-build.env')\r\n     1260\r\n     1261                     # Redirect I/O to a build log (and optionally to\r\n     1262                     # the terminal)\r\n     1263                     log_path = join_path(os.getcwd(), 'spack-build.out')\r\n     1264\r\n     1265                     # FIXME : refactor this assignment\r\n     1266                     self.log_path = log_path\r\n     1267                     self.env_path = env_path\r\n     1268                     dump_environment(env_path)\r\n     1269\r\n     1270                     # Spawn a daemon that reads from a pipe and redirects\r\n     1271                     # everything to log_path\r\n     1272                     redirection_context = log_output(\r\n     1273                         log_path,\r\n     1274                         echo=verbose,\r\n     1275                         force_color=sys.stdout.isatty(),\r\n     1276                         debug=True,\r\n     1277                         input_stream=input_stream\r\n     1278                     )\r\n     1279                     with redirection_context as log_redirection:\r\n     1280                         for phase_name, phase in zip(\r\n     1281                                 self.phases, self._InstallPhase_phases):\r\n     1282                             tty.msg(\r\n     1283                                 'Executing phase : \\'{0}\\''.format(phase_name)\r\n     1284                             )\r\n     1285                             # Redirect stdout and stderr to daemon pipe\r\n     1286                             with log_redirection:\r\n     1287                                 getattr(self, phase)(\r\n     1288                                     self.spec, self.prefix)\r\n     1289                     self.log()\r\n     1290                 # Run post install hooks before build stage is removed.\r\n  >> 1291                 spack.hooks.post_install(self.spec)\r\n     1292\r\n     1293             # Stop timer.\r\n     1294             self._total_time = time.time() - start_time\r\n     1295             build_time = self._total_time - self._fetch_time\r\n     1296\r\n     1297             tty.msg(\"Successfully installed %s\" % self.name,\r\n     1298                     \"Fetch: %s.  Build: %s.  Total: %s.\" %\r\n     1299                     (_hms(self._fetch_time), _hms(build_time),\r\n     1300                      _hms(self._total_time)))\r\n     1301             print_pkg(self.prefix)\r\n\r\nSee build log for details:\r\n  /tmp/junghans/spack-stage/spack-stage-vsdhukt3/pax-utils-1.2.2/spack-build.out\r\n```\n", "before_files": [{"content": "##############################################################################\n# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.\n# Produced at the Lawrence Livermore National Laboratory.\n#\n# This file is part of Spack.\n# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.\n# LLNL-CODE-647188\n#\n# For details, see https://github.com/llnl/spack\n# Please also see the LICENSE file for our notice and the LGPL.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License (as\n# published by the Free Software Foundation) version 2.1, February 1999.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and\n# conditions of the GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n##############################################################################\nimport os\nimport stat\nimport re\n\nimport llnl.util.tty as tty\n\nimport spack\nimport spack.modules\n\n# Character limit for shebang line.  Using Linux's 127 characters\n# here, as it is the shortest I could find on a modern OS.\nshebang_limit = 127\n\n\ndef shebang_too_long(path):\n    \"\"\"Detects whether a file has a shebang line that is too long.\"\"\"\n    with open(path, 'r') as script:\n        bytes = script.read(2)\n        if bytes != '#!':\n            return False\n\n        line = bytes + script.readline()\n        return len(line) > shebang_limit\n\n\ndef filter_shebang(path):\n    \"\"\"Adds a second shebang line, using sbang, at the beginning of a file.\"\"\"\n    with open(path, 'r') as original_file:\n        original = original_file.read()\n\n    # This line will be prepended to file\n    new_sbang_line = '#!/bin/bash %s/bin/sbang\\n' % spack.spack_root\n\n    # Skip files that are already using sbang.\n    if original.startswith(new_sbang_line):\n        return\n\n    # Use --! instead of #! on second line for lua.\n    if re.search(r'^#!(/[^/]*)*lua\\b', original):\n        original = re.sub(r'^#', '--', original)\n\n    # Change non-writable files to be writable if needed.\n    saved_mode = None\n    if not os.access(path, os.W_OK):\n        st = os.stat(path)\n        saved_mode = st.st_mode\n        os.chmod(path, saved_mode | stat.S_IWRITE)\n\n    with open(path, 'w') as new_file:\n        new_file.write(new_sbang_line)\n        new_file.write(original)\n\n    # Restore original permissions.\n    if saved_mode is not None:\n        os.chmod(path, saved_mode)\n\n    tty.warn(\"Patched overlong shebang in %s\" % path)\n\n\ndef filter_shebangs_in_directory(directory, filenames=None):\n    if filenames is None:\n        filenames = os.listdir(directory)\n    for file in filenames:\n        path = os.path.join(directory, file)\n\n        # only handle files\n        if not os.path.isfile(path):\n            continue\n\n        # only handle links that resolve within THIS package's prefix.\n        if os.path.islink(path):\n            real_path = os.path.realpath(path)\n            if not real_path.startswith(directory + os.sep):\n                continue\n\n        # test the file for a long shebang, and filter\n        if shebang_too_long(path):\n            filter_shebang(path)\n\n\ndef post_install(spec):\n    \"\"\"This hook edits scripts so that they call /bin/bash\n    $spack_prefix/bin/sbang instead of something longer than the\n    shebang limit.\n    \"\"\"\n    if spec.external:\n        tty.debug('SKIP: shebang filtering [external package]')\n        return\n\n    for directory, _, filenames in os.walk(spec.prefix):\n        filter_shebangs_in_directory(directory, filenames)\n", "path": "lib/spack/spack/hooks/sbang.py"}], "after_files": [{"content": "##############################################################################\n# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.\n# Produced at the Lawrence Livermore National Laboratory.\n#\n# This file is part of Spack.\n# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.\n# LLNL-CODE-647188\n#\n# For details, see https://github.com/llnl/spack\n# Please also see the LICENSE file for our notice and the LGPL.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License (as\n# published by the Free Software Foundation) version 2.1, February 1999.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and\n# conditions of the GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n##############################################################################\nimport os\nimport stat\nimport re\n\nimport llnl.util.tty as tty\n\nimport spack\nimport spack.modules\n\n# Character limit for shebang line.  Using Linux's 127 characters\n# here, as it is the shortest I could find on a modern OS.\nshebang_limit = 127\n\n\ndef shebang_too_long(path):\n    \"\"\"Detects whether a file has a shebang line that is too long.\"\"\"\n    if not os.path.isfile(path):\n        return False\n\n    with open(path, 'rb') as script:\n        bytes = script.read(2)\n        if bytes != b'#!':\n            return False\n\n        line = bytes + script.readline()\n        return len(line) > shebang_limit\n\n\ndef filter_shebang(path):\n    \"\"\"Adds a second shebang line, using sbang, at the beginning of a file.\"\"\"\n    with open(path, 'r') as original_file:\n        original = original_file.read()\n\n    # This line will be prepended to file\n    new_sbang_line = '#!/bin/bash %s/bin/sbang\\n' % spack.spack_root\n\n    # Skip files that are already using sbang.\n    if original.startswith(new_sbang_line):\n        return\n\n    # Use --! instead of #! on second line for lua.\n    if re.search(r'^#!(/[^/]*)*lua\\b', original):\n        original = re.sub(r'^#', '--', original)\n\n    # Change non-writable files to be writable if needed.\n    saved_mode = None\n    if not os.access(path, os.W_OK):\n        st = os.stat(path)\n        saved_mode = st.st_mode\n        os.chmod(path, saved_mode | stat.S_IWRITE)\n\n    with open(path, 'w') as new_file:\n        new_file.write(new_sbang_line)\n        new_file.write(original)\n\n    # Restore original permissions.\n    if saved_mode is not None:\n        os.chmod(path, saved_mode)\n\n    tty.warn(\"Patched overlong shebang in %s\" % path)\n\n\ndef filter_shebangs_in_directory(directory, filenames=None):\n    if filenames is None:\n        filenames = os.listdir(directory)\n    for file in filenames:\n        path = os.path.join(directory, file)\n\n        # only handle files\n        if not os.path.isfile(path):\n            continue\n\n        # only handle links that resolve within THIS package's prefix.\n        if os.path.islink(path):\n            real_path = os.path.realpath(path)\n            if not real_path.startswith(directory + os.sep):\n                continue\n\n        # test the file for a long shebang, and filter\n        if shebang_too_long(path):\n            filter_shebang(path)\n\n\ndef post_install(spec):\n    \"\"\"This hook edits scripts so that they call /bin/bash\n    $spack_prefix/bin/sbang instead of something longer than the\n    shebang limit.\n    \"\"\"\n    if spec.external:\n        tty.debug('SKIP: shebang filtering [external package]')\n        return\n\n    for directory, _, filenames in os.walk(spec.prefix):\n        filter_shebangs_in_directory(directory, filenames)\n", "path": "lib/spack/spack/hooks/sbang.py"}]}