in lib/ramble/spack/package.py [0:0]
def __init__(cls, name, bases, attr_dict):
if hasattr(cls, 'executables') and hasattr(cls, 'libraries'):
msg = "a package can have either an 'executables' or 'libraries' attribute"
msg += " [package '{0.name}' defines both]"
raise spack.error.SpackError(msg.format(cls))
# On windows, extend the list of regular expressions to look for
# filenames ending with ".exe"
# (in some cases these regular expressions include "$" to avoid
# pulling in filenames with unexpected suffixes, but this allows
# for example detecting "foo.exe" when the package writer specified
# that "foo" was a possible executable.
# If a package has the executables or libraries attribute then it's
# assumed to be detectable
if hasattr(cls, 'executables') or hasattr(cls, 'libraries'):
@property
def platform_executables(self):
def to_windows_exe(exe):
if exe.endswith('$'):
exe = exe.replace('$', '%s$' % spack.util.path.win_exe_ext())
else:
exe += spack.util.path.win_exe_ext()
return exe
plat_exe = []
if hasattr(self, 'executables'):
for exe in self.executables:
if sys.platform == 'win32':
exe = to_windows_exe(exe)
plat_exe.append(exe)
return plat_exe
@classmethod
def determine_spec_details(cls, prefix, objs_in_prefix):
"""Allow ``spack external find ...`` to locate installations.
Args:
prefix (str): the directory containing the executables
or libraries
objs_in_prefix (set): the executables or libraries that
match the regex
Returns:
The list of detected specs for this package
"""
objs_by_version = collections.defaultdict(list)
# The default filter function is the identity function for the
# list of executables
filter_fn = getattr(cls, 'filter_detected_exes',
lambda x, exes: exes)
objs_in_prefix = filter_fn(prefix, objs_in_prefix)
for obj in objs_in_prefix:
try:
version_str = cls.determine_version(obj)
if version_str:
objs_by_version[version_str].append(obj)
except Exception as e:
msg = ('An error occurred when trying to detect '
'the version of "{0}" [{1}]')
tty.debug(msg.format(obj, str(e)))
specs = []
for version_str, objs in objs_by_version.items():
variants = cls.determine_variants(objs, version_str)
# Normalize output to list
if not isinstance(variants, list):
variants = [variants]
for variant in variants:
if isinstance(variant, str):
variant = (variant, {})
variant_str, extra_attributes = variant
spec_str = '{0}@{1} {2}'.format(
cls.name, version_str, variant_str
)
# Pop a few reserved keys from extra attributes, since
# they have a different semantics
external_path = extra_attributes.pop('prefix', None)
external_modules = extra_attributes.pop(
'modules', None
)
try:
spec = spack.spec.Spec(
spec_str,
external_path=external_path,
external_modules=external_modules
)
except Exception as e:
msg = 'Parsing failed [spec_str="{0}", error={1}]'
tty.debug(msg.format(spec_str, str(e)))
else:
specs.append(spack.spec.Spec.from_detection(
spec, extra_attributes=extra_attributes
))
return sorted(specs)
@classmethod
def determine_variants(cls, objs, version_str):
return ''
# Register the class as a detectable package
detectable_packages[cls.namespace].append(cls.name)
# Attach function implementations to the detectable class
default = False
if not hasattr(cls, 'determine_spec_details'):
default = True
cls.determine_spec_details = determine_spec_details
if default and not hasattr(cls, 'determine_version'):
msg = ('the package "{0}" in the "{1}" repo needs to define'
' the "determine_version" method to be detectable')
NotImplementedError(msg.format(cls.name, cls.namespace))
if default and not hasattr(cls, 'determine_variants'):
cls.determine_variants = determine_variants
# This function should not be overridden by subclasses,
# as it is not designed for bespoke pkg detection but rather
# on a per-platform basis
if 'platform_executables' in cls.__dict__.keys():
raise PackageError("Packages should not override platform_executables")
cls.platform_executables = platform_executables
super(DetectablePackageMeta, cls).__init__(name, bases, attr_dict)