def test_filter_deps(self): """Test filtered dependencies.""" test_ecs_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'easyconfigs') ec_file = os.path.join(test_ecs_dir, 'goolf-1.4.10.eb') ec = EasyConfig(ec_file) deps = sorted([dep['name'] for dep in ec.dependencies()]) self.assertEqual(deps, ['FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK']) # test filtering multiple deps init_config(build_options={'filter_deps': ['FFTW', 'ScaLAPACK']}) deps = sorted([dep['name'] for dep in ec.dependencies()]) self.assertEqual(deps, ['GCC', 'OpenBLAS', 'OpenMPI']) # test filtering of non-existing dep init_config(build_options={'filter_deps': ['zlib']}) deps = sorted([dep['name'] for dep in ec.dependencies()]) self.assertEqual(deps, ['FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK']) # test parsing of value passed to --filter-deps opts = init_config(args=[]) self.assertEqual(opts.filter_deps, None) opts = init_config(args=['--filter-deps=zlib']) self.assertEqual(opts.filter_deps, ['zlib']) opts = init_config(args=['--filter-deps=zlib,ncurses']) self.assertEqual(opts.filter_deps, ['zlib', 'ncurses'])
def test_external_module_toolchain(self): """Test specifying external (build) dependencies in yaml format.""" if 'yaml' not in sys.modules: print "Skipping test_external_module_toolchain (no PyYAML available)" return ecpath = os.path.join(os.path.dirname(__file__), 'easyconfigs', 'yeb', 'CrayCCE-5.1.29.yeb') metadata = { 'name': ['foo', 'bar'], 'version': ['1.2.3', '3.2.1'], 'prefix': '/foo/bar', } build_options = { 'external_modules_metadata': { 'fftw/3.3.4.0': metadata }, 'valid_module_classes': module_classes(), } init_config(build_options=build_options) easybuild.tools.build_log.EXPERIMENTAL = True ec = EasyConfig(ecpath) self.assertEqual(ec.dependencies()[1]['full_mod_name'], 'fftw/3.3.4.0') self.assertEqual(ec.dependencies()[1]['external_module_metadata'], metadata)
def test_dependency(self): """ test all possible ways of specifying dependencies """ self.contents = '\n'.join([ 'name = "pi"', 'version = "3.14"', 'homepage = "http://google.com"', 'description = "test easyconfig"', 'toolchain = {"name":"GCC", "version": "4.6.3"}', 'dependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', 'builddependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', ]) self.prep() eb = EasyConfig(self.eb_file, valid_stops=self.all_stops) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') eb['dependencies'] = ["wrong type"] self.assertErrorRegex(EasyBuildError, "wrong type from unsupported type", eb.dependencies) eb['dependencies'] = [()] self.assertErrorRegex(EasyBuildError, "without name", eb.dependencies) eb['dependencies'] = [{'name': "test"}] self.assertErrorRegex(EasyBuildError, "without version", eb.dependencies)
def test_dependency(self): """ test all possible ways of specifying dependencies """ self.contents = '\n'.join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.14"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name":"GCC", "version": "4.6.3"}', 'dependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', 'builddependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', ]) self.prep() eb = EasyConfig(self.eb_file) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') self.assertErrorRegex(EasyBuildError, "Dependency foo of unsupported type", eb._parse_dependency, "foo") self.assertErrorRegex(EasyBuildError, "without name", eb._parse_dependency, ()) self.assertErrorRegex(EasyBuildError, "without version", eb._parse_dependency, {'name': 'test'}) err_msg = "Incorrect external dependency specification" self.assertErrorRegex(EasyBuildError, err_msg, eb._parse_dependency, (EXTERNAL_MODULE_MARKER,)) self.assertErrorRegex(EasyBuildError, err_msg, eb._parse_dependency, ('foo', '1.2.3', EXTERNAL_MODULE_MARKER))
def test_dependency(self): """ test all possible ways of specifying dependencies """ self.contents = '\n'.join([ 'name = "pi"', 'version = "3.14"', 'homepage = "http://google.com"', 'description = "test easyconfig"', 'toolchain = {"name":"GCC", "version": "4.6.3"}', 'dependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', 'builddependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', ]) self.prep() eb = EasyConfig(self.eb_file, valid_stops=self.all_stops) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') eb['dependencies'] = ["wrong type"] self.assertErrorRegex(EasyBuildError, "wrong type from unsupported type", eb.dependencies) eb['dependencies'] = [()] self.assertErrorRegex(EasyBuildError, "without name", eb.dependencies) eb['dependencies'] = [{'name': "test"}] self.assertErrorRegex(EasyBuildError, "without version", eb.dependencies)
def test_external_dependencies(self): """Test specifying external (build) dependencies.""" ectxt = read_file(os.path.join(os.path.dirname(__file__), 'easyconfigs', 'toy-0.0-deps.eb')) toy_ec = os.path.join(self.test_prefix, 'toy-0.0-external-deps.eb') # just specify some of the test modules we ship, doesn't matter where they come from ectxt += "\ndependencies += [('foobar/1.2.3', EXTERNAL_MODULE)]" ectxt += "\nbuilddependencies = [('somebuilddep/0.1', EXTERNAL_MODULE)]" write_file(toy_ec, ectxt) build_options = { 'valid_module_classes': module_classes(), 'external_modules_metadata': ConfigObj(), } init_config(build_options=build_options) ec = EasyConfig(toy_ec) builddeps = ec.builddependencies() self.assertEqual(len(builddeps), 1) self.assertEqual(builddeps[0]['short_mod_name'], 'somebuilddep/0.1') self.assertEqual(builddeps[0]['full_mod_name'], 'somebuilddep/0.1') self.assertEqual(builddeps[0]['external_module'], True) deps = ec.dependencies() self.assertEqual(len(deps), 4) correct_deps = ['ictce/4.1.13', 'GCC/4.7.2', 'foobar/1.2.3', 'somebuilddep/0.1'] self.assertEqual([d['short_mod_name'] for d in deps], correct_deps) self.assertEqual([d['full_mod_name'] for d in deps], correct_deps) self.assertEqual([d['external_module'] for d in deps], [False, True, True, True]) metadata = os.path.join(self.test_prefix, 'external_modules_metadata.cfg') metadatatxt = '\n'.join(['[foobar/1.2.3]', 'name = foo,bar', 'version = 1.2.3,3.2.1', 'prefix = /foo/bar']) write_file(metadata, metadatatxt) cfg = init_config(args=['--external-modules-metadata=%s' % metadata]) build_options = { 'external_modules_metadata': cfg.external_modules_metadata, 'valid_module_classes': module_classes(), } init_config(build_options=build_options) ec = EasyConfig(toy_ec) self.assertEqual(ec.dependencies()[2]['short_mod_name'], 'foobar/1.2.3') self.assertEqual(ec.dependencies()[2]['external_module'], True) metadata = { 'name': ['foo', 'bar'], 'version': ['1.2.3', '3.2.1'], 'prefix': '/foo/bar', } self.assertEqual(ec.dependencies()[2]['external_module_metadata'], metadata)
def test_dependency(self): """ test all possible ways of specifying dependencies """ self.contents = '\n'.join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.14"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name":"GCC", "version": "4.6.3"}', 'dependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', 'builddependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', ]) self.prep() eb = EasyConfig(self.eb_file) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') self.assertErrorRegex(EasyBuildError, "Dependency foo of unsupported type", eb._parse_dependency, "foo") self.assertErrorRegex(EasyBuildError, "without name", eb._parse_dependency, ()) self.assertErrorRegex(EasyBuildError, "without version", eb._parse_dependency, {'name': 'test'})
def test_dependency(self): """ test all possible ways of specifying dependencies """ self.contents = '\n'.join([ 'name = "pi"', 'version = "3.14"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name":"GCC", "version": "4.6.3"}', 'dependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', 'builddependencies = [("first", "1.1"), {"name": "second", "version": "2.2"}]', ]) self.prep() eb = EasyConfig(self.eb_file, build_options={'valid_stops': self.all_stops}) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') self.assertErrorRegex(EasyBuildError, "Dependency foo of unsupported type", eb._parse_dependency, "foo") self.assertErrorRegex(EasyBuildError, "without name", eb._parse_dependency, ()) self.assertErrorRegex(EasyBuildError, "without version", eb._parse_dependency, {'name': 'test'})
def process_easyconfig(path, onlyBlocks=None, regtest_online=False, validate=True): """ Process easyconfig, returning some information for each block """ blocks = retrieve_blocks_in_spec(path, onlyBlocks) easyconfigs = [] for spec in blocks: # process for dependencies and real installversionname # - use mod? __init__ and importCfg are ignored. _log.debug("Processing easyconfig %s" % spec) # create easyconfig try: all_stops = [x[0] for x in EasyBlock.get_steps()] ec = EasyConfig(spec, validate=validate, valid_module_classes=module_classes(), valid_stops=all_stops) except EasyBuildError, err: msg = "Failed to process easyconfig %s:\n%s" % (spec, err.msg) _log.exception(msg) name = ec["name"] # this app will appear as following module in the list easyconfig = { "spec": spec, "module": (ec.name, ec.get_installversion()), "dependencies": [], "builddependencies": [], } if len(blocks) > 1: easyconfig["originalSpec"] = path # add build dependencies for dep in ec.builddependencies(): deptup = (dep["name"], dep["tc"]) _log.debug("Adding build dependency %s for app %s." % (deptup, name)) easyconfig["builddependencies"].append(deptup) # add dependencies (including build dependencies) for dep in ec.dependencies(): deptup = (dep["name"], dep["tc"]) _log.debug("Adding dependency %s for app %s." % (deptup, name)) easyconfig["dependencies"].append(deptup) # add toolchain as dependency too if ec.toolchain.name != "dummy": dep = (ec.toolchain.name, ec.toolchain.version) _log.debug("Adding toolchain %s as dependency for app %s." % (dep, name)) easyconfig["dependencies"].append(dep) del ec # this is used by the parallel builder easyconfig["unresolvedDependencies"] = copy.copy(easyconfig["dependencies"]) easyconfigs.append(easyconfig)
def process_easyconfig(path, onlyBlocks=None, regtest_online=False, validate=True): """ Process easyconfig, returning some information for each block """ blocks = retrieve_blocks_in_spec(path, onlyBlocks) easyconfigs = [] for spec in blocks: # process for dependencies and real installversionname # - use mod? __init__ and importCfg are ignored. _log.debug("Processing easyconfig %s" % spec) # create easyconfig try: all_stops = [x[0] for x in EasyBlock.get_steps()] ec = EasyConfig(spec, validate=validate, valid_module_classes=module_classes(), valid_stops=all_stops) except EasyBuildError, err: msg = "Failed to process easyconfig %s:\n%s" % (spec, err.msg) _log.exception(msg) name = ec['name'] # this app will appear as following module in the list easyconfig = { 'spec': spec, 'module': (ec.name, ec.get_installversion()), 'dependencies': [], 'builddependencies': [], } if len(blocks) > 1: easyconfig['originalSpec'] = path # add build dependencies for dep in ec.builddependencies(): deptup = (dep['name'], dep['tc']) _log.debug("Adding build dependency %s for app %s." % (deptup, name)) easyconfig['builddependencies'].append(deptup) # add dependencies (including build dependencies) for dep in ec.dependencies(): deptup = (dep['name'], dep['tc']) _log.debug("Adding dependency %s for app %s." % (deptup, name)) easyconfig['dependencies'].append(deptup) # add toolchain as dependency too if ec.toolchain.name != 'dummy': dep = (ec.toolchain.name, ec.toolchain.version) _log.debug("Adding toolchain %s as dependency for app %s." % (dep, name)) easyconfig['dependencies'].append(dep) del ec # this is used by the parallel builder easyconfig['unresolvedDependencies'] = copy.copy(easyconfig['dependencies']) easyconfigs.append(easyconfig)
def process_easyconfig(path, build_options=None, build_specs=None): """ Process easyconfig, returning some information for each block @param path: path to easyconfig file @param build_options: dictionary specifying build options (e.g. robot_path, check_osdeps, ...) @param build_specs: dictionary specifying build specifications (e.g. version, toolchain, ...) """ blocks = retrieve_blocks_in_spec(path, build_options.get("only_blocks", None)) easyconfigs = [] for spec in blocks: # process for dependencies and real installversionname _log.debug("Processing easyconfig %s" % spec) # create easyconfig try: ec = EasyConfig(spec, build_options=build_options, build_specs=build_specs) except EasyBuildError, err: msg = "Failed to process easyconfig %s:\n%s" % (spec, err.msg) _log.exception(msg) name = ec["name"] # this app will appear as following module in the list easyconfig = { "ec": ec, "spec": spec, "module": det_full_module_name(ec), "dependencies": [], "builddependencies": [], } if len(blocks) > 1: easyconfig["originalSpec"] = path # add build dependencies for dep in ec.builddependencies(): _log.debug("Adding build dependency %s for app %s." % (dep, name)) easyconfig["builddependencies"].append(dep) # add dependencies (including build dependencies) for dep in ec.dependencies(): _log.debug("Adding dependency %s for app %s." % (dep, name)) easyconfig["dependencies"].append(dep) # add toolchain as dependency too if ec.toolchain.name != DUMMY_TOOLCHAIN_NAME: dep = ec.toolchain.as_dict() _log.debug("Adding toolchain %s as dependency for app %s." % (dep, name)) easyconfig["dependencies"].append(dep) del ec # this is used by the parallel builder easyconfig["unresolved_deps"] = copy.deepcopy(easyconfig["dependencies"]) easyconfigs.append(easyconfig)
def test_external_module_toolchain(self): """Test specifying external (build) dependencies.""" ecpath = os.path.join(os.path.dirname(__file__), 'easyconfigs', 'yeb', 'CrayCCE-5.1.29.yeb') metadata = { 'name': ['foo', 'bar'], 'version': ['1.2.3', '3.2.1'], 'prefix': '/foo/bar', } build_options = { 'external_modules_metadata': {'fftw/3.3.4.0': metadata}, 'valid_module_classes': module_classes(), } init_config(build_options=build_options) easybuild.tools.build_log.EXPERIMENTAL = True ec = EasyConfig(ecpath) self.assertEqual(ec.dependencies()[1]['full_mod_name'], 'fftw/3.3.4.0') self.assertEqual(ec.dependencies()[1]['external_module_metadata'], metadata)
def process_easyconfig(path, onlyBlocks=None, regtest_online=False, validate=True): """ Process easyconfig, returning some information for each block """ blocks = retrieve_blocks_in_spec(path, onlyBlocks) easyconfigs = [] for spec in blocks: # process for dependencies and real installversionname # - use mod? __init__ and importCfg are ignored. _log.debug("Processing easyconfig %s" % spec) # create easyconfig try: all_stops = [x[0] for x in EasyBlock.get_steps()] ec = EasyConfig(spec, validate=validate, valid_module_classes=module_classes(), valid_stops=all_stops) except EasyBuildError, err: msg = "Failed to process easyconfig %s:\n%s" % (spec, err.msg) _log.exception(msg) name = ec['name'] # this app will appear as following module in the list easyconfig = { 'ec': ec, 'spec': spec, 'module': det_full_module_name(ec), 'dependencies': [], 'builddependencies': [], } if len(blocks) > 1: easyconfig['originalSpec'] = path # add build dependencies for dep in ec.builddependencies(): _log.debug("Adding build dependency %s for app %s." % (dep, name)) easyconfig['builddependencies'].append(dep) # add dependencies (including build dependencies) for dep in ec.dependencies(): _log.debug("Adding dependency %s for app %s." % (dep, name)) easyconfig['dependencies'].append(dep) # add toolchain as dependency too if ec.toolchain.name != DUMMY_TOOLCHAIN_NAME: dep = ec.toolchain.as_dict() _log.debug("Adding toolchain %s as dependency for app %s." % (dep, name)) easyconfig['dependencies'].append(dep) del ec # this is used by the parallel builder easyconfig['unresolved_deps'] = copy.deepcopy(easyconfig['dependencies']) easyconfigs.append(easyconfig)
def runTest(self): """ test all possible ways of specifying dependencies """ eb = EasyConfig(self.eb_file, valid_stops=self.all_stops) # should include builddependencies self.assertEqual(len(eb.dependencies()), 4) self.assertEqual(len(eb.builddependencies()), 2) first = eb.dependencies()[0] second = eb.dependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') # same tests for builddependencies first = eb.builddependencies()[0] second = eb.builddependencies()[1] self.assertEqual(first['name'], "first") self.assertEqual(second['name'], "second") self.assertEqual(first['version'], "1.1") self.assertEqual(second['version'], "2.2") self.assertEqual(first['tc'], '1.1-GCC-4.6.3') self.assertEqual(second['tc'], '2.2-GCC-4.6.3') eb['dependencies'] = ["wrong type"] self.assertErrorRegex(EasyBuildError, "wrong type from unsupported type", eb.dependencies) eb['dependencies'] = [()] self.assertErrorRegex(EasyBuildError, "without name", eb.dependencies) eb['dependencies'] = [{'name': "test"}] self.assertErrorRegex(EasyBuildError, "without version", eb.dependencies)
def process_easyconfig(path, onlyBlocks=None, regtest_online=False, validate=True): """ Process easyconfig, returning some information for each block """ blocks = retrieve_blocks_in_spec(path, onlyBlocks) easyconfigs = [] for spec in blocks: # process for dependencies and real installversionname # - use mod? __init__ and importCfg are ignored. log.debug("Processing easyconfig %s" % spec) # create easyconfig try: all_stops = [x[0] for x in EasyBlock.get_steps()] ec = EasyConfig(spec, validate=validate, valid_module_classes=module_classes(), valid_stops=all_stops) except EasyBuildError, err: msg = "Failed to process easyconfig %s:\n%s" % (spec, err.msg) log.exception(msg) name = ec['name'] # this app will appear as following module in the list easyconfig = { 'spec': spec, 'module': (ec.name, ec.get_installversion()), 'dependencies': [] } if len(blocks) > 1: easyconfig['originalSpec'] = path for d in ec.dependencies(): dep = (d['name'], d['tc']) log.debug("Adding dependency %s for app %s." % (dep, name)) easyconfig['dependencies'].append(dep) if ec.toolchain.name != 'dummy': dep = (ec.toolchain.name, ec.toolchain.version) log.debug("Adding toolchain %s as dependency for app %s." % (dep, name)) easyconfig['dependencies'].append(dep) del ec # this is used by the parallel builder easyconfig['unresolvedDependencies'] = copy.copy(easyconfig['dependencies']) easyconfigs.append(easyconfig)
def test_obtain_easyconfig(self): """test obtaining an easyconfig file given certain specifications""" tcname = 'GCC' tcver = '4.3.2' patches = ["one.patch"] # prepare a couple of eb files to test again fns = ["pi-3.14.eb", "pi-3.13-GCC-4.3.2.eb", "pi-3.15-GCC-4.3.2.eb", "pi-3.15-GCC-4.4.5.eb", "foo-1.2.3-GCC-4.3.2.eb"] eb_files = [(fns[0], "\n".join(['name = "pi"', 'version = "3.12"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "dummy", "version": "dummy"}', 'patches = %s' % patches ])), (fns[1], "\n".join(['name = "pi"', 'version = "3.13"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'patches = %s' % patches ])), (fns[2], "\n".join(['name = "pi"', 'version = "3.15"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'patches = %s' % patches ])), (fns[3], "\n".join(['name = "pi"', 'version = "3.15"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "4.5.1"}' % tcname, 'patches = %s' % patches ])), (fns[4], "\n".join(['name = "foo"', 'version = "1.2.3"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'foo_extra1 = "bar"', ])) ] self.ec_dir = tempfile.mkdtemp() for (fn, txt) in eb_files: write_file(os.path.join(self.ec_dir, fn), txt) # should crash when no suited easyconfig file (or template) is available specs = {'name': 'nosuchsoftware'} error_regexp = ".*No easyconfig files found for software %s, and no templates available. I'm all out of ideas." % specs['name'] self.assertErrorRegex(EasyBuildError, error_regexp, obtain_ec_for, specs, [self.ec_dir], None) # should find matching easyconfig file specs = {'name': 'foo', 'version': '1.2.3'} res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], False) self.assertEqual(res[1], os.path.join(self.ec_dir, fns[-1])) # should not pick between multiple available toolchain names name = "pi" ver = "3.12" suff = "mysuff" specs.update({ 'name': name, 'version': ver, 'versionsuffix': suff }) error_regexp = ".*No toolchain name specified, and more than one available: .*" self.assertErrorRegex(EasyBuildError, error_regexp, obtain_ec_for, specs, [self.ec_dir], None) # should be able to generate an easyconfig file that slightly differs ver = '3.16' specs.update({ 'toolchain_name': tcname, 'toolchain_version': tcver, 'version': ver, 'foo': 'bar123' }) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[1], "%s-%s-%s-%s%s.eb" % (name, ver, tcname, tcver, suff)) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['name'], specs['name']) self.assertEqual(ec['version'], specs['version']) self.assertEqual(ec['versionsuffix'], specs['versionsuffix']) self.assertEqual(ec['toolchain'], {'name': tcname, 'version': tcver}) # can't check for key 'foo', because EasyConfig ignores parameter names it doesn't know about txt = read_file(res[1]) self.assertTrue(re.search('foo = "%s"' % specs['foo'], txt)) os.remove(res[1]) # should pick correct version, i.e. not newer than what's specified, if a choice needs to be made ver = '3.14' specs.update({'version': ver}) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['version'], specs['version']) txt = read_file(res[1]) self.assertTrue(re.search("version = [\"']%s[\"'] .*was: [\"']3.13[\"']" % ver, txt)) os.remove(res[1]) # should pick correct toolchain version as well, i.e. now newer than what's specified, if a choice needs to be made specs.update({ 'version': '3.15', 'toolchain_version': '4.4.5', }) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['version'], specs['version']) self.assertEqual(ec['toolchain']['version'], specs['toolchain_version']) txt = read_file(res[1]) pattern = "toolchain = .*version.*[\"']%s[\"'].*was: .*version.*[\"']%s[\"']" % (specs['toolchain_version'], tcver) self.assertTrue(re.search(pattern, txt)) os.remove(res[1]) # should be able to prepend to list of patches and handle list of dependencies new_patches = ['two.patch', 'three.patch'] specs.update({ 'patches': new_patches[:], 'dependencies': [('foo', '1.2.3'), ('bar', '666', '-bleh', ('gompi', '1.4.10'))], 'hiddendependencies': [('test', '3.2.1')], }) parsed_deps = [ { 'name': 'foo', 'version': '1.2.3', 'versionsuffix': '', 'toolchain': ec['toolchain'], 'dummy': False, 'short_mod_name': 'foo/1.2.3-GCC-4.4.5', 'full_mod_name': 'foo/1.2.3-GCC-4.4.5', 'hidden': False, }, { 'name': 'bar', 'version': '666', 'versionsuffix': '-bleh', 'toolchain': {'name': 'gompi', 'version': '1.4.10'}, 'dummy': False, 'short_mod_name': 'bar/666-gompi-1.4.10-bleh', 'full_mod_name': 'bar/666-gompi-1.4.10-bleh', 'hidden': False, }, { 'name': 'test', 'version': '3.2.1', 'versionsuffix': '', 'toolchain': ec['toolchain'], 'dummy': False, 'short_mod_name': 'test/.3.2.1-GCC-4.4.5', 'full_mod_name': 'test/.3.2.1-GCC-4.4.5', 'hidden': True, }, ] res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], specs['patches']) self.assertEqual(ec.dependencies(), parsed_deps) os.remove(res[1]) # verify append functionality for lists specs['patches'].insert(0, '') res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], patches + new_patches) specs['patches'].remove('') os.remove(res[1]) # verify prepend functionality for lists specs['patches'].append('') res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], new_patches + patches) os.remove(res[1]) # should use supplied filename fn = "my.eb" res = obtain_ec_for(specs, [self.ec_dir], fn) self.assertEqual(res[0], True) self.assertEqual(res[1], fn) os.remove(res[1]) # should use a template if it's there tpl_path = os.path.join("share", "easybuild", "easyconfigs", "TEMPLATE.eb") def trim_path(path): dirs = path.split(os.path.sep) if len(dirs) > 3 and 'site-packages' in dirs: if path.endswith('.egg'): path = os.path.join(*dirs[:-4]) # strip of lib/python2.7/site-packages/*.egg part else: path = os.path.join(*dirs[:-3]) # strip of lib/python2.7/site-packages part return path tpl_full_path = find_full_path(tpl_path, trim=trim_path) # only run this test if the TEMPLATE.eb file is available # TODO: use unittest.skip for this (but only works from Python 2.7) if tpl_full_path: shutil.copy2(tpl_full_path, self.ec_dir) specs.update({'name': 'nosuchsoftware'}) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['name'], specs['name']) os.remove(res[1]) # cleanup shutil.rmtree(self.ec_dir)
def test_robot_find_minimal_toolchain_of_dependency(self): """Test robot_find_minimal_toolchain_of_dependency.""" # replace log.experimental with log.warning to allow experimental code easybuild.framework.easyconfig.tools._log.experimental = easybuild.framework.easyconfig.tools._log.warning test_easyconfigs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs') init_config(build_options={ 'valid_module_classes': module_classes(), 'robot_path': test_easyconfigs, }) # # First test that it can do basic resolution # gzip15 = { 'name': 'gzip', 'version': '1.5', 'versionsuffix': '', 'toolchain': {'name': 'goolf', 'version': '1.4.10'}, } get_toolchain_hierarchy.clear() new_gzip15_toolchain = robot_find_minimal_toolchain_of_dependency(gzip15, self.modtool) self.assertEqual(new_gzip15_toolchain, gzip15['toolchain']) # no easyconfig for gzip 1.4 with matching non-dummy (sub)toolchain gzip14 = { 'name': 'gzip', 'version': '1.4', 'versionsuffix': '', 'toolchain': {'name': 'goolf', 'version': '1.4.10'}, } get_toolchain_hierarchy.clear() self.assertEqual(robot_find_minimal_toolchain_of_dependency(gzip14, self.modtool), None) gzip14['toolchain'] = {'name': 'gompi', 'version': '1.4.10'} # # Second test also including dummy toolchain # init_config(build_options={ 'add_dummy_to_minimal_toolchains': True, 'valid_module_classes': module_classes(), 'robot_path': test_easyconfigs, }) # specify alternative parent toolchain gompi_1410 = {'name': 'gompi', 'version': '1.4.10'} get_toolchain_hierarchy.clear() new_gzip14_toolchain = robot_find_minimal_toolchain_of_dependency(gzip14, self.modtool, parent_tc=gompi_1410) self.assertTrue(new_gzip14_toolchain != gzip14['toolchain']) self.assertEqual(new_gzip14_toolchain, {'name': 'dummy', 'version': ''}) # default: use toolchain from dependency gzip14['toolchain'] = gompi_1410 get_toolchain_hierarchy.clear() new_gzip14_toolchain = robot_find_minimal_toolchain_of_dependency(gzip14, self.modtool) self.assertTrue(new_gzip14_toolchain != gzip14['toolchain']) self.assertEqual(new_gzip14_toolchain, {'name': 'dummy', 'version': ''}) # check reversed order (parent tc first) and skipping of parent tc itself dep = { 'name': 'SQLite', 'version': '3.8.10.2', 'toolchain': {'name': 'goolf', 'version': '1.4.10'}, } res = robot_find_minimal_toolchain_of_dependency(dep, self.modtool) self.assertEqual(res, {'name': 'GCC', 'version': '4.7.2'}) res = robot_find_minimal_toolchain_of_dependency(dep, self.modtool, parent_first=True) self.assertEqual(res, {'name': 'goolf', 'version': '1.4.10'}) # # Finally test if it can recognise existing modules and use those # barec = os.path.join(self.test_prefix, 'bar-1.2.3-goolf-1.4.10.eb') barec_txt = '\n'.join([ "easyblock = 'ConfigureMake'", "name = 'bar'", "version = '1.2.3'", "homepage = 'http://example.com'", "description = 'foo'", "toolchain = {'name': 'goolf', 'version': '1.4.10'}", # deliberately listing components of toolchain as dependencies without specifying subtoolchains, # to test resolving of dependencies with minimal toolchain # for each of these, we know test easyconfigs are available (which are required here) "dependencies = [", " ('OpenMPI', '1.6.4'),", # available with GCC/4.7.2 " ('OpenBLAS', '0.2.6', '-LAPACK-3.4.2'),", # available with gompi/1.4.10 " ('ScaLAPACK', '2.0.2', '-OpenBLAS-0.2.6-LAPACK-3.4.2'),", # available with gompi/1.4.10 " ('SQLite', '3.8.10.2'),", # available with goolf/1.4.10, gompi/1.4.10 and GCC/4.7.2 "]", ]) write_file(barec, barec_txt) # check without --minimal-toolchains init_config(build_options={ 'valid_module_classes': module_classes(), 'robot_path': test_easyconfigs, }) bar = EasyConfig(barec) expected_dep_versions = [ '1.6.4-GCC-4.7.2', '0.2.6-gompi-1.4.10-LAPACK-3.4.2', '2.0.2-gompi-1.4.10-OpenBLAS-0.2.6-LAPACK-3.4.2', '3.8.10.2-goolf-1.4.10', ] for dep, expected_dep_version in zip(bar.dependencies(), expected_dep_versions): self.assertEqual(det_full_ec_version(dep), expected_dep_version) # check with --minimal-toolchains enabled init_config(build_options={ 'minimal_toolchains': True, 'valid_module_classes': module_classes(), 'robot_path': test_easyconfigs, }) bar = EasyConfig(barec) # check that all bar dependencies have been processed as expected expected_dep_versions[-1] = '3.8.10.2-GCC-4.7.2' for dep, expected_dep_version in zip(bar.dependencies(), expected_dep_versions): self.assertEqual(det_full_ec_version(dep), expected_dep_version) # Add the gompi/1.4.10 version of SQLite as an available module module_parent = os.path.join(self.test_prefix, 'minimal_toolchain_modules') module_file = os.path.join(module_parent, 'SQLite', '3.8.10.2-gompi-1.4.10') module_txt = '\n'.join([ "#%Module", "set root /tmp/SQLite/3.8.10.2", "setenv EBROOTSQLITE $root", "setenv EBVERSIONSQLITE 3.8.10.2", "setenv EBDEVELSQLITE $root/easybuild/SQLite-3.8.10.2-easybuild-devel", ]) write_file(module_file, module_txt) os.environ['MODULEPATH'] = module_parent # Add the parent directory to the MODULEPATH invalidate_module_caches_for(module_parent) # Reinitialize the environment for the updated MODULEPATH and use_existing_modules init_config(build_options={ 'minimal_toolchains': True, 'use_existing_modules': True, 'valid_module_classes': module_classes(), 'robot_path': test_easyconfigs, }) # Check gompi is now being picked up bar = EasyConfig(barec) # Re-parse the parent easyconfig sqlite = bar.dependencies()[3] self.assertEqual(det_full_ec_version(sqlite), '3.8.10.2-gompi-1.4.10') # Add the goolf version as an available version and check that gets precedence over the gompi version module_file = os.path.join(module_parent, 'SQLite', '3.8.10.2-goolf-1.4.10') write_file(module_file, module_txt) invalidate_module_caches_for(module_parent) bar = EasyConfig(barec) # Re-parse the parent easyconfig sqlite = bar.dependencies()[3] self.assertEqual(det_full_ec_version(sqlite), '3.8.10.2-goolf-1.4.10')
def test_obtain_easyconfig(self): """test obtaining an easyconfig file given certain specifications""" tcname = 'GCC' tcver = '4.3.2' patches = ["one.patch"] # prepare a couple of eb files to test again fns = ["pi-3.14.eb", "pi-3.13-GCC-4.3.2.eb", "pi-3.15-GCC-4.3.2.eb", "pi-3.15-GCC-4.4.5.eb", "foo-1.2.3-GCC-4.3.2.eb"] eb_files = [(fns[0], "\n".join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.12"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "dummy", "version": "dummy"}', 'patches = %s' % patches ])), (fns[1], "\n".join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.13"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'patches = %s' % patches ])), (fns[2], "\n".join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.15"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'patches = %s' % patches ])), (fns[3], "\n".join([ 'easyblock = "ConfigureMake"', 'name = "pi"', 'version = "3.15"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "4.5.1"}' % tcname, 'patches = %s' % patches ])), (fns[4], "\n".join([ 'easyblock = "ConfigureMake"', 'name = "foo"', 'version = "1.2.3"', 'homepage = "http://example.com"', 'description = "test easyconfig"', 'toolchain = {"name": "%s", "version": "%s"}' % (tcname, tcver), 'foo_extra1 = "bar"', ])) ] self.ec_dir = tempfile.mkdtemp() for (fn, txt) in eb_files: write_file(os.path.join(self.ec_dir, fn), txt) # should crash when no suited easyconfig file (or template) is available specs = {'name': 'nosuchsoftware'} error_regexp = ".*No easyconfig files found for software %s, and no templates available. I'm all out of ideas." % specs['name'] self.assertErrorRegex(EasyBuildError, error_regexp, obtain_ec_for, specs, [self.ec_dir], None) # should find matching easyconfig file specs = { 'name': 'foo', 'version': '1.2.3' } res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], False) self.assertEqual(res[1], os.path.join(self.ec_dir, fns[-1])) # should not pick between multiple available toolchain names name = "pi" ver = "3.12" suff = "mysuff" specs.update({ 'name': name, 'version': ver, 'versionsuffix': suff }) error_regexp = ".*No toolchain name specified, and more than one available: .*" self.assertErrorRegex(EasyBuildError, error_regexp, obtain_ec_for, specs, [self.ec_dir], None) # should be able to generate an easyconfig file that slightly differs ver = '3.16' specs.update({ 'toolchain_name': tcname, 'toolchain_version': tcver, 'version': ver, 'start_dir': 'bar123' }) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[1], "%s-%s-%s-%s%s.eb" % (name, ver, tcname, tcver, suff)) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['name'], specs['name']) self.assertEqual(ec['version'], specs['version']) self.assertEqual(ec['versionsuffix'], specs['versionsuffix']) self.assertEqual(ec['toolchain'], {'name': tcname, 'version': tcver}) self.assertEqual(ec['start_dir'], specs['start_dir']) os.remove(res[1]) specs.update({ 'foo': 'bar123' }) self.assertErrorRegex(EasyBuildError, "Unkown easyconfig parameter: foo", obtain_ec_for, specs, [self.ec_dir], None) del specs['foo'] # should pick correct version, i.e. not newer than what's specified, if a choice needs to be made ver = '3.14' specs.update({'version': ver}) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['version'], specs['version']) txt = read_file(res[1]) self.assertTrue(re.search("^version = [\"']%s[\"']$" % ver, txt, re.M)) os.remove(res[1]) # should pick correct toolchain version as well, i.e. now newer than what's specified, if a choice needs to be made specs.update({ 'version': '3.15', 'toolchain_version': '4.4.5', }) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['version'], specs['version']) self.assertEqual(ec['toolchain']['version'], specs['toolchain_version']) txt = read_file(res[1]) pattern = "^toolchain = .*version.*[\"']%s[\"'].*}$" % specs['toolchain_version'] self.assertTrue(re.search(pattern, txt, re.M)) os.remove(res[1]) # should be able to prepend to list of patches and handle list of dependencies new_patches = ['two.patch', 'three.patch'] specs.update({ 'patches': new_patches[:], 'dependencies': [('foo', '1.2.3'), ('bar', '666', '-bleh', ('gompi', '1.4.10'))], 'hiddendependencies': [('test', '3.2.1')], }) parsed_deps = [ { 'name': 'foo', 'version': '1.2.3', 'versionsuffix': '', 'toolchain': ec['toolchain'], 'dummy': False, 'short_mod_name': 'foo/1.2.3-GCC-4.4.5', 'full_mod_name': 'foo/1.2.3-GCC-4.4.5', 'hidden': False, 'external_module': False, 'external_module_metadata': {}, }, { 'name': 'bar', 'version': '666', 'versionsuffix': '-bleh', 'toolchain': {'name': 'gompi', 'version': '1.4.10'}, 'dummy': False, 'short_mod_name': 'bar/666-gompi-1.4.10-bleh', 'full_mod_name': 'bar/666-gompi-1.4.10-bleh', 'hidden': False, 'external_module': False, 'external_module_metadata': {}, }, { 'name': 'test', 'version': '3.2.1', 'versionsuffix': '', 'toolchain': ec['toolchain'], 'dummy': False, 'short_mod_name': 'test/.3.2.1-GCC-4.4.5', 'full_mod_name': 'test/.3.2.1-GCC-4.4.5', 'hidden': True, 'external_module': False, 'external_module_metadata': {}, }, ] # hidden dependencies must be included in list of dependencies res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) error_pattern = "Hidden dependencies with visible module names .* not in list of dependencies: .*" self.assertErrorRegex(EasyBuildError, error_pattern, EasyConfig, res[1]) specs['dependencies'].append(('test', '3.2.1')) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], specs['patches']) self.assertEqual(ec.dependencies(), parsed_deps) # hidden dependencies are filtered from list of dependencies self.assertFalse('test/3.2.1-GCC-4.4.5' in [d['full_mod_name'] for d in ec['dependencies']]) self.assertTrue('test/.3.2.1-GCC-4.4.5' in [d['full_mod_name'] for d in ec['hiddendependencies']]) os.remove(res[1]) # hidden dependencies are also filtered from list of dependencies when validation is skipped res = obtain_ec_for(specs, [self.ec_dir], None) ec = EasyConfig(res[1], validate=False) self.assertFalse('test/3.2.1-GCC-4.4.5' in [d['full_mod_name'] for d in ec['dependencies']]) self.assertTrue('test/.3.2.1-GCC-4.4.5' in [d['full_mod_name'] for d in ec['hiddendependencies']]) os.remove(res[1]) # verify append functionality for lists specs['patches'].insert(0, '') res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], patches + new_patches) specs['patches'].remove('') os.remove(res[1]) # verify prepend functionality for lists specs['patches'].append('') res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['patches'], new_patches + patches) os.remove(res[1]) # should use supplied filename fn = "my.eb" res = obtain_ec_for(specs, [self.ec_dir], fn) self.assertEqual(res[0], True) self.assertEqual(res[1], fn) os.remove(res[1]) # should use a template if it's there tpl_path = os.path.join("share", "easybuild", "easyconfigs", "TEMPLATE.eb") def trim_path(path): dirs = path.split(os.path.sep) if len(dirs) > 3 and 'site-packages' in dirs: if path.endswith('.egg'): path = os.path.join(*dirs[:-4]) # strip of lib/python2.7/site-packages/*.egg part else: path = os.path.join(*dirs[:-3]) # strip of lib/python2.7/site-packages part return path tpl_full_path = find_full_path(tpl_path, trim=trim_path) # only run this test if the TEMPLATE.eb file is available # TODO: use unittest.skip for this (but only works from Python 2.7) if tpl_full_path: shutil.copy2(tpl_full_path, self.ec_dir) specs.update({'name': 'nosuchsoftware'}) res = obtain_ec_for(specs, [self.ec_dir], None) self.assertEqual(res[0], True) ec = EasyConfig(res[1]) self.assertEqual(ec['name'], specs['name']) os.remove(res[1]) # cleanup shutil.rmtree(self.ec_dir)