## # 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 DIRAC, implemented as an easyblock """ import os import re import shutil import tempfile import easybuild.tools.environment as env import easybuild.tools.toolchain as toolchain from easybuild.easyblocks.generic.cmakemake import CMakeMake from easybuild.framework.easyconfig import CUSTOM, MANDATORY from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option from easybuild.tools.run import run_cmd class EB_DIRAC(CMakeMake): """Support for building/installing DIRAC.""" def configure_step(self): """Custom configuration procedure for DIRAC.""" # make very sure the install directory isn't there yet, since it may cause problems if it used (forced rebuild) if os.path.exists(self.installdir): self.log.warning("Found existing install directory %s, removing it to avoid problems", self.installdir) try: shutil.rmtree(self.installdir) except OSError as err: raise EasyBuildError("Failed to remove existing install directory %s: %s", self.installdir, err) self.cfg['separate_build_dir'] = True #self.cfg.update('configopts', "-DENABLE_MPI=ON -DCMAKE_BUILD_TYPE=release") self.cfg.update('configopts', "--fc=mpiifort --mpi --cc=mpiicc --cxx=mpicxx") # complete configuration with configure_method of parent super(EB_DIRAC, self).configure_step() def test_step(self): """Custom built-in test procedure for DIRAC.""" if self.cfg['runtest']: if not build_option('mpi_tests'): self.log.info("Skipping testing of DIRAC since MPI testing is disabled") return # set up test environment # see http://diracprogram.org/doc/release-14/installation/testing.html env.setvar('DIRAC_TMPDIR', tempfile.mkdtemp(prefix='dirac-test-')) env.setvar('DIRAC_MPI_COMMAND', self.toolchain.mpi_cmd_for('', self.cfg['parallel'])) # run tests (may take a while, especially if some tests take a while to time out) self.log.info("Running tests may take a while, especially if some tests timeout (default timeout is 1500s)") cmd = "make test" out, ec = run_cmd(cmd, simple=False, log_all=False, log_ok=False) # check that majority of tests pass # some may fail due to timeout, but that's acceptable # cfr. https://groups.google.com/forum/#!msg/dirac-users/zEd5-xflBnY/OQ1pSbuX810J # over 90% of tests should pass passed_regex = re.compile('^(9|10)[0-9.]+% tests passed', re.M) if not passed_regex.search(out) and not self.dry_run: raise EasyBuildError("Too many failed tests; '%s' not found in test output: %s", passed_regex.pattern, out) # extract test results test_result_regex = re.compile(r'^\s*[0-9]+/[0-9]+ Test \s*#[0-9]+: .*', re.M) test_results = test_result_regex.findall(out) if test_results: self.log.info("Found %d test results: %s", len(test_results), test_results) elif self.dry_run: # dummy test result test_results = ["1/1 Test #1: dft_alda_xcfun ............................. Passed 72.29 sec"] else: raise EasyBuildError("Couldn't find *any* test results?") test_count_regex = re.compile(r'^\s*[0-9]+/([0-9]+)') res = test_count_regex.search(test_results[0]) if res: test_count = int(res.group(1)) elif self.dry_run: # a single dummy test result test_count = 1 else: raise EasyBuildError("Failed to determine total test count from %s using regex '%s'", test_results[0], test_count_regex.pattern) if len(test_results) != test_count: raise EasyBuildError("Expected to find %s test results, but found %s", test_count, len(test_results)) # check test results, only 'Passed' or 'Timeout' are acceptable outcomes faulty_tests = [] for test_result in test_results: if ' Passed ' not in test_result: self.log.warning("Found failed test: %s", test_result) if '***Timeout' not in test_result: faulty_tests.append(test_result) if faulty_tests: raise EasyBuildError("Found tests failing due to something else than timeout: %s", faulty_tests) def sanity_check_step(self): """Custom sanity check for DIRAC.""" custom_paths = { 'files': ['bin/pam-dirac'], 'dirs': ['share/dirac'], } super(EB_DIRAC, self).sanity_check_step(custom_paths=custom_paths)