Skip to content
Snippets Groups Projects
dirac.py 5.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • ##
    # 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)