Merge pull request #955 from trws/lua-rework

complete lua rework
This commit is contained in:
Todd Gamblin 2016-05-17 13:21:51 -07:00
commit 138307dd0c
5 changed files with 170 additions and 46 deletions

View File

@ -45,11 +45,8 @@ class OpenMpi(Package):
* ``resource``
"""
__all__ = ['depends_on', 'extends', 'provides', 'patch', 'version',
'variant', 'resource']
import re
import inspect
import os.path
import functools
@ -67,6 +64,9 @@ class OpenMpi(Package):
from spack.resource import Resource
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 file.
@ -122,15 +122,14 @@ class Foo(Package):
def __init__(self, dicts=None):
if isinstance(dicts, basestring):
dicts = (dicts,)
dicts = (dicts, )
elif type(dicts) not in (list, tuple):
raise TypeError(
"dicts arg must be list, tuple, or string. Found %s"
% type(dicts))
"dicts arg must be list, tuple, or string. Found %s" %
type(dicts))
self.dicts = dicts
def ensure_dicts(self, pkg):
"""Ensure that a package has the dicts required by this directive."""
for d in self.dicts:
@ -142,7 +141,6 @@ def ensure_dicts(self, pkg):
raise spack.error.SpackError(
"Package %s has non-dict %s attribute!" % (pkg, d))
def __call__(self, directive_function):
directives[directive_function.__name__] = self
@ -259,11 +257,12 @@ def variant(pkg, name, default=False, description=""):
"""Define a variant for the package. Packager can specify a default
value (on or off) as well as a text description."""
default = bool(default)
default = bool(default)
description = str(description).strip()
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)
@ -271,31 +270,37 @@ def variant(pkg, name, default=False, description=""):
@directive('resources')
def resource(pkg, **kwargs):
"""
Define an external resource to be fetched and staged when building the package. Based on the keywords present in the
dictionary the appropriate 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.
Define an external resource to be fetched and staged when building the
package. Based on the keywords present in the dictionary the appropriate
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:
* 'when' : (optional) represents the condition upon which the resource is needed
* 'destination' : (optional) path where to link the resource. This path must be relative to the main package stage
area.
* 'placement' : (optional) gives the possibility to fine tune how the resource is linked into the main package stage
area.
* 'when' : (optional) represents the condition upon which the resource is
needed
* 'destination' : (optional) path where to link the resource. This path
must be relative to the main package stage 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)
destination = kwargs.get('destination', "")
placement = kwargs.get('placement', None)
# Check if the path is relative
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)
raise RuntimeError(message)
# Check if the path falls within the main package stage area
test_path = 'stage_folder_root/'
normalized_destination = os.path.normpath(join_path(test_path, destination)) # Normalized absolute path
test_path = 'stage_folder_root'
normalized_destination = os.path.normpath(join_path(test_path, destination)
) # Normalized absolute path
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)
raise RuntimeError(message)
when_spec = parse_anonymous_spec(when, pkg.name)
@ -307,6 +312,7 @@ def resource(pkg, **kwargs):
class DirectiveError(spack.error.SpackError):
"""This is raised when something is wrong with a package directive."""
def __init__(self, directive, message):
super(DirectiveError, self).__init__(message)
self.directive = directive
@ -314,6 +320,7 @@ def __init__(self, directive, message):
class CircularReferenceError(DirectiveError):
"""This is raised when something depends on itself."""
def __init__(self, directive, package):
super(CircularReferenceError, self).__init__(
directive,

View File

@ -39,7 +39,8 @@ class NameValueModifier(object):
def __init__(self, name, value, **kwargs):
self.name = name
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)
@ -56,34 +57,36 @@ def execute(self):
class SetPath(NameValueModifier):
def execute(self):
string_path = concatenate_paths(self.value)
string_path = concatenate_paths(self.value, separator=self.separator)
os.environ[self.name] = string_path
class AppendPath(NameValueModifier):
def execute(self):
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))
os.environ[self.name] = ':'.join(directories)
os.environ[self.name] = self.separator.join(directories)
class PrependPath(NameValueModifier):
def execute(self):
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
os.environ[self.name] = ':'.join(directories)
os.environ[self.name] = self.separator.join(directories)
class RemovePath(NameValueModifier):
def execute(self):
environment_value = os.environ.get(self.name, '')
directories = environment_value.split(':') if environment_value else []
directories = [os.path.normpath(x)
for x in directories
directories = environment_value.split(
self.separator) if environment_value else []
directories = [os.path.normpath(x) for x in directories
if x != os.path.normpath(self.value)]
os.environ[self.name] = ':'.join(directories)
os.environ[self.name] = self.separator.join(directories)
class EnvironmentModifications(object):
@ -238,17 +241,19 @@ def apply_modifications(self):
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:
paths: iterable of paths
separator: the separator to use, default ':'
Returns:
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):
@ -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
have already been requested
"""
indexes = [ii
for ii, item in enumerate(changes)
indexes = [ii for ii, item in enumerate(changes)
if ii != 0 and type(item) in [SetEnv, UnsetEnv]]
if indexes:
good = '\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
errstream(
message.format(
var=variable))
errstream(message.format(var=variable))
for ii, item in enumerate(changes):
print_format = nogood if ii in indexes else good
errstream(print_format.format(**item.args))

View File

@ -485,9 +485,9 @@ class TclModule(EnvModule):
path = join_path(spack.share_path, "modules")
environment_modifications_formats = {
PrependPath: 'prepend-path {name} \"{value}\"\n',
AppendPath: 'append-path {name} \"{value}\"\n',
RemovePath: 'remove-path {name} \"{value}\"\n',
PrependPath: 'prepend-path --delim "{delim}" {name} \"{value}\"\n',
AppendPath: 'append-path --delim "{delim}" {name} \"{value}\"\n',
RemovePath: 'remove-path --delim "{delim}" {name} \"{value}\"\n',
SetEnv: 'setenv {name} \"{value}\"\n',
UnsetEnv: 'unsetenv {name}\n'
}

View File

@ -0,0 +1,16 @@
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])

View File

@ -25,10 +25,11 @@
from spack import *
import os
class Lua(Package):
""" The Lua programming language interpreter and library """
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.1', '797adacada8d85761c079390ff1d9961')
@ -42,17 +43,115 @@ class Lua(Package):
version('5.1.4', 'd0870f2de55d59c1c8419f36e8fac150')
version('5.1.3', 'a70a8dfaa150e047866dc01a46272599')
extendable = True
depends_on('ncurses')
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):
if spec.satisfies("=darwin-i686") or spec.satisfies("=darwin-x86_64"):
target = 'macosx'
else:
target = 'linux'
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)
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')
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'))