package : added hooks for generic phases
This commit is contained in:
parent
069de3f008
commit
a36f3764af
2 changed files with 92 additions and 72 deletions
|
@ -176,10 +176,10 @@
|
||||||
# TODO: it's not clear where all the stuff that needs to be included in packages
|
# TODO: it's not clear where all the stuff that needs to be included in packages
|
||||||
# should live. This file is overloaded for spack core vs. for packages.
|
# should live. This file is overloaded for spack core vs. for packages.
|
||||||
#
|
#
|
||||||
__all__ = ['Package', 'StagedPackage', 'CMakePackage', \
|
__all__ = ['Package', 'CMakePackage', \
|
||||||
'Version', 'when', 'ver']
|
'Version', 'when', 'ver']
|
||||||
from spack.package import Package, ExtensionConflictError
|
from spack.package import Package, ExtensionConflictError
|
||||||
from spack.package import StagedPackage, CMakePackage
|
from spack.package import CMakePackage
|
||||||
from spack.version import Version, ver
|
from spack.version import Version, ver
|
||||||
from spack.multimethod import when
|
from spack.multimethod import when
|
||||||
|
|
||||||
|
|
|
@ -875,7 +875,7 @@ def _resource_stage(self, resource):
|
||||||
resource_stage_folder = '-'.join(pieces)
|
resource_stage_folder = '-'.join(pieces)
|
||||||
return resource_stage_folder
|
return resource_stage_folder
|
||||||
|
|
||||||
install_phases = set(['configure', 'build', 'install', 'provenance'])
|
_phases = ['install', 'create_spack_logs']
|
||||||
def do_install(self,
|
def do_install(self,
|
||||||
keep_prefix=False,
|
keep_prefix=False,
|
||||||
keep_stage=False,
|
keep_stage=False,
|
||||||
|
@ -887,7 +887,7 @@ def do_install(self,
|
||||||
fake=False,
|
fake=False,
|
||||||
explicit=False,
|
explicit=False,
|
||||||
dirty=False,
|
dirty=False,
|
||||||
install_phases = install_phases):
|
allowed_phases=None):
|
||||||
"""Called by commands to install a package and its dependencies.
|
"""Called by commands to install a package and its dependencies.
|
||||||
|
|
||||||
Package implementations should override install() to describe
|
Package implementations should override install() to describe
|
||||||
|
@ -907,6 +907,10 @@ def do_install(self,
|
||||||
make_jobs -- Number of make jobs to use for install. Default is ncpus
|
make_jobs -- Number of make jobs to use for install. Default is ncpus
|
||||||
run_tests -- Runn tests within the package's install()
|
run_tests -- Runn tests within the package's install()
|
||||||
"""
|
"""
|
||||||
|
# FIXME : we need a better semantic
|
||||||
|
if allowed_phases is None:
|
||||||
|
allowed_phases = self._phases
|
||||||
|
|
||||||
if not self.spec.concrete:
|
if not self.spec.concrete:
|
||||||
raise ValueError("Can only install concrete packages.")
|
raise ValueError("Can only install concrete packages.")
|
||||||
|
|
||||||
|
@ -917,7 +921,8 @@ def do_install(self,
|
||||||
return
|
return
|
||||||
|
|
||||||
# Ensure package is not already installed
|
# Ensure package is not already installed
|
||||||
if 'install' in install_phases and spack.install_layout.check_installed(self.spec):
|
# FIXME : This should be a pre-requisite to a phase
|
||||||
|
if 'install' in self._phases and spack.install_layout.check_installed(self.spec):
|
||||||
tty.msg("%s is already installed in %s" % (self.name, self.prefix))
|
tty.msg("%s is already installed in %s" % (self.name, self.prefix))
|
||||||
rec = spack.installed_db.get_record(self.spec)
|
rec = spack.installed_db.get_record(self.spec)
|
||||||
if (not rec.explicit) and explicit:
|
if (not rec.explicit) and explicit:
|
||||||
|
@ -960,7 +965,6 @@ def build_process():
|
||||||
tty.msg("Building %s" % self.name)
|
tty.msg("Building %s" % self.name)
|
||||||
|
|
||||||
self.stage.keep = keep_stage
|
self.stage.keep = keep_stage
|
||||||
self.install_phases = install_phases
|
|
||||||
self.build_directory = join_path(self.stage.path, 'spack-build')
|
self.build_directory = join_path(self.stage.path, 'spack-build')
|
||||||
self.source_directory = self.stage.source_path
|
self.source_directory = self.stage.source_path
|
||||||
|
|
||||||
|
@ -983,11 +987,25 @@ def build_process():
|
||||||
# the terminal)
|
# the terminal)
|
||||||
log_path = join_path(os.getcwd(), 'spack-build.out')
|
log_path = join_path(os.getcwd(), 'spack-build.out')
|
||||||
log_file = open(log_path, 'w')
|
log_file = open(log_path, 'w')
|
||||||
|
# FIXME : refactor this assignment
|
||||||
|
self.log_path = log_path
|
||||||
|
self.env_path = env_path
|
||||||
with log_output(log_file, verbose, sys.stdout.isatty(),
|
with log_output(log_file, verbose, sys.stdout.isatty(),
|
||||||
True):
|
True):
|
||||||
dump_environment(env_path)
|
dump_environment(env_path)
|
||||||
self.install(self.spec, self.prefix)
|
try:
|
||||||
|
for phase in filter(lambda x: x in allowed_phases, self._phases):
|
||||||
|
# TODO : Log to screen the various phases
|
||||||
|
action = getattr(self, phase)
|
||||||
|
if getattr(action, 'preconditions', None):
|
||||||
|
action.preconditions()
|
||||||
|
action(self.spec, self.prefix)
|
||||||
|
if getattr(action, 'postconditions', None):
|
||||||
|
action.postconditions()
|
||||||
|
|
||||||
|
except AttributeError as e:
|
||||||
|
# FIXME : improve error messages
|
||||||
|
raise ProcessError(e.message, long_message='')
|
||||||
except ProcessError as e:
|
except ProcessError as e:
|
||||||
# Annotate ProcessErrors with the location of
|
# Annotate ProcessErrors with the location of
|
||||||
# the build log
|
# the build log
|
||||||
|
@ -995,29 +1013,9 @@ def build_process():
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
# Ensure that something was actually installed.
|
# Ensure that something was actually installed.
|
||||||
if 'install' in self.install_phases:
|
# FIXME : This should be executed after 'install' as a postcondition
|
||||||
self.sanity_check_prefix()
|
# if 'install' in self._phases:
|
||||||
|
# self.sanity_check_prefix()
|
||||||
|
|
||||||
# Copy provenance into the install directory on success
|
|
||||||
if 'provenance' in self.install_phases:
|
|
||||||
log_install_path = spack.install_layout.build_log_path(
|
|
||||||
self.spec)
|
|
||||||
env_install_path = spack.install_layout.build_env_path(
|
|
||||||
self.spec)
|
|
||||||
packages_dir = spack.install_layout.build_packages_path(
|
|
||||||
self.spec)
|
|
||||||
|
|
||||||
# Remove first if we're overwriting another build
|
|
||||||
# (can happen with spack setup)
|
|
||||||
try:
|
|
||||||
shutil.rmtree(packages_dir) # log_install_path and env_install_path are inside this
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
install(log_path, log_install_path)
|
|
||||||
install(env_path, env_install_path)
|
|
||||||
dump_packages(self.spec, packages_dir)
|
|
||||||
|
|
||||||
# Run post install hooks before build stage is removed.
|
# Run post install hooks before build stage is removed.
|
||||||
spack.hooks.post_install(self)
|
spack.hooks.post_install(self)
|
||||||
|
@ -1036,7 +1034,7 @@ def build_process():
|
||||||
# Create the install prefix and fork the build process.
|
# Create the install prefix and fork the build process.
|
||||||
spack.install_layout.create_install_directory(self.spec)
|
spack.install_layout.create_install_directory(self.spec)
|
||||||
except directory_layout.InstallDirectoryAlreadyExistsError:
|
except directory_layout.InstallDirectoryAlreadyExistsError:
|
||||||
if 'install' in install_phases:
|
if 'install' in self._phases:
|
||||||
# Abort install if install directory exists.
|
# Abort install if install directory exists.
|
||||||
# But do NOT remove it (you'd be overwriting someon else's stuff)
|
# But do NOT remove it (you'd be overwriting someon else's stuff)
|
||||||
tty.warn("Keeping existing install prefix in place.")
|
tty.warn("Keeping existing install prefix in place.")
|
||||||
|
@ -1064,6 +1062,27 @@ def build_process():
|
||||||
# the database, so that we don't need to re-read from file.
|
# the database, so that we don't need to re-read from file.
|
||||||
spack.installed_db.add(self.spec, self.prefix, explicit=explicit)
|
spack.installed_db.add(self.spec, self.prefix, explicit=explicit)
|
||||||
|
|
||||||
|
def create_spack_logs(self, spec, prefix):
|
||||||
|
# Copy provenance into the install directory on success
|
||||||
|
log_install_path = spack.install_layout.build_log_path(
|
||||||
|
self.spec)
|
||||||
|
env_install_path = spack.install_layout.build_env_path(
|
||||||
|
self.spec)
|
||||||
|
packages_dir = spack.install_layout.build_packages_path(
|
||||||
|
self.spec)
|
||||||
|
|
||||||
|
# Remove first if we're overwriting another build
|
||||||
|
# (can happen with spack setup)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(packages_dir) # log_install_path and env_install_path are inside this
|
||||||
|
except Exception:
|
||||||
|
# FIXME : this potentially catches too many things...
|
||||||
|
pass
|
||||||
|
|
||||||
|
install(self.log_path, log_install_path)
|
||||||
|
install(self.env_path, env_install_path)
|
||||||
|
dump_packages(self.spec, packages_dir)
|
||||||
|
|
||||||
def sanity_check_prefix(self):
|
def sanity_check_prefix(self):
|
||||||
"""This function checks whether install succeeded."""
|
"""This function checks whether install succeeded."""
|
||||||
|
|
||||||
|
@ -1529,42 +1548,42 @@ def _hms(seconds):
|
||||||
parts.append("%.2fs" % s)
|
parts.append("%.2fs" % s)
|
||||||
return ' '.join(parts)
|
return ' '.join(parts)
|
||||||
|
|
||||||
class StagedPackage(Package):
|
#class StagedPackage(Package):
|
||||||
"""A Package subclass where the install() is split up into stages."""
|
# """A Package subclass where the install() is split up into stages."""
|
||||||
|
# _phases = ['configure']
|
||||||
def install_setup(self):
|
# def install_setup(self):
|
||||||
"""Creates an spack_setup.py script to configure the package later if we like."""
|
# """Creates an spack_setup.py script to configure the package later if we like."""
|
||||||
raise InstallError("Package %s provides no install_setup() method!" % self.name)
|
# raise InstallError("Package %s provides no install_setup() method!" % self.name)
|
||||||
|
#
|
||||||
def install_configure(self):
|
# def install_configure(self):
|
||||||
"""Runs the configure process."""
|
# """Runs the configure process."""
|
||||||
raise InstallError("Package %s provides no install_configure() method!" % self.name)
|
# raise InstallError("Package %s provides no install_configure() method!" % self.name)
|
||||||
|
#
|
||||||
def install_build(self):
|
# def install_build(self):
|
||||||
"""Runs the build process."""
|
# """Runs the build process."""
|
||||||
raise InstallError("Package %s provides no install_build() method!" % self.name)
|
# raise InstallError("Package %s provides no install_build() method!" % self.name)
|
||||||
|
#
|
||||||
def install_install(self):
|
# def install_install(self):
|
||||||
"""Runs the install process."""
|
# """Runs the install process."""
|
||||||
raise InstallError("Package %s provides no install_install() method!" % self.name)
|
# raise InstallError("Package %s provides no install_install() method!" % self.name)
|
||||||
|
#
|
||||||
def install(self, spec, prefix):
|
# def install(self, spec, prefix):
|
||||||
if 'setup' in self.install_phases:
|
# if 'setup' in self._phases:
|
||||||
self.install_setup()
|
# self.install_setup()
|
||||||
|
#
|
||||||
if 'configure' in self.install_phases:
|
# if 'configure' in self._phases:
|
||||||
self.install_configure()
|
# self.install_configure()
|
||||||
|
#
|
||||||
if 'build' in self.install_phases:
|
# if 'build' in self._phases:
|
||||||
self.install_build()
|
# self.install_build()
|
||||||
|
#
|
||||||
if 'install' in self.install_phases:
|
# if 'install' in self._phases:
|
||||||
self.install_install()
|
# self.install_install()
|
||||||
else:
|
# else:
|
||||||
# Create a dummy file so the build doesn't fail.
|
# # Create a dummy file so the build doesn't fail.
|
||||||
# That way, the module file will also be created.
|
# # That way, the module file will also be created.
|
||||||
with open(os.path.join(prefix, 'dummy'), 'w') as fout:
|
# with open(os.path.join(prefix, 'dummy'), 'w') as fout:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
# stackoverflow.com/questions/12791997/how-do-you-do-a-simple-chmod-x-from-within-python
|
# stackoverflow.com/questions/12791997/how-do-you-do-a-simple-chmod-x-from-within-python
|
||||||
def make_executable(path):
|
def make_executable(path):
|
||||||
|
@ -1574,7 +1593,8 @@ def make_executable(path):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CMakePackage(StagedPackage):
|
class CMakePackage(Package):
|
||||||
|
_phases = ['configure', 'build', 'install', 'provenance']
|
||||||
|
|
||||||
def make_make(self):
|
def make_make(self):
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
@ -1602,7 +1622,7 @@ def spack_transitive_include_path(self):
|
||||||
for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep)
|
for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep)
|
||||||
)
|
)
|
||||||
|
|
||||||
def install_setup(self):
|
def setup(self):
|
||||||
cmd = [str(which('cmake'))] + \
|
cmd = [str(which('cmake'))] + \
|
||||||
spack.build_environment.get_std_cmake_args(self) + \
|
spack.build_environment.get_std_cmake_args(self) + \
|
||||||
['-DCMAKE_INSTALL_PREFIX=%s' % os.environ['SPACK_PREFIX'],
|
['-DCMAKE_INSTALL_PREFIX=%s' % os.environ['SPACK_PREFIX'],
|
||||||
|
@ -1657,7 +1677,7 @@ def cmdlist(str):
|
||||||
make_executable(setup_fname)
|
make_executable(setup_fname)
|
||||||
|
|
||||||
|
|
||||||
def install_configure(self):
|
def configure(self):
|
||||||
cmake = which('cmake')
|
cmake = which('cmake')
|
||||||
with working_dir(self.build_directory, create=True):
|
with working_dir(self.build_directory, create=True):
|
||||||
os.environ.update(self.configure_env())
|
os.environ.update(self.configure_env())
|
||||||
|
@ -1665,12 +1685,12 @@ def install_configure(self):
|
||||||
options = self.configure_args() + spack.build_environment.get_std_cmake_args(self)
|
options = self.configure_args() + spack.build_environment.get_std_cmake_args(self)
|
||||||
cmake(self.source_directory, *options)
|
cmake(self.source_directory, *options)
|
||||||
|
|
||||||
def install_build(self):
|
def build(self):
|
||||||
make = self.make_make()
|
make = self.make_make()
|
||||||
with working_dir(self.build_directory, create=False):
|
with working_dir(self.build_directory, create=False):
|
||||||
make()
|
make()
|
||||||
|
|
||||||
def install_install(self):
|
def install(self):
|
||||||
make = self.make_make()
|
make = self.make_make()
|
||||||
with working_dir(self.build_directory, create=False):
|
with working_dir(self.build_directory, create=False):
|
||||||
make('install')
|
make('install')
|
||||||
|
|
Loading…
Reference in a new issue