Repository: spack/spack

Issue:
Spack aborts no matter what the command is after git merge upstream/develop
Hi all,

I wanted to run with the latest spack code so I updated,  but now I can't do anything with spack.
I tried moving my $HOME/.spack files out of the way, but it didn't make a difference.
Does anyone have any insight into this?

Thanks,
Jim G

git fetch upstream

git merge upstream/develop


jeg@localhost spack]$ which spack
~/spack/bin/spack
[jeg@localhost spack]$ echo $SPACK_ROOT
/home/jeg/spack

[jeg@localhost spack]$ spack install cbtf
Traceback (most recent call last):
  File "/home/jeg/spack/bin/spack", line 99, in <module>
    import spack
  File "/home/jeg/spack/lib/spack/spack/__init__.py", line 74, in <module>
    import spack.repository
  File "/home/jeg/spack/lib/spack/spack/repository.py", line 45, in <module>
    import spack.spec
  File "/home/jeg/spack/lib/spack/spack/spec.py", line 114, in <module>
    import spack.store
  File "/home/jeg/spack/lib/spack/spack/store.py", line 47, in <module>
    import spack.config
  File "/home/jeg/spack/lib/spack/spack/config.py", line 208, in <module>
    _platform = spack.architecture.platform().name
  File "/home/jeg/spack/lib/spack/llnl/util/lang.py", line 187, in __call__
    self.cache[args] = self.func(*args)
  File "/home/jeg/spack/lib/spack/spack/architecture.py", line 530, in platform
    return platform_cls()
  File "/home/jeg/spack/lib/spack/spack/platforms/linux.py", line 21, in __init__
    linux_dist = LinuxDistro()
  File "/home/jeg/spack/lib/spack/spack/operating_systems/linux_distro.py", line 16, in __init__
    from external.distro import linux_distribution
  File "/home/jeg/spack/lib/spack/external/distro.py", line 1049, in <module>
    _distroi = LinuxDistribution()
  File "/home/jeg/spack/lib/spack/external/distro.py", line 595, in __init__
    if include_lsb else {}
  File "/home/jeg/spack/lib/spack/external/distro.py", line 921, in _lsb_release_info
    out, err = out.decode('ascii'), err.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 250: ordinal not in range(128)



[jeg@localhost spack]$ spack uninstall papi
Traceback (most recent call last):
  File "/home/jeg/spack/bin/spack", line 99, in <module>
    import spack
  File "/home/jeg/spack/lib/spack/spack/__init__.py", line 74, in <module>
    import spack.repository
  File "/home/jeg/spack/lib/spack/spack/repository.py", line 45, in <module>
    import spack.spec
  File "/home/jeg/spack/lib/spack/spack/spec.py", line 114, in <module>
    import spack.store
  File "/home/jeg/spack/lib/spack/spack/store.py", line 47, in <module>
    import spack.config
  File "/home/jeg/spack/lib/spack/spack/config.py", line 208, in <module>
    _platform = spack.architecture.platform().name
  File "/home/jeg/spack/lib/spack/llnl/util/lang.py", line 187, in __call__
    self.cache[args] = self.func(*args)
  File "/home/jeg/spack/lib/spack/spack/architecture.py", line 530, in platform
    return platform_cls()
  File "/home/jeg/spack/lib/spack/spack/platforms/linux.py", line 21, in __init__
    linux_dist = LinuxDistro()
  File "/home/jeg/spack/lib/spack/spack/operating_systems/linux_distro.py", line 16, in __init__
    from external.distro import linux_distribution
  File "/home/jeg/spack/lib/spack/external/distro.py", line 1049, in <module>
    _distroi = LinuxDistribution()
  File "/home/jeg/spack/lib/spack/external/distro.py", line 595, in __init__
    if include_lsb else {}
  File "/home/jeg/spack/lib/spack/external/distro.py", line 921, in _lsb_release_info
    out, err = out.decode('ascii'), err.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 250: ordinal not in range(128)


[jeg@localhost spack]$ spack find compilers
Traceback (most recent call last):
  File "/home/jeg/spack/bin/spack", line 99, in <module>
    import spack
  File "/home/jeg/spack/lib/spack/spack/__init__.py", line 74, in <module>
    import spack.repository
  File "/home/jeg/spack/lib/spack/spack/repository.py", line 45, in <module>
    import spack.spec
  File "/home/jeg/spack/lib/spack/spack/spec.py", line 114, in <module>
    import spack.store
  File "/home/jeg/spack/lib/spack/spack/store.py", line 47, in <module>
    import spack.config
  File "/home/jeg/spack/lib/spack/spack/config.py", line 208, in <module>
    _platform = spack.architecture.platform().name
  File "/home/jeg/spack/lib/spack/llnl/util/lang.py", line 187, in __call__
    self.cache[args] = self.func(*args)
  File "/home/jeg/spack/lib/spack/spack/architecture.py", line 530, in platform
    return platform_cls()
  File "/home/jeg/spack/lib/spack/spack/platforms/linux.py", line 21, in __init__
    linux_dist = LinuxDistro()
  File "/home/jeg/spack/lib/spack/spack/operating_systems/linux_distro.py", line 16, in __init__
    from external.distro import linux_distribution
  File "/home/jeg/spack/lib/spack/external/distro.py", line 1049, in <module>
    _distroi = LinuxDistribution()
  File "/home/jeg/spack/lib/spack/external/distro.py", line 595, in __init__
    if include_lsb else {}
  File "/home/jeg/spack/lib/spack/external/distro.py", line 921, in _lsb_release_info
    out, err = out.decode('ascii'), err.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 250: ordinal not in range(128)
[jeg@localhost spack]$ 


spack install openspeedshop
Traceback (most recent call last):
  File "/home/jeg/spack4/spack/bin/spack", line 99, in <module>
    import spack
  File "/home/jeg/spack4/spack/lib/spack/spack/__init__.py", line 74, in <module>
    import spack.repository
  File "/home/jeg/spack4/spack/lib/spack/spack/repository.py", line 45, in <module>
    import spack.spec
  File "/home/jeg/spack4/spack/lib/spack/spack/spec.py", line 114, in <module>
    import spack.store
  File "/home/jeg/spack4/spack/lib/spack/spack/store.py", line 47, in <module>
    import spack.config
  File "/home/jeg/spack4/spack/lib/spack/spack/config.py", line 208, in <module>
    _platform = spack.architecture.platform().name
  File "/home/jeg/spack4/spack/lib/spack/llnl/util/lang.py", line 187, in __call__
    self.cache[args] = self.func(*args)
  File "/home/jeg/spack4/spack/lib/spack/spack/architecture.py", line 530, in platform
    return platform_cls()
  File "/home/jeg/spack4/spack/lib/spack/spack/platforms/linux.py", line 21, in __init__
    linux_dist = LinuxDistro()
  File "/home/jeg/spack4/spack/lib/spack/spack/operating_systems/linux_distro.py", line 16, in __init__
    from external.distro import linux_distribution
  File "/home/jeg/spack4/spack/lib/spack/external/distro.py", line 1049, in <module>
    _distroi = LinuxDistribution()
  File "/home/jeg/spack4/spack/lib/spack/external/distro.py", line 595, in __init__
    if include_lsb else {}
  File "/home/jeg/spack4/spack/lib/spack/external/distro.py", line 921, in _lsb_release_info
    out, err = out.decode('ascii'), err.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 250: ordinal not in range(128)
[jeg@localhost packages]$ 



Discussion:
What is the output of the following command?

```
$ lsb_release -a
```

[jeg@localhost spack]$ lsb_release -a
LSB Version:    :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
Distributor ID: Fedora
Description:    Fedora release 19 (Schrödinger’s Cat)
Release:    19
Codename:   Schrödinger’sCat
[jeg@localhost spack]$ 

Ha, it must be because of `Schrödinger’sCat`. We're using the distro Python module for linux distribution detection now. I'll file an issue with the distro developers. Hopefully they can put in a quick fix.

Issue filed at https://github.com/nir0s/distro/issues/151

Hi Adam,
Thanks for looking at this!
Jim G

Are you sure Spack is running here with Python2?  Just a guess, and probably not the cause of the problem...
The issue is that we are using an out-of-date version of the `distro` package. See https://github.com/nir0s/distro/issues/151 for details. I'll update the package and submit a PR shortly.

Resolving patch:
diff --git a/lib/spack/external/distro.py b/lib/spack/external/distro.py
--- a/lib/spack/external/distro.py
+++ b/lib/spack/external/distro.py
@@ -31,14 +31,16 @@
 import os
 import re
 import sys
+import json
 import shlex
+import logging
+import argparse
 import subprocess
 
 
 if not sys.platform.startswith('linux'):
     raise ImportError('Unsupported platform: {0}'.format(sys.platform))
 
-
 _UNIXCONFDIR = '/etc'
 _OS_RELEASE_BASENAME = 'os-release'
 
@@ -75,7 +77,6 @@
     'redhat': 'rhel',  # RHEL 6.x, 7.x
 }
 
-
 # Pattern for content of distro release file (reversed)
 _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
     r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)')
@@ -119,7 +120,7 @@ def linux_distribution(full_distribution_name=True):
     method normalizes the distro ID string to a reliable machine-readable value
     for a number of popular Linux distributions.
     """
-    return _distroi.linux_distribution(full_distribution_name)
+    return _distro.linux_distribution(full_distribution_name)
 
 
 def id():
@@ -194,7 +195,7 @@ def id():
       command, with ID values that differ from what was previously determined
       from the distro release file name.
     """
-    return _distroi.id()
+    return _distro.id()
 
 
 def name(pretty=False):
@@ -233,7 +234,7 @@ def name(pretty=False):
         with the value of the pretty version ("<version_id>" and "<codename>"
         fields) of the distro release file, if available.
     """
-    return _distroi.name(pretty)
+    return _distro.name(pretty)
 
 
 def version(pretty=False, best=False):
@@ -277,7 +278,7 @@ def version(pretty=False, best=False):
       the lsb_release command, if it follows the format of the distro release
       files.
     """
-    return _distroi.version(pretty, best)
+    return _distro.version(pretty, best)
 
 
 def version_parts(best=False):
@@ -294,7 +295,7 @@ def version_parts(best=False):
     For a description of the *best* parameter, see the :func:`distro.version`
     method.
     """
-    return _distroi.version_parts(best)
+    return _distro.version_parts(best)
 
 
 def major_version(best=False):
@@ -307,7 +308,7 @@ def major_version(best=False):
     For a description of the *best* parameter, see the :func:`distro.version`
     method.
     """
-    return _distroi.major_version(best)
+    return _distro.major_version(best)
 
 
 def minor_version(best=False):
@@ -320,7 +321,7 @@ def minor_version(best=False):
     For a description of the *best* parameter, see the :func:`distro.version`
     method.
     """
-    return _distroi.minor_version(best)
+    return _distro.minor_version(best)
 
 
 def build_number(best=False):
@@ -333,7 +334,7 @@ def build_number(best=False):
     For a description of the *best* parameter, see the :func:`distro.version`
     method.
     """
-    return _distroi.build_number(best)
+    return _distro.build_number(best)
 
 
 def like():
@@ -350,7 +351,7 @@ def like():
     `os-release man page
     <http://www.freedesktop.org/software/systemd/man/os-release.html>`_.
     """
-    return _distroi.like()
+    return _distro.like()
 
 
 def codename():
@@ -374,7 +375,7 @@ def codename():
 
     * the value of the "<codename>" field of the distro release file.
     """
-    return _distroi.codename()
+    return _distro.codename()
 
 
 def info(pretty=False, best=False):
@@ -418,7 +419,7 @@ def info(pretty=False, best=False):
     For a description of the *pretty* and *best* parameters, see the
     :func:`distro.version` method.
     """
-    return _distroi.info(pretty, best)
+    return _distro.info(pretty, best)
 
 
 def os_release_info():
@@ -428,7 +429,7 @@ def os_release_info():
 
     See `os-release file`_ for details about these information items.
     """
-    return _distroi.os_release_info()
+    return _distro.os_release_info()
 
 
 def lsb_release_info():
@@ -439,7 +440,7 @@ def lsb_release_info():
     See `lsb_release command output`_ for details about these information
     items.
     """
-    return _distroi.lsb_release_info()
+    return _distro.lsb_release_info()
 
 
 def distro_release_info():
@@ -449,7 +450,7 @@ def distro_release_info():
 
     See `distro release file`_ for details about these information items.
     """
-    return _distroi.distro_release_info()
+    return _distro.distro_release_info()
 
 
 def os_release_attr(attribute):
@@ -468,7 +469,7 @@ def os_release_attr(attribute):
 
     See `os-release file`_ for details about these information items.
     """
-    return _distroi.os_release_attr(attribute)
+    return _distro.os_release_attr(attribute)
 
 
 def lsb_release_attr(attribute):
@@ -488,7 +489,7 @@ def lsb_release_attr(attribute):
     See `lsb_release command output`_ for details about these information
     items.
     """
-    return _distroi.lsb_release_attr(attribute)
+    return _distro.lsb_release_attr(attribute)
 
 
 def distro_release_attr(attribute):
@@ -507,7 +508,7 @@ def distro_release_attr(attribute):
 
     See `distro release file`_ for details about these information items.
     """
-    return _distroi.distro_release_attr(attribute)
+    return _distro.distro_release_attr(attribute)
 
 
 class LinuxDistribution(object):
@@ -590,12 +591,14 @@ def __init__(self,
         self.os_release_file = os_release_file or \
             os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME)
         self.distro_release_file = distro_release_file or ''  # updated later
-        self._os_release_info = self._os_release_info()
-        self._lsb_release_info = self._lsb_release_info() \
+        self._os_release_info = self._get_os_release_info()
+        self._lsb_release_info = self._get_lsb_release_info() \
             if include_lsb else {}
-        self._distro_release_info = self._distro_release_info()
+        self._distro_release_info = self._get_distro_release_info()
 
     def __repr__(self):
+        """Return repr of all info
+        """
         return \
             "LinuxDistribution(" \
             "os_release_file={0!r}, " \
@@ -624,25 +627,25 @@ def linux_distribution(self, full_distribution_name=True):
         )
 
     def id(self):
-        """
-        Return the distro ID of the Linux distribution, as a string.
+        """Return the distro ID of the Linux distribution, as a string.
 
         For details, see :func:`distro.id`.
         """
+        def normalize(distro_id, table):
+            distro_id = distro_id.lower().replace(' ', '_')
+            return table.get(distro_id, distro_id)
+
         distro_id = self.os_release_attr('id')
         if distro_id:
-            distro_id = distro_id.lower().replace(' ', '_')
-            return NORMALIZED_OS_ID.get(distro_id, distro_id)
+            return normalize(distro_id, NORMALIZED_OS_ID)
 
         distro_id = self.lsb_release_attr('distributor_id')
         if distro_id:
-            distro_id = distro_id.lower().replace(' ', '_')
-            return NORMALIZED_LSB_ID.get(distro_id, distro_id)
+            return normalize(distro_id, NORMALIZED_LSB_ID)
 
         distro_id = self.distro_release_attr('id')
         if distro_id:
-            distro_id = distro_id.lower().replace(' ', '_')
-            return NORMALIZED_DISTRO_ID.get(distro_id, distro_id)
+            return normalize(distro_id, NORMALIZED_DISTRO_ID)
 
         return ''
 
@@ -707,10 +710,10 @@ def version_parts(self, best=False):
         """
         version_str = self.version(best=best)
         if version_str:
-            g = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?')
-            m = g.match(version_str)
-            if m:
-                major, minor, build_number = m.groups()
+            version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?')
+            matches = version_regex.match(version_str)
+            if matches:
+                major, minor, build_number = matches.groups()
                 return major, minor or '', build_number or ''
         return '', '', ''
 
@@ -832,7 +835,7 @@ def distro_release_attr(self, attribute):
         """
         return self._distro_release_info.get(attribute, '')
 
-    def _os_release_info(self):
+    def _get_os_release_info(self):
         """
         Get the information items from the specified os-release file.
 
@@ -840,8 +843,8 @@ def _os_release_info(self):
             A dictionary containing all information items.
         """
         if os.path.isfile(self.os_release_file):
-            with open(self.os_release_file, 'r') as f:
-                return self._parse_os_release_content(f)
+            with open(self.os_release_file) as release_file:
+                return self._parse_os_release_content(release_file)
         return {}
 
     @staticmethod
@@ -904,7 +907,7 @@ def _parse_os_release_content(lines):
                 pass
         return props
 
-    def _lsb_release_info(self):
+    def _get_lsb_release_info(self):
         """
         Get the information items from the lsb_release command output.
 
@@ -912,26 +915,26 @@ def _lsb_release_info(self):
             A dictionary containing all information items.
         """
         cmd = 'lsb_release -a'
-        p = subprocess.Popen(
+        process = subprocess.Popen(
             cmd,
             shell=True,
             stdout=subprocess.PIPE,
             stderr=subprocess.PIPE)
-        out, err = p.communicate()
-        out, err = out.decode('ascii'), err.decode('ascii')
-        rc = p.returncode
-        if rc == 0:
-            content = out.splitlines()
+        stdout, stderr = process.communicate()
+        stdout, stderr = stdout.decode('utf-8'), stderr.decode('utf-8')
+        code = process.returncode
+        if code == 0:
+            content = stdout.splitlines()
             return self._parse_lsb_release_content(content)
-        elif rc == 127:  # Command not found
+        elif code == 127:  # Command not found
             return {}
         else:
             if sys.version_info[:2] >= (3, 5):
-                raise subprocess.CalledProcessError(rc, cmd, out, err)
+                raise subprocess.CalledProcessError(code, cmd, stdout, stderr)
             elif sys.version_info[:2] >= (2, 7):
-                raise subprocess.CalledProcessError(rc, cmd, out)
+                raise subprocess.CalledProcessError(code, cmd, stdout)
             elif sys.version_info[:2] == (2, 6):
-                raise subprocess.CalledProcessError(rc, cmd)
+                raise subprocess.CalledProcessError(code, cmd)
 
     @staticmethod
     def _parse_lsb_release_content(lines):
@@ -949,8 +952,7 @@ def _parse_lsb_release_content(lines):
         """
         props = {}
         for line in lines:
-            if isinstance(line, bytes):
-                line = line.decode('utf-8')
+            line = line.decode('utf-8') if isinstance(line, bytes) else line
             kv = line.strip('\n').split(':', 1)
             if len(kv) != 2:
                 # Ignore lines without colon.
@@ -959,7 +961,7 @@ def _parse_lsb_release_content(lines):
             props.update({k.replace(' ', '_').lower(): v.strip()})
         return props
 
-    def _distro_release_info(self):
+    def _get_distro_release_info(self):
         """
         Get the information items from the specified distro release file.
 
@@ -1012,7 +1014,7 @@ def _parse_distro_release_file(self, filepath):
             A dictionary containing all information items.
         """
         if os.path.isfile(filepath):
-            with open(filepath, 'r') as fp:
+            with open(filepath) as fp:
                 # Only parse the first line. For instance, on SLES there
                 # are multiple lines. We don't want them...
                 return self._parse_distro_release_content(fp.readline())
@@ -1032,18 +1034,48 @@ def _parse_distro_release_content(line):
         """
         if isinstance(line, bytes):
             line = line.decode('utf-8')
-        m = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
+        matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
             line.strip()[::-1])
         distro_info = {}
-        if m:
-            distro_info['name'] = m.group(3)[::-1]   # regexp ensures non-None
-            if m.group(2):
-                distro_info['version_id'] = m.group(2)[::-1]
-            if m.group(1):
-                distro_info['codename'] = m.group(1)[::-1]
+        if matches:
+            # regexp ensures non-None
+            distro_info['name'] = matches.group(3)[::-1]
+            if matches.group(2):
+                distro_info['version_id'] = matches.group(2)[::-1]
+            if matches.group(1):
+                distro_info['codename'] = matches.group(1)[::-1]
         elif line:
             distro_info['name'] = line.strip()
         return distro_info
 
 
-_distroi = LinuxDistribution()
+_distro = LinuxDistribution()
+
+
+def main():
+    logger = logging.getLogger(__name__)
+    logger.setLevel(logging.DEBUG)
+    logger.addHandler(logging.StreamHandler(sys.stdout))
+
+    parser = argparse.ArgumentParser(description="Linux distro info tool")
+    parser.add_argument(
+        '--json',
+        '-j',
+        help="Output in machine readable format",
+        action="store_true")
+    args = parser.parse_args()
+
+    if args.json:
+        logger.info(json.dumps(info(), indent=4, sort_keys=True))
+    else:
+        logger.info('Name: %s', name(pretty=True))
+        distribution_version = version(pretty=True)
+        if distribution_version:
+            logger.info('Version: %s', distribution_version)
+        distribution_codename = codename()
+        if distribution_codename:
+            logger.info('Codename: %s', distribution_codename)
+
+
+if __name__ == '__main__':
+    main()


Test patch: