summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-08-26 18:55:55 +0200
committerGitHub <noreply@github.com>2024-08-26 18:55:55 +0200
commit497e19f0e351b38420da3867fabe6e3361837d04 (patch)
tree0efef679c13a1c6908a1ac6264b5484ae86f6b03 /lib
parentcd6ee963985bf9791f68553dcca9cac2a3a6427a (diff)
downloadspack-497e19f0e351b38420da3867fabe6e3361837d04.tar.gz
spack-497e19f0e351b38420da3867fabe6e3361837d04.tar.bz2
spack-497e19f0e351b38420da3867fabe6e3361837d04.tar.xz
spack-497e19f0e351b38420da3867fabe6e3361837d04.zip
distro.py: avoid excessive stat calls (#46030)
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/external/_vendoring/distro/distro.py24
-rw-r--r--lib/spack/external/patches/distro.patch45
2 files changed, 58 insertions, 11 deletions
diff --git a/lib/spack/external/_vendoring/distro/distro.py b/lib/spack/external/_vendoring/distro/distro.py
index 89e1868047..50c3b18d4d 100644
--- a/lib/spack/external/_vendoring/distro/distro.py
+++ b/lib/spack/external/_vendoring/distro/distro.py
@@ -1265,27 +1265,29 @@ class LinuxDistribution:
match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
else:
try:
- basenames = [
- basename
- for basename in os.listdir(self.etc_dir)
- if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES
- and os.path.isfile(os.path.join(self.etc_dir, basename))
- ]
+ with os.scandir(self.etc_dir) as it:
+ etc_files = [
+ p.path for p in it
+ if p.is_file() and p.name not in _DISTRO_RELEASE_IGNORE_BASENAMES
+ ]
# We sort for repeatability in cases where there are multiple
# distro specific files; e.g. CentOS, Oracle, Enterprise all
# containing `redhat-release` on top of their own.
- basenames.sort()
+ etc_files.sort()
except OSError:
# This may occur when /etc is not readable but we can't be
# sure about the *-release files. Check common entries of
# /etc for information. If they turn out to not be there the
# error is handled in `_parse_distro_release_file()`.
- basenames = _DISTRO_RELEASE_BASENAMES
- for basename in basenames:
- match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
+ etc_files = [
+ os.path.join(self.etc_dir, basename)
+ for basename in _DISTRO_RELEASE_BASENAMES
+ ]
+
+ for filepath in etc_files:
+ match = _DISTRO_RELEASE_BASENAME_PATTERN.match(os.path.basename(filepath))
if match is None:
continue
- filepath = os.path.join(self.etc_dir, basename)
distro_info = self._parse_distro_release_file(filepath)
# The name is always present if the pattern matches.
if "name" not in distro_info:
diff --git a/lib/spack/external/patches/distro.patch b/lib/spack/external/patches/distro.patch
new file mode 100644
index 0000000000..067df63d45
--- /dev/null
+++ b/lib/spack/external/patches/distro.patch
@@ -0,0 +1,45 @@
+diff --git a/lib/spack/external/_vendoring/distro/distro.py b/lib/spack/external/_vendoring/distro/distro.py
+index 89e1868047..50c3b18d4d 100644
+--- a/lib/spack/external/_vendoring/distro/distro.py
++++ b/lib/spack/external/_vendoring/distro/distro.py
+@@ -1265,27 +1265,29 @@ def _distro_release_info(self) -> Dict[str, str]:
+ match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
+ else:
+ try:
+- basenames = [
+- basename
+- for basename in os.listdir(self.etc_dir)
+- if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES
+- and os.path.isfile(os.path.join(self.etc_dir, basename))
+- ]
++ with os.scandir(self.etc_dir) as it:
++ etc_files = [
++ p.path for p in it
++ if p.is_file() and p.name not in _DISTRO_RELEASE_IGNORE_BASENAMES
++ ]
+ # We sort for repeatability in cases where there are multiple
+ # distro specific files; e.g. CentOS, Oracle, Enterprise all
+ # containing `redhat-release` on top of their own.
+- basenames.sort()
++ etc_files.sort()
+ except OSError:
+ # This may occur when /etc is not readable but we can't be
+ # sure about the *-release files. Check common entries of
+ # /etc for information. If they turn out to not be there the
+ # error is handled in `_parse_distro_release_file()`.
+- basenames = _DISTRO_RELEASE_BASENAMES
+- for basename in basenames:
+- match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
++ etc_files = [
++ os.path.join(self.etc_dir, basename)
++ for basename in _DISTRO_RELEASE_BASENAMES
++ ]
++
++ for filepath in etc_files:
++ match = _DISTRO_RELEASE_BASENAME_PATTERN.match(os.path.basename(filepath))
+ if match is None:
+ continue
+- filepath = os.path.join(self.etc_dir, basename)
+ distro_info = self._parse_distro_release_file(filepath)
+ # The name is always present if the pattern matches.
+ if "name" not in distro_info: