prevent multiple version sigils in the same spec (#17246)

* prevent multiple version sigils in the same spec

* fix packages with malformed versions
This commit is contained in:
Greg Becker
2020-06-25 12:34:09 -05:00
committed by GitHub
parent f936e3a1db
commit 096bd69a94
7 changed files with 51 additions and 16 deletions

View File

@@ -511,8 +511,17 @@ def __init__(self, *args):
raise TypeError(
"__init__ takes 1 or 2 arguments. (%d given)" % nargs)
def _add_version(self, version):
self.versions.add(version)
def _add_versions(self, version_list):
# If it already has a non-trivial version list, this is an error
if self.versions and self.versions != vn.VersionList(':'):
# Note: This may be impossible to reach by the current parser
# Keeping it in case the implementation changes.
raise MultipleVersionError(
'A spec cannot contain multiple version signifiers.'
' Use a version list instead.')
self.versions = vn.VersionList()
for version in version_list:
self.versions.add(version)
def _autospec(self, compiler_spec_like):
if isinstance(compiler_spec_like, CompilerSpec):
@@ -1050,9 +1059,16 @@ def dependents_dict(self, deptype='all'):
#
# Private routines here are called by the parser when building a spec.
#
def _add_version(self, version):
def _add_versions(self, version_list):
"""Called by the parser to add an allowable version."""
self.versions.add(version)
# If it already has a non-trivial version list, this is an error
if self.versions and self.versions != vn.VersionList(':'):
raise MultipleVersionError(
'A spec cannot contain multiple version signifiers.'
' Use a version list instead.')
self.versions = vn.VersionList()
for version in version_list:
self.versions.add(version)
def _add_flag(self, name, value):
"""Called by the parser to add a known flag.
@@ -4157,9 +4173,7 @@ def spec(self, name):
while self.next:
if self.accept(AT):
vlist = self.version_list()
spec.versions = vn.VersionList()
for version in vlist:
spec._add_version(version)
spec._add_versions(vlist)
elif self.accept(ON):
name = self.variant()
@@ -4251,8 +4265,7 @@ def compiler(self):
compiler.versions = vn.VersionList()
if self.accept(AT):
vlist = self.version_list()
for version in vlist:
compiler._add_version(version)
compiler._add_versions(vlist)
else:
compiler.versions = vn.VersionList(':')
return compiler
@@ -4325,6 +4338,10 @@ class DuplicateDependencyError(spack.error.SpecError):
"""Raised when the same dependency occurs in a spec twice."""
class MultipleVersionError(spack.error.SpecError):
"""Raised when version constraints occur in a spec twice."""
class DuplicateCompilerSpecError(spack.error.SpecError):
"""Raised when the same compiler occurs in a spec twice."""

View File

@@ -20,6 +20,7 @@
from spack.spec import DuplicateArchitectureError
from spack.spec import DuplicateDependencyError, DuplicateCompilerSpecError
from spack.spec import SpecFilenameError, NoSuchSpecFileError
from spack.spec import MultipleVersionError
from spack.variant import DuplicateVariantError
@@ -149,6 +150,9 @@ def test_simple_dependence(self):
self.check_parse("openmpi ^hwloc ^libunwind",
"openmpi^hwloc^libunwind")
def test_version_after_compiler(self):
self.check_parse('foo@2.0%bar@1.0', 'foo %bar@1.0 @2.0')
def test_dependencies_with_versions(self):
self.check_parse("openmpi ^hwloc@1.2e6")
self.check_parse("openmpi ^hwloc@1.2e6:")
@@ -432,6 +436,17 @@ def test_duplicate_variant(self):
]
self._check_raises(DuplicateVariantError, duplicates)
def test_multiple_versions(self):
multiples = [
'x@1.2@2.3',
'x@1.2:2.3@1.4',
'x@1.2@2.3:2.4',
'x@1.2@2.3,2.4',
'x@1.2 +foo~bar @2.3',
'x@1.2%y@1.2@2.3:2.4',
]
self._check_raises(MultipleVersionError, multiples)
def test_duplicate_dependency(self):
self._check_raises(DuplicateDependencyError, ["x ^y ^y"])

View File

@@ -782,6 +782,9 @@ def __reversed__(self):
def __len__(self):
return len(self.versions)
def __bool__(self):
return bool(self.versions)
@coerced
def __eq__(self, other):
return other is not None and self.versions == other.versions