Select Git revision
docker_cmd.py
juliapackage.py 6.15 KiB
##
# Copyright 2009-2019 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for building and installing Julia packages, implemented as an easyblock
@author: Victor Holanda (CSCS)
@author: Samuel Omlin (CSCS)
minor adjustments by Jens Henrik Goebbert (JSC)
"""
import os
import sys
import easybuild.tools.toolchain as toolchain
from easybuild.framework.easyconfig import CUSTOM
from easybuild.framework.extensioneasyblock import ExtensionEasyBlock
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.run import run_cmd, parse_log_for_error
class JuliaPackage(ExtensionEasyBlock):
"""
Install an Julia package as a separate module, or as an extension.
"""
@staticmethod
def extra_options(extra_vars=None):
if extra_vars is None:
extra_vars = {}
extra_vars.update({
'system_name': [None, "Change julia's Project.toml pathname", CUSTOM],
'arch_name': [None, "Change julia's Project.toml pathname", CUSTOM],
'packagespec': [None, "Overwrite install options for Pkg.add(PackageSpec(<packagespec>))", CUSTOM],
'mpiexec': [None, "Set the mpiexec command", CUSTOM],
'mpiexec_args': [None, "Set the mpiexec command args", CUSTOM],
'mpi_path': [None, "Set the MPI installation path", CUSTOM],
'mpicc': [None, "Set mpicc command", "mpicc"],
})
return ExtensionEasyBlock.extra_options(extra_vars=extra_vars)
def __init__(self, *args, **kwargs):
super(JuliaPackage, self).__init__(*args, **kwargs)
self.package_name = self.name
names = self.package_name.split('.')
if len(names) > 1:
self.package_name = ''.join(names[:-1])
julia_env_name = os.getenv('EBJULIA_ENV_NAME', '')
self.depot = os.path.join(self.installdir, 'extensions')
self.projectdir = os.path.join(self.depot, 'environments', julia_env_name)
self.log.info("Depot for package installations: %s" % self.depot)
def patch_step(self, beginpath=None):
pass
def fetch_sources(self, sources=None, checksums=None):
pass
def extract_step(self):
"""Source should not be extracted."""
pass
def configure_step(self):
"""No configuration for installing Julia packages."""
pass
def build_step(self):
"""No separate build step for Julia packages."""
pass
def make_julia_cmd(self, remove=False):
"""Create a command to run in julia to install an julia package."""
if self.cfg['packagespec']:
package_spec = self.cfg['packagespec']
else:
package_spec = "name=\"%s\", version=\"%s\"" % (self.package_name, self.version)
pre_cmd = '%s unset EBJULIA_USER_DEPOT_PATH && unset EBJULIA_ADMIN_DEPOT_PATH && export JULIA_DEPOT_PATH=%s && export JULIA_PROJECT=%s' % (self.cfg['preinstallopts'], self.depot, self.projectdir)
if self.cfg['mpi_path']:
pre_cmd += ' && export JULIA_MPI_BINARY=system'
pre_cmd += ' && export JULIA_MPI_PATH="%s"' % self.cfg['mpi_path']
if self.cfg['mpiexec']:
pre_cmd += ' && export JULIA_MPIEXEC="%s"' % self.cfg['mpiexec']
if self.cfg['mpiexec_args']:
pre_cmd += ' && export JULIA_MPIEXEC_ARGS="%s"' % self.cfg['mpiexec_args']
if self.cfg['mpicc']:
pre_cmd += ' && export JULIA_MPICC="%s"' % self.cfg['mpicc']
if self.cfg['arch_name'] == 'gpu':
pre_cmd += ' && export JULIA_CUDA_USE_BINARYBUILDER=false'
if remove:
cmd = ' && '.join([pre_cmd, "julia --eval 'using Pkg; Pkg.rm(PackageSpec(%s))'" % package_spec])
else:
cmd = ' && '.join([pre_cmd, "julia --eval 'using Pkg; Pkg.add(PackageSpec(%s))'" % package_spec])
return cmd
def install_step(self):
"""Install procedure for Julia packages."""
cmd = self.make_julia_cmd(remove=False)
cmdttdouterr, _ = run_cmd(cmd, log_all=True, simple=False, regexp=False)
cmderrors = parse_log_for_error(cmdttdouterr, regExp="^ERROR:")
if cmderrors:
cmd = self.make_julia_cmd(remove=True)
run_cmd(cmd, log_all=False, log_ok=False, simple=False, inp=sys.stdin, regexp=False)
raise EasyBuildError("Errors detected during installation of Julia package %s!", self.name)
self.log.info("Julia package %s installed succesfully" % self.name)
def run(self):
"""Install Julia package as an extension."""
self.install_step()
def sanity_check_step(self, *args, **kwargs):
"""
Custom sanity check for Julia packages
"""
#NOTE: we don't use Pkg.status with arguments as only supported for Julia >=v1.1
cmd = "unset EBJULIA_USER_DEPOT_PATH && unset EBJULIA_ADMIN_DEPOT_PATH && export JULIA_DEPOT_PATH=%s && export JULIA_PROJECT=%s && julia --eval 'using Pkg; Pkg.status()'" % (self.depot, self.projectdir)
cmdttdouterr, _ = run_cmd(cmd, log_all=True, simple=False, regexp=False)
self.log.error("Julia package %s sanity returned %s" % (self.name, cmdttdouterr))
return len(parse_log_for_error(cmdttdouterr, regExp="%s\s+v%s" % (self.package_name, self.version))) != 0