Skip to content
Snippets Groups Projects
Commit 138307dd authored by Todd Gamblin's avatar Todd Gamblin
Browse files

Merge pull request #955 from trws/lua-rework

complete lua rework
parents 6384264a 97804279
Branches
Tags
No related merge requests found
...@@ -45,11 +45,8 @@ class OpenMpi(Package): ...@@ -45,11 +45,8 @@ class OpenMpi(Package):
* ``resource`` * ``resource``
""" """
__all__ = ['depends_on', 'extends', 'provides', 'patch', 'version',
'variant', 'resource']
import re import re
import inspect
import os.path import os.path
import functools import functools
...@@ -67,6 +64,9 @@ class OpenMpi(Package): ...@@ -67,6 +64,9 @@ class OpenMpi(Package):
from spack.resource import Resource from spack.resource import Resource
from spack.fetch_strategy import from_kwargs from spack.fetch_strategy import from_kwargs
__all__ = ['depends_on', 'extends', 'provides', 'patch', 'version', 'variant',
'resource']
# #
# This is a list of all directives, built up as they are defined in # This is a list of all directives, built up as they are defined in
# this file. # this file.
...@@ -122,15 +122,14 @@ class Foo(Package): ...@@ -122,15 +122,14 @@ class Foo(Package):
def __init__(self, dicts=None): def __init__(self, dicts=None):
if isinstance(dicts, basestring): if isinstance(dicts, basestring):
dicts = (dicts,) dicts = (dicts, )
elif type(dicts) not in (list, tuple): elif type(dicts) not in (list, tuple):
raise TypeError( raise TypeError(
"dicts arg must be list, tuple, or string. Found %s" "dicts arg must be list, tuple, or string. Found %s" %
% type(dicts)) type(dicts))
self.dicts = dicts self.dicts = dicts
def ensure_dicts(self, pkg): def ensure_dicts(self, pkg):
"""Ensure that a package has the dicts required by this directive.""" """Ensure that a package has the dicts required by this directive."""
for d in self.dicts: for d in self.dicts:
...@@ -142,7 +141,6 @@ def ensure_dicts(self, pkg): ...@@ -142,7 +141,6 @@ def ensure_dicts(self, pkg):
raise spack.error.SpackError( raise spack.error.SpackError(
"Package %s has non-dict %s attribute!" % (pkg, d)) "Package %s has non-dict %s attribute!" % (pkg, d))
def __call__(self, directive_function): def __call__(self, directive_function):
directives[directive_function.__name__] = self directives[directive_function.__name__] = self
...@@ -259,11 +257,12 @@ def variant(pkg, name, default=False, description=""): ...@@ -259,11 +257,12 @@ def variant(pkg, name, default=False, description=""):
"""Define a variant for the package. Packager can specify a default """Define a variant for the package. Packager can specify a default
value (on or off) as well as a text description.""" value (on or off) as well as a text description."""
default = bool(default) default = bool(default)
description = str(description).strip() description = str(description).strip()
if not re.match(spack.spec.identifier_re, name): if not re.match(spack.spec.identifier_re, name):
raise DirectiveError("Invalid variant name in %s: '%s'" % (pkg.name, name)) raise DirectiveError("Invalid variant name in %s: '%s'" %
(pkg.name, name))
pkg.variants[name] = Variant(default, description) pkg.variants[name] = Variant(default, description)
...@@ -271,31 +270,37 @@ def variant(pkg, name, default=False, description=""): ...@@ -271,31 +270,37 @@ def variant(pkg, name, default=False, description=""):
@directive('resources') @directive('resources')
def resource(pkg, **kwargs): def resource(pkg, **kwargs):
""" """
Define an external resource to be fetched and staged when building the package. Based on the keywords present in the Define an external resource to be fetched and staged when building the
dictionary the appropriate FetchStrategy will be used for the resource. Resources are fetched and staged in their package. Based on the keywords present in the dictionary the appropriate
own folder inside spack stage area, and then linked into the stage area of the package that needs them. FetchStrategy will be used for the resource. Resources are fetched and
staged in their own folder inside spack stage area, and then linked into
the stage area of the package that needs them.
List of recognized keywords: List of recognized keywords:
* 'when' : (optional) represents the condition upon which the resource is needed * 'when' : (optional) represents the condition upon which the resource is
* 'destination' : (optional) path where to link the resource. This path must be relative to the main package stage needed
area. * 'destination' : (optional) path where to link the resource. This path
* 'placement' : (optional) gives the possibility to fine tune how the resource is linked into the main package stage must be relative to the main package stage area.
area. * 'placement' : (optional) gives the possibility to fine tune how the
resource is linked into the main package stage area.
""" """
when = kwargs.get('when', pkg.name) when = kwargs.get('when', pkg.name)
destination = kwargs.get('destination', "") destination = kwargs.get('destination', "")
placement = kwargs.get('placement', None) placement = kwargs.get('placement', None)
# Check if the path is relative # Check if the path is relative
if os.path.isabs(destination): if os.path.isabs(destination):
message = "The destination keyword of a resource directive can't be an absolute path.\n" message = "The destination keyword of a resource directive can't be"
" an absolute path.\n"
message += "\tdestination : '{dest}\n'".format(dest=destination) message += "\tdestination : '{dest}\n'".format(dest=destination)
raise RuntimeError(message) raise RuntimeError(message)
# Check if the path falls within the main package stage area # Check if the path falls within the main package stage area
test_path = 'stage_folder_root/' test_path = 'stage_folder_root'
normalized_destination = os.path.normpath(join_path(test_path, destination)) # Normalized absolute path normalized_destination = os.path.normpath(join_path(test_path, destination)
) # Normalized absolute path
if test_path not in normalized_destination: if test_path not in normalized_destination:
message = "The destination folder of a resource must fall within the main package stage directory.\n" message = "The destination folder of a resource must fall within the"
" main package stage directory.\n"
message += "\tdestination : '{dest}'\n".format(dest=destination) message += "\tdestination : '{dest}'\n".format(dest=destination)
raise RuntimeError(message) raise RuntimeError(message)
when_spec = parse_anonymous_spec(when, pkg.name) when_spec = parse_anonymous_spec(when, pkg.name)
...@@ -307,6 +312,7 @@ def resource(pkg, **kwargs): ...@@ -307,6 +312,7 @@ def resource(pkg, **kwargs):
class DirectiveError(spack.error.SpackError): class DirectiveError(spack.error.SpackError):
"""This is raised when something is wrong with a package directive.""" """This is raised when something is wrong with a package directive."""
def __init__(self, directive, message): def __init__(self, directive, message):
super(DirectiveError, self).__init__(message) super(DirectiveError, self).__init__(message)
self.directive = directive self.directive = directive
...@@ -314,6 +320,7 @@ def __init__(self, directive, message): ...@@ -314,6 +320,7 @@ def __init__(self, directive, message):
class CircularReferenceError(DirectiveError): class CircularReferenceError(DirectiveError):
"""This is raised when something depends on itself.""" """This is raised when something depends on itself."""
def __init__(self, directive, package): def __init__(self, directive, package):
super(CircularReferenceError, self).__init__( super(CircularReferenceError, self).__init__(
directive, directive,
......
...@@ -39,7 +39,8 @@ class NameValueModifier(object): ...@@ -39,7 +39,8 @@ class NameValueModifier(object):
def __init__(self, name, value, **kwargs): def __init__(self, name, value, **kwargs):
self.name = name self.name = name
self.value = value self.value = value
self.args = {'name': name, 'value': value} self.separator = kwargs.get('separator', ':')
self.args = {'name': name, 'value': value, 'delim': self.separator}
self.args.update(kwargs) self.args.update(kwargs)
...@@ -56,34 +57,36 @@ def execute(self): ...@@ -56,34 +57,36 @@ def execute(self):
class SetPath(NameValueModifier): class SetPath(NameValueModifier):
def execute(self): def execute(self):
string_path = concatenate_paths(self.value) string_path = concatenate_paths(self.value, separator=self.separator)
os.environ[self.name] = string_path os.environ[self.name] = string_path
class AppendPath(NameValueModifier): class AppendPath(NameValueModifier):
def execute(self): def execute(self):
environment_value = os.environ.get(self.name, '') environment_value = os.environ.get(self.name, '')
directories = environment_value.split(':') if environment_value else [] directories = environment_value.split(
self.separator) if environment_value else []
directories.append(os.path.normpath(self.value)) directories.append(os.path.normpath(self.value))
os.environ[self.name] = ':'.join(directories) os.environ[self.name] = self.separator.join(directories)
class PrependPath(NameValueModifier): class PrependPath(NameValueModifier):
def execute(self): def execute(self):
environment_value = os.environ.get(self.name, '') environment_value = os.environ.get(self.name, '')
directories = environment_value.split(':') if environment_value else [] directories = environment_value.split(
self.separator) if environment_value else []
directories = [os.path.normpath(self.value)] + directories directories = [os.path.normpath(self.value)] + directories
os.environ[self.name] = ':'.join(directories) os.environ[self.name] = self.separator.join(directories)
class RemovePath(NameValueModifier): class RemovePath(NameValueModifier):
def execute(self): def execute(self):
environment_value = os.environ.get(self.name, '') environment_value = os.environ.get(self.name, '')
directories = environment_value.split(':') if environment_value else [] directories = environment_value.split(
directories = [os.path.normpath(x) self.separator) if environment_value else []
for x in directories directories = [os.path.normpath(x) for x in directories
if x != os.path.normpath(self.value)] if x != os.path.normpath(self.value)]
os.environ[self.name] = ':'.join(directories) os.environ[self.name] = self.separator.join(directories)
class EnvironmentModifications(object): class EnvironmentModifications(object):
...@@ -238,17 +241,19 @@ def apply_modifications(self): ...@@ -238,17 +241,19 @@ def apply_modifications(self):
x.execute() x.execute()
def concatenate_paths(paths): def concatenate_paths(paths, separator=':'):
""" """
Concatenates an iterable of paths into a string of column separated paths Concatenates an iterable of paths into a string of paths separated by
separator, defaulting to colon
Args: Args:
paths: iterable of paths paths: iterable of paths
separator: the separator to use, default ':'
Returns: Returns:
string string
""" """
return ':'.join(str(item) for item in paths) return separator.join(str(item) for item in paths)
def set_or_unset_not_first(variable, changes, errstream): def set_or_unset_not_first(variable, changes, errstream):
...@@ -256,16 +261,13 @@ def set_or_unset_not_first(variable, changes, errstream): ...@@ -256,16 +261,13 @@ def set_or_unset_not_first(variable, changes, errstream):
Check if we are going to set or unset something after other modifications Check if we are going to set or unset something after other modifications
have already been requested have already been requested
""" """
indexes = [ii indexes = [ii for ii, item in enumerate(changes)
for ii, item in enumerate(changes)
if ii != 0 and type(item) in [SetEnv, UnsetEnv]] if ii != 0 and type(item) in [SetEnv, UnsetEnv]]
if indexes: if indexes:
good = '\t \t{context} at {filename}:{lineno}' good = '\t \t{context} at {filename}:{lineno}'
nogood = '\t--->\t{context} at {filename}:{lineno}' nogood = '\t--->\t{context} at {filename}:{lineno}'
message = 'Suspicious requests to set or unset the variable \'{var}\' found' # NOQA: ignore=E501 message = 'Suspicious requests to set or unset the variable \'{var}\' found' # NOQA: ignore=E501
errstream( errstream(message.format(var=variable))
message.format(
var=variable))
for ii, item in enumerate(changes): for ii, item in enumerate(changes):
print_format = nogood if ii in indexes else good print_format = nogood if ii in indexes else good
errstream(print_format.format(**item.args)) errstream(print_format.format(**item.args))
......
...@@ -485,9 +485,9 @@ class TclModule(EnvModule): ...@@ -485,9 +485,9 @@ class TclModule(EnvModule):
path = join_path(spack.share_path, "modules") path = join_path(spack.share_path, "modules")
environment_modifications_formats = { environment_modifications_formats = {
PrependPath: 'prepend-path {name} \"{value}\"\n', PrependPath: 'prepend-path --delim "{delim}" {name} \"{value}\"\n',
AppendPath: 'append-path {name} \"{value}\"\n', AppendPath: 'append-path --delim "{delim}" {name} \"{value}\"\n',
RemovePath: 'remove-path {name} \"{value}\"\n', RemovePath: 'remove-path --delim "{delim}" {name} \"{value}\"\n',
SetEnv: 'setenv {name} \"{value}\"\n', SetEnv: 'setenv {name} \"{value}\"\n',
UnsetEnv: 'unsetenv {name}\n' UnsetEnv: 'unsetenv {name}\n'
} }
......
from spack import *
import glob
class LuaLuaposix(Package):
"""Lua posix bindings, including ncurses"""
homepage = "https://github.com/luaposix/luaposix/"
url = "https://github.com/luaposix/luaposix/archive/release-v33.4.0.tar.gz"
version('33.4.0', 'b36ff049095f28752caeb0b46144516c')
extends("lua")
def install(self, spec, prefix):
rockspec = glob.glob('luaposix-*.rockspec')
luarocks('--tree=' + prefix, 'install', rockspec[0])
...@@ -25,10 +25,11 @@ ...@@ -25,10 +25,11 @@
from spack import * from spack import *
import os import os
class Lua(Package): class Lua(Package):
""" The Lua programming language interpreter and library """ """ The Lua programming language interpreter and library """
homepage = "http://www.lua.org" homepage = "http://www.lua.org"
url = "http://www.lua.org/ftp/lua-5.1.5.tar.gz" url = "http://www.lua.org/ftp/lua-5.1.5.tar.gz"
version('5.3.2', '33278c2ab5ee3c1a875be8d55c1ca2a1') version('5.3.2', '33278c2ab5ee3c1a875be8d55c1ca2a1')
version('5.3.1', '797adacada8d85761c079390ff1d9961') version('5.3.1', '797adacada8d85761c079390ff1d9961')
...@@ -42,17 +43,115 @@ class Lua(Package): ...@@ -42,17 +43,115 @@ class Lua(Package):
version('5.1.4', 'd0870f2de55d59c1c8419f36e8fac150') version('5.1.4', 'd0870f2de55d59c1c8419f36e8fac150')
version('5.1.3', 'a70a8dfaa150e047866dc01a46272599') version('5.1.3', 'a70a8dfaa150e047866dc01a46272599')
extendable = True
depends_on('ncurses') depends_on('ncurses')
depends_on('readline') depends_on('readline')
resource(
name="luarocks",
url="https://keplerproject.github.io/luarocks/releases/"
"luarocks-2.3.0.tar.gz",
md5="a38126684cf42b7d0e7a3c7cf485defb",
destination="luarocks",
placement='luarocks')
def install(self, spec, prefix): def install(self, spec, prefix):
if spec.satisfies("=darwin-i686") or spec.satisfies("=darwin-x86_64"): if spec.satisfies("=darwin-i686") or spec.satisfies("=darwin-x86_64"):
target = 'macosx' target = 'macosx'
else: else:
target = 'linux' target = 'linux'
make('INSTALL_TOP=%s' % prefix, make('INSTALL_TOP=%s' % prefix,
'MYLDFLAGS=-L%s -lncurses' % spec['ncurses'].prefix.lib, 'MYLDFLAGS=-L%s -L%s ' % (
spec['readline'].prefix.lib,
spec['ncurses'].prefix.lib),
'MYLIBS=-lncurses',
target) target)
make('INSTALL_TOP=%s' % prefix, make('INSTALL_TOP=%s' % prefix,
'MYLDFLAGS=-L%s -lncurses' % spec['ncurses'].prefix.lib, 'MYLDFLAGS=-L%s -L%s ' % (
spec['readline'].prefix.lib,
spec['ncurses'].prefix.lib),
'MYLIBS=-lncurses',
'install') 'install')
with working_dir(os.path.join('luarocks', 'luarocks')):
configure('--prefix=' + prefix, '--with-lua=' + prefix)
make('build')
make('install')
def append_paths(self, paths, cpaths, path):
paths.append(os.path.join(path, '?.lua'))
paths.append(os.path.join(path, '?', 'init.lua'))
cpaths.append(os.path.join(path, '?.so'))
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
lua_paths = []
for d in extension_spec.traverse():
if d.package.extends(self.spec):
lua_paths.append(os.path.join(d.prefix, self.lua_lib_dir))
lua_paths.append(os.path.join(d.prefix, self.lua_share_dir))
lua_patterns = []
lua_cpatterns = []
for p in lua_paths:
if os.path.isdir(p):
self.append_paths(lua_patterns, lua_cpatterns, p)
# Always add this package's paths
for p in (os.path.join(self.spec.prefix, self.lua_lib_dir),
os.path.join(self.spec.prefix, self.lua_share_dir)):
self.append_paths(lua_patterns, lua_cpatterns, p)
spack_env.set('LUA_PATH', ';'.join(lua_patterns), separator=';')
spack_env.set('LUA_CPATH', ';'.join(lua_cpatterns), separator=';')
# For run time environment set only the path for extension_spec and
# prepend it to LUAPATH
if extension_spec.package.extends(self.spec):
run_env.prepend_path('LUA_PATH', ';'.join(lua_patterns),
separator=';')
run_env.prepend_path('LUA_CPATH', ';'.join(lua_cpatterns),
separator=';')
def setup_environment(self, spack_env, run_env):
run_env.prepend_path(
'LUA_PATH',
os.path.join(self.spec.prefix, self.lua_share_dir, '?.lua'),
separator=';')
run_env.prepend_path(
'LUA_PATH', os.path.join(self.spec.prefix, self.lua_share_dir, '?',
'init.lua'),
separator=';')
run_env.prepend_path(
'LUA_PATH',
os.path.join(self.spec.prefix, self.lua_lib_dir, '?.lua'),
separator=';')
run_env.prepend_path(
'LUA_PATH',
os.path.join(self.spec.prefix, self.lua_lib_dir, '?', 'init.lua'),
separator=';')
run_env.prepend_path(
'LUA_CPATH',
os.path.join(self.spec.prefix, self.lua_lib_dir, '?.so'),
separator=';')
@property
def lua_lib_dir(self):
return os.path.join('lib', 'lua', '%d.%d' % self.version[:2])
@property
def lua_share_dir(self):
return os.path.join('share', 'lua', '%d.%d' % self.version[:2])
def setup_dependent_package(self, module, ext_spec):
"""
Called before lua modules's install() methods.
In most cases, extensions will only need to have two lines::
luarocks('--tree=' + prefix, 'install', rock_spec_path)
"""
# Lua extension builds can have lua and luarocks executable functions
module.lua = Executable(join_path(self.spec.prefix.bin, 'lua'))
module.luarocks = Executable(join_path(self.spec.prefix.bin,
'luarocks'))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment