def build_and_install_software(module, options, origEnviron, exitOnFailure=True, silent=False): """ Build the software """ spec = module['spec'] print_msg("processing EasyBuild easyconfig %s" % spec, log=_log, silent=silent) # restore original environment _log.info("Resetting environment") filetools.errorsFoundInLog = 0 modify_env(os.environ, origEnviron) cwd = os.getcwd() # load easyblock easyblock = options.easyblock if not easyblock: # try to look in .eb file reg = re.compile(r"^\s*easyblock\s*=(.*)$") txt = read_file(spec) for line in txt.split('\n'): match = reg.search(line) if match: easyblock = eval(match.group(1)) break name = module['module'][0] try: app_class = get_class(easyblock, name=name) app = app_class(spec, debug=options.debug, robot_path=options.robot) _log.info("Obtained application instance of for %s (easyblock: %s)" % (name, easyblock)) except EasyBuildError, err: print_error("Failed to get application instance for %s (easyblock: %s): %s" % (name, easyblock, err.msg), silent=silent)
def obtain_path(specs, paths, try_to_generate=False, exit_on_error=True, silent=False): """Obtain a path for an easyconfig that matches the given specifications.""" # if no easyconfig files/paths were provided, but we did get a software name, # we can try and find a suitable easyconfig ourselves, or generate one if we can (generated, fn) = easyconfig.tools.obtain_ec_for(specs, paths, None) if not generated: return (fn, generated) else: # if an easyconfig was generated, make sure we're allowed to use it if try_to_generate: print_msg("Generated an easyconfig file %s, going to use it now..." % fn, silent=silent) return (fn, generated) else: try: os.remove(fn) except OSError, err: print_warning("Failed to remove generated easyconfig file %s." % fn) print_error( ( "Unable to find an easyconfig for the given specifications: %s; " "to make EasyBuild try to generate a matching easyconfig, " "use the --try-X options " ) % specs, log=_log, exit_on_error=exit_on_error, )
def obtain_path(specs, paths, try_to_generate=False, exit_on_error=True, silent=False): """Obtain a path for an easyconfig that matches the given specifications.""" # if no easyconfig files/paths were provided, but we did get a software name, # we can try and find a suitable easyconfig ourselves, or generate one if we can (generated, fn) = obtain_ec_for(specs, paths, None) if not generated: return (fn, generated) else: # if an easyconfig was generated, make sure we're allowed to use it if try_to_generate: print_msg( "Generated an easyconfig file %s, going to use it now..." % fn, silent=silent) return (fn, generated) else: try: os.remove(fn) except OSError, err: print_warning( "Failed to remove generated easyconfig file %s: %s" % (fn, err)) print_error(( "Unable to find an easyconfig for the given specifications: %s; " "to make EasyBuild try to generate a matching easyconfig, " "use the --try-X options ") % specs, log=_log, exit_on_error=exit_on_error)
def build_and_install_software(module, options, origEnviron, exitOnFailure=True, silent=False): """ Build the software """ spec = module['spec'] print_msg("processing EasyBuild easyconfig %s" % spec, log=_log, silent=silent) # restore original environment _log.info("Resetting environment") filetools.errorsFoundInLog = 0 modify_env(os.environ, origEnviron) cwd = os.getcwd() # load easyblock easyblock = options.easyblock if not easyblock: # try to look in .eb file reg = re.compile(r"^\s*easyblock\s*=(.*)$") txt = read_file(spec) for line in txt.split('\n'): match = reg.search(line) if match: easyblock = eval(match.group(1)) break name = module['module'][0] try: app_class = get_class(easyblock, name=name) app = app_class(spec, debug=options.debug, robot_path=options.robot) _log.info("Obtained application instance of for %s (easyblock: %s)" % (name, easyblock)) except EasyBuildError, err: print_error("Failed to get application instance for %s (easyblock: %s): %s" % (name, easyblock, err.msg), silent=silent)
def main(args=None, logfile=None, do_build=None, testing=False, modtool=None): """ Main function: parse command line options, and act accordingly. :param args: command line arguments to use :param logfile: log file to use :param do_build: whether or not to actually perform the build :param testing: enable testing mode """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set by option parsers via set_tmpdir eb_tmpdir = tempfile.gettempdir() search_query = options.search or options.search_filename or options.search_short # initialise logging for main global _log _log, logfile = init_logging(logfile, logtostdout=options.logtostdout, silent=(testing or options.terse or search_query), colorize=options.color) # disallow running EasyBuild as root if os.getuid() == 0: raise EasyBuildError("You seem to be running EasyBuild with root privileges which is not wise, " "so let's end this here.") # log startup info eb_cmd_line = eb_go.generate_cmd_line() + eb_go.args log_start(eb_cmd_line, eb_tmpdir) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) # determine robot path # --try-X, --dep-graph, --search use robot path for searching, so enable it with path of installed easyconfigs tweaked_ecs = try_to_generate and build_specs tweaked_ecs_paths, pr_path = alt_easyconfig_paths(eb_tmpdir, tweaked_ecs=tweaked_ecs, from_pr=options.from_pr) auto_robot = try_to_generate or options.check_conflicts or options.dep_graph or search_query robot_path = det_robot_path(options.robot_paths, tweaked_ecs_paths, pr_path, auto_robot=auto_robot) _log.debug("Full robot path: %s" % robot_path) # configure & initialize build options config_options_dict = eb_go.get_options_by_section('config') build_options = { 'build_specs': build_specs, 'command_line': eb_cmd_line, 'external_modules_metadata': parse_external_modules_metadata(options.external_modules_metadata), 'pr_path': pr_path, 'robot_path': robot_path, 'silent': testing, 'try_to_generate': try_to_generate, 'valid_stops': [x[0] for x in EasyBlock.get_steps()], } # initialise the EasyBuild configuration & build options config.init(options, config_options_dict) config.init_build_options(build_options=build_options, cmdline_options=options) if modtool is None: modtool = modules_tool(testing=testing) if options.last_log: # print location to last log file, and exit last_log = find_last_log(logfile) or '(none)' print_msg(last_log, log=_log, prefix=False) # check whether packaging is supported when it's being used if options.package: check_pkg_support() else: _log.debug("Packaging not enabled, so not checking for packaging support.") # search for easyconfigs, if a query is specified if search_query: search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename, terse=options.terse) # GitHub options that warrant a silent cleanup & exit if options.check_github: check_github() elif options.install_github_token: install_github_token(options.github_user, silent=build_option('silent')) elif options.review_pr: print review_pr(options.review_pr, colored=use_color(options.color)) elif options.list_installed_software: detailed = options.list_installed_software == 'detailed' print list_software(output_format=options.output_format, detailed=detailed, only_installed=True) elif options.list_software: print list_software(output_format=options.output_format, detailed=options.list_software == 'detailed') # non-verbose cleanup after handling GitHub integration stuff or printing terse info early_stop_options = [ options.check_github, options.install_github_token, options.list_installed_software, options.list_software, options.review_pr, options.terse, search_query, ] if any(early_stop_options): cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = modtool.list() # build options must be initialized first before 'module list' works init_session_state.update({'easybuild_configuration': eb_config}) init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning("Failed to determine install path for easybuild-easyconfigs package.") if options.install_latest_eb_release: if orig_paths: raise EasyBuildError("Installing the latest EasyBuild release can not be combined with installing " "other easyconfigs") else: eb_file = find_easybuild_easyconfig() orig_paths.append(eb_file) categorized_paths = categorize_files_by_type(orig_paths) # command line options that do not require any easyconfigs to be specified no_ec_opts = [options.aggregate_regtest, options.new_pr, options.regtest, options.update_pr, search_query] # determine paths to easyconfigs paths = det_easyconfig_paths(categorized_paths['easyconfigs']) if paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in paths] else: if 'name' in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif not any(no_ec_opts): print_error(("Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 if options.check_style: _log.debug("Running style check...") if cmdline_easyconfigs_style_check([path[0] for path in paths]): print_msg("All style checks passed!", prefix=False) cleanup(logfile, eb_tmpdir, testing) sys.exit(0) else: raise EasyBuildError("One or more style checks FAILED!") # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs(paths) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, modtool, targetdirs=tweaked_ecs_paths) dry_run_mode = options.dry_run or options.dry_run_short new_update_pr = options.new_pr or options.update_pr # skip modules that are already installed unless forced if not (options.force or options.rebuild or dry_run_mode or options.extended_dry_run or new_update_pr): retained_ecs = skip_available(easyconfigs, modtool) if not testing: for skipped_ec in [ec for ec in easyconfigs if ec not in retained_ecs]: print_msg("%s is already installed (module found), skipping" % skipped_ec['full_mod_name']) easyconfigs = retained_ecs # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: # resolve dependencies if robot is enabled, except in dry run mode # one exception: deps *are* resolved with --new-pr or --update-pr when dry run mode is enabled if options.robot and (not dry_run_mode or new_update_pr): print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies(easyconfigs, modtool) else: ordered_ecs = easyconfigs elif new_update_pr: ordered_ecs = None else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] # creating/updating PRs if new_update_pr: if options.new_pr: new_pr(categorized_paths, ordered_ecs, title=options.pr_title, descr=options.pr_descr, commit_msg=options.pr_commit_msg) else: update_pr(options.update_pr, categorized_paths, ordered_ecs, commit_msg=options.pr_commit_msg) cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # dry_run: print all easyconfigs and dependencies, and whether they are already built elif dry_run_mode: txt = dry_run(easyconfigs, modtool, short=not options.dry_run) print_msg(txt, log=_log, silent=testing, prefix=False) elif options.check_conflicts: if check_conflicts(easyconfigs, modtool): print_error("One or more conflicts detected!") sys.exit(1) else: print_msg("\nNo conflicts detected!\n", prefix=False) # dump source script to set up build environment elif options.dump_env_script: dump_env_script(easyconfigs) # cleanup and exit after dry run, searching easyconfigs or submitting regression test if any(no_ec_opts + [options.check_conflicts, dry_run_mode, options.dump_env_script]): cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # submit build as job(s), clean up and exit if options.job: submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now") cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # build software, will exit when errors occurs (except when testing) exit_on_failure = not options.dump_test_report and not options.upload_test_report if not testing or (testing and do_build): ecs_with_res = build_and_install_software(ordered_ecs, init_session_state, exit_on_failure=exit_on_failure) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False)]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
correct_builds_cnt = len([ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False)]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing) if __name__ == "__main__": try: main() except EasyBuildError, e: print_error(e.msg)
def main(args=None, logfile=None, do_build=None, testing=False): """ Main function: parse command line options, and act accordingly. @param args: command line arguments to use @param logfile: log file to use @param do_build: whether or not to actually perform the build @param testing: enable testing mode """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set by option parsers via set_tmpdir eb_tmpdir = tempfile.gettempdir() # initialise logging for main global _log _log, logfile = init_logging(logfile, logtostdout=options.logtostdout, silent=testing or options.last_log) # disallow running EasyBuild as root if os.getuid() == 0: raise EasyBuildError( "You seem to be running EasyBuild with root privileges which is not wise, " "so let's end this here." ) # log startup info eb_cmd_line = eb_go.generate_cmd_line() + eb_go.args log_start(eb_cmd_line, eb_tmpdir) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) # determine robot path # --try-X, --dep-graph, --search use robot path for searching, so enable it with path of installed easyconfigs tweaked_ecs = try_to_generate and build_specs tweaked_ecs_path, pr_path = alt_easyconfig_paths(eb_tmpdir, tweaked_ecs=tweaked_ecs, from_pr=options.from_pr) auto_robot = try_to_generate or options.dep_graph or options.search or options.search_short robot_path = det_robot_path(options.robot_paths, tweaked_ecs_path, pr_path, auto_robot=auto_robot) _log.debug("Full robot path: %s" % robot_path) # configure & initialize build options config_options_dict = eb_go.get_options_by_section("config") build_options = { "build_specs": build_specs, "command_line": eb_cmd_line, "pr_path": pr_path, "robot_path": robot_path, "silent": testing, "try_to_generate": try_to_generate, "valid_stops": [x[0] for x in EasyBlock.get_steps()], } # initialise the EasyBuild configuration & build options config.init(options, config_options_dict) config.init_build_options(build_options=build_options, cmdline_options=options) if options.last_log: # print location to last log file, and exit last_log = find_last_log(logfile) or "(none)" print_msg(last_log, log=_log, prefix=False) cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # check whether packaging is supported when it's being used if options.package: check_pkg_support() else: _log.debug("Packaging not enabled, so not checking for packaging support.") # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = session_module_list(testing=testing) # build options must be initialized first before 'module list' works init_session_state.update({"easybuild_configuration": eb_config}) init_session_state.update({"module_list": modlist}) _log.debug("Initial session state: %s" % init_session_state) # GitHub integration if options.review_pr or options.new_pr or options.update_pr: if options.review_pr: print review_pr(options.review_pr, colored=options.color) elif options.new_pr: new_pr(orig_paths, title=options.pr_title, descr=options.pr_descr, commit_msg=options.pr_commit_msg) elif options.update_pr: update_pr(options.update_pr, orig_paths, commit_msg=options.pr_commit_msg) cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # search for easyconfigs, if a query is specified query = options.search or options.search_short if query: search_easyconfigs(query, short=not options.search) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning("Failed to determine install path for easybuild-easyconfigs package.") # command line options that do not require any easyconfigs to be specified no_ec_opts = [ options.aggregate_regtest, options.new_pr, options.review_pr, options.search, options.search_short, options.regtest, options.update_pr, ] # determine paths to easyconfigs paths = det_easyconfig_paths(orig_paths) if paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in paths] else: if "name" in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif not any(no_ec_opts): print_error( ( "Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs" ), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing, ) _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs(paths) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, targetdir=tweaked_ecs_path) # dry_run: print all easyconfigs and dependencies, and whether they are already built if options.dry_run or options.dry_run_short: txt = dry_run(easyconfigs, short=not options.dry_run) print_msg(txt, log=_log, silent=testing, prefix=False) # cleanup and exit after dry run, searching easyconfigs or submitting regression test if any(no_ec_opts + [options.dry_run, options.dry_run_short]): cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # skip modules that are already installed unless forced if not (options.force or options.rebuild or options.extended_dry_run): retained_ecs = skip_available(easyconfigs) if not testing: for skipped_ec in [ec for ec in easyconfigs if ec not in retained_ecs]: print_msg("%s is already installed (module found), skipping" % skipped_ec["full_mod_name"]) easyconfigs = retained_ecs # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: if options.robot: print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies( easyconfigs, minimal_toolchains=build_option("minimal_toolchains"), use_existing_modules=build_option("use_existing_modules"), ) else: ordered_ecs = easyconfigs else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) sys.exit(0) # submit build as job(s), clean up and exit if options.job: submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now") cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # build software, will exit when errors occurs (except when testing) exit_on_failure = not options.dump_test_report and not options.upload_test_report if not testing or (testing and do_build): ecs_with_res = build_and_install_software(ordered_ecs, init_session_state, exit_on_failure=exit_on_failure) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ec_res for (_, ec_res) in ecs_with_res if ec_res.get("success", False)]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if "original_spec" in ec and os.path.isfile(ec["spec"]): os.remove(ec["spec"]) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
def main(testing_data=(None, None)): """ Main function: @arg options: a tuple: (options, paths, logger, logfile, hn) as defined in parse_options This function will: - read easyconfig - build software """ # disallow running EasyBuild as root if os.getuid() == 0: sys.stderr.write("ERROR: You seem to be running EasyBuild with root privileges.\n" \ "That's not wise, so let's end this here.\n" \ "Exiting.\n") sys.exit(1) # steer behavior when testing main testing = testing_data[0] is not None args, logfile = testing_data # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # initialise logging for main if options.logtostdout: fancylogger.logToScreen(enable=True, stdout=True) else: if logfile is None: # mkstemp returns (fd,filename), fd is from os.open, not regular open! fd, logfile = tempfile.mkstemp(suffix='.log', prefix='easybuild-') os.close(fd) fancylogger.logToFile(logfile) print_msg('temporary log file in case of crash %s' % (logfile), log=None, silent=testing) global _log _log = fancylogger.getLogger(fname=False) # hello world! _log.info(this_is_easybuild()) # set strictness of filetools module if options.strict: filetools.strictness = options.strict if not options.robot is None: if options.robot: _log.info("Using robot path: %s" % options.robot) else: _log.error("No robot path specified, and unable to determine easybuild-easyconfigs install path.") # determine easybuild-easyconfigs package install path easyconfigs_paths = get_paths_for("easyconfigs", robot_path=options.robot) easyconfigs_pkg_full_path = None search_path = os.getcwd() if easyconfigs_paths: easyconfigs_pkg_full_path = easyconfigs_paths[0] if not options.robot: search_path = easyconfigs_pkg_full_path else: search_path = options.robot else: _log.info("Failed to determine install path for easybuild-easyconfigs package.") if options.robot: easyconfigs_paths = [options.robot] + easyconfigs_paths # initialise the easybuild configuration config.init(options, eb_go.get_options_by_section('config')) # search for easyconfigs if options.search: search_file(search_path, options.search, silent=testing) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, software_build_specs) = process_software_build_specs(options) paths = [] if len(orig_paths) == 0: if software_build_specs.has_key('name'): paths = [obtain_path(software_build_specs, easyconfigs_paths, try_to_generate=try_to_generate, exit_on_error=not testing)] elif not any([options.aggregate_regtest, options.search, options.regtest]): print_error(("Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) else: # look for easyconfigs with relative paths in easybuild-easyconfigs package, # unless they we found at the given relative paths if easyconfigs_pkg_full_path: # create a mapping from filename to path in easybuild-easyconfigs package install path easyconfigs_map = {} for (subpath, _, filenames) in os.walk(easyconfigs_pkg_full_path): for filename in filenames: easyconfigs_map.update({filename: os.path.join(subpath, filename)}) # try and find non-existing non-absolute eaysconfig paths in easybuild-easyconfigs package install path for idx, orig_path in enumerate(orig_paths): if not os.path.isabs(orig_path) and not os.path.exists(orig_path): if orig_path in easyconfigs_map: _log.info("Found %s in %s: %s" % (orig_path, easyconfigs_pkg_full_path, easyconfigs_map[orig_path])) orig_paths[idx] = easyconfigs_map[orig_path] # indicate that specified paths do not contain generated easyconfig files paths = [(path, False) for path in orig_paths] _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") if paths: regtest_ok = regtest(options, [path[0] for path in paths]) else: # fallback: easybuild-easyconfigs install path regtest_ok = regtest(options, [easyconfigs_pkg_full_path]) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 if any([options.search, options.regtest]): cleanup_logfile_and_exit(logfile, testing, True) # building a dependency graph implies force, so that all dependencies are retained # and also skips validation of easyconfigs (e.g. checking os dependencies) validate_easyconfigs = True retain_all_deps = False if options.dep_graph: _log.info("Enabling force to generate dependency graph.") options.force = True validate_easyconfigs = False retain_all_deps = True # read easyconfig files easyconfigs = [] for (path, generated) in paths: path = os.path.abspath(path) if not (os.path.exists(path)): print_error("Can't find path %s" % path) try: files = find_easyconfigs(path) for f in files: if not generated and try_to_generate and software_build_specs: ec_file = easyconfig.tools.tweak(f, None, software_build_specs) else: ec_file = f easyconfigs.extend(process_easyconfig(ec_file, options.only_blocks, validate=validate_easyconfigs)) except IOError, err: _log.error("Processing easyconfigs in path %s failed: %s" % (path, err))
except EasyBuildError, err: _log.warn("Unable to commit easyconfig to repository: %s", err) exitCode = 0 succ = "successfully" summary = "COMPLETED" # cleanup logs app.close_log() try: if not os.path.isdir(newLogDir): os.makedirs(newLogDir) applicationLog = os.path.join(newLogDir, get_log_filename(app.name, app.version)) shutil.move(app.logfile, applicationLog) except IOError, err: print_error("Failed to move log file %s to new log file %s: %s" % (app.logfile, applicationLog, err)) try: shutil.copy(spec, os.path.join(newLogDir, "%s-%s.eb" % (app.name, app.get_installversion()))) except IOError, err: print_error("Failed to move easyconfig %s to log dir %s: %s" % (spec, newLogDir, err)) # build failed else: exitCode = 1 summary = "FAILED" buildDir = "" if app.builddir: buildDir = " (build directory: %s)" % (app.builddir) succ = "unsuccessfully%s:\n%s" % (buildDir, errormsg)
def main(args=None, logfile=None, do_build=None, testing=False, modtool=None): """ Main function: parse command line options, and act accordingly. :param args: command line arguments to use :param logfile: log file to use :param do_build: whether or not to actually perform the build :param testing: enable testing mode """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set by option parsers via set_tmpdir eb_tmpdir = tempfile.gettempdir() search_query = options.search or options.search_filename or options.search_short # initialise logging for main global _log _log, logfile = init_logging(logfile, logtostdout=options.logtostdout, silent=(testing or options.terse or search_query), colorize=options.color) # disallow running EasyBuild as root (by default) check_root_usage( allow_use_as_root=options.allow_use_as_root_and_accept_consequences) # log startup info eb_cmd_line = eb_go.generate_cmd_line() + eb_go.args log_start(eb_cmd_line, eb_tmpdir) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) # determine robot path # --try-X, --dep-graph, --search use robot path for searching, so enable it with path of installed easyconfigs tweaked_ecs = try_to_generate and build_specs tweaked_ecs_paths, pr_path = alt_easyconfig_paths(eb_tmpdir, tweaked_ecs=tweaked_ecs, from_pr=options.from_pr) auto_robot = try_to_generate or options.check_conflicts or options.dep_graph or search_query robot_path = det_robot_path(options.robot_paths, tweaked_ecs_paths, pr_path, auto_robot=auto_robot) _log.debug("Full robot path: %s" % robot_path) # configure & initialize build options config_options_dict = eb_go.get_options_by_section('config') build_options = { 'build_specs': build_specs, 'command_line': eb_cmd_line, 'external_modules_metadata': parse_external_modules_metadata(options.external_modules_metadata), 'pr_path': pr_path, 'robot_path': robot_path, 'silent': testing, 'try_to_generate': try_to_generate, 'valid_stops': [x[0] for x in EasyBlock.get_steps()], } # initialise the EasyBuild configuration & build options config.init(options, config_options_dict) config.init_build_options(build_options=build_options, cmdline_options=options) if modtool is None: modtool = modules_tool(testing=testing) # check whether any (EasyBuild-generated) modules are loaded already in the current session modtool.check_loaded_modules() if options.last_log: # print location to last log file, and exit last_log = find_last_log(logfile) or '(none)' print_msg(last_log, log=_log, prefix=False) # check whether packaging is supported when it's being used if options.package: check_pkg_support() else: _log.debug( "Packaging not enabled, so not checking for packaging support.") # search for easyconfigs, if a query is specified if search_query: search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename, terse=options.terse) # GitHub options that warrant a silent cleanup & exit if options.check_github: check_github() elif options.install_github_token: install_github_token(options.github_user, silent=build_option('silent')) elif options.merge_pr: merge_pr(options.merge_pr) elif options.review_pr: print review_pr(pr=options.review_pr, colored=use_color(options.color)) elif options.list_installed_software: detailed = options.list_installed_software == 'detailed' print list_software(output_format=options.output_format, detailed=detailed, only_installed=True) elif options.list_software: print list_software(output_format=options.output_format, detailed=options.list_software == 'detailed') # non-verbose cleanup after handling GitHub integration stuff or printing terse info early_stop_options = [ options.check_github, options.install_github_token, options.list_installed_software, options.list_software, options.merge_pr, options.review_pr, options.terse, search_query, ] if any(early_stop_options): cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = modtool.list( ) # build options must be initialized first before 'module list' works init_session_state.update({'easybuild_configuration': eb_config}) init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning( "Failed to determine install path for easybuild-easyconfigs package." ) if options.install_latest_eb_release: if orig_paths: raise EasyBuildError( "Installing the latest EasyBuild release can not be combined with installing " "other easyconfigs") else: eb_file = find_easybuild_easyconfig() orig_paths.append(eb_file) categorized_paths = categorize_files_by_type(orig_paths) # command line options that do not require any easyconfigs to be specified new_update_preview_pr = options.new_pr or options.update_pr or options.preview_pr no_ec_opts = [ options.aggregate_regtest, options.regtest, search_query, new_update_preview_pr ] # determine paths to easyconfigs determined_paths = det_easyconfig_paths(categorized_paths['easyconfigs']) if determined_paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in determined_paths] else: if 'name' in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif any(no_ec_opts): paths = determined_paths else: print_error(( "Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 if options.check_style: _log.debug("Running style check...") if cmdline_easyconfigs_style_check([path[0] for path in paths]): print_msg("All style checks passed!", prefix=False) cleanup(logfile, eb_tmpdir, testing) sys.exit(0) else: raise EasyBuildError("One or more style checks FAILED!") # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs( paths, validate=not options.inject_checksums) # verify easyconfig filenames, if desired if options.verify_easyconfig_filenames: _log.info("Verifying easyconfig filenames...") for easyconfig in easyconfigs: verify_easyconfig_filename(easyconfig['spec'], easyconfig['ec'], parsed_ec=easyconfig['ec']) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, modtool, targetdirs=tweaked_ecs_paths) if options.containerize: containerize(easyconfigs) cleanup(logfile, eb_tmpdir, testing) sys.exit(0) forced = options.force or options.rebuild dry_run_mode = options.dry_run or options.dry_run_short # skip modules that are already installed unless forced, or unless an option is used that warrants not skipping if not (forced or dry_run_mode or options.extended_dry_run or new_update_preview_pr or options.inject_checksums): retained_ecs = skip_available(easyconfigs, modtool) if not testing: for skipped_ec in [ ec for ec in easyconfigs if ec not in retained_ecs ]: print_msg("%s is already installed (module found), skipping" % skipped_ec['full_mod_name']) easyconfigs = retained_ecs # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: # resolve dependencies if robot is enabled, except in dry run mode # one exception: deps *are* resolved with --new-pr or --update-pr when dry run mode is enabled if options.robot and (not dry_run_mode or new_update_preview_pr): print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies(easyconfigs, modtool) else: ordered_ecs = easyconfigs elif new_update_preview_pr: ordered_ecs = None else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] # creating/updating PRs if new_update_preview_pr: if options.new_pr: new_pr(categorized_paths, ordered_ecs, title=options.pr_title, descr=options.pr_descr, commit_msg=options.pr_commit_msg) elif options.preview_pr: print review_pr(paths=determined_paths, colored=use_color(options.color)) else: update_pr(options.update_pr, categorized_paths, ordered_ecs, commit_msg=options.pr_commit_msg) # dry_run: print all easyconfigs and dependencies, and whether they are already built elif dry_run_mode: txt = dry_run(easyconfigs, modtool, short=not options.dry_run) print_msg(txt, log=_log, silent=testing, prefix=False) elif options.check_conflicts: if check_conflicts(easyconfigs, modtool): print_error("One or more conflicts detected!") sys.exit(1) else: print_msg("\nNo conflicts detected!\n", prefix=False) # dump source script to set up build environment elif options.dump_env_script: dump_env_script(easyconfigs) elif options.inject_checksums: inject_checksums(ordered_ecs, options.inject_checksums) # cleanup and exit after dry run, searching easyconfigs or submitting regression test stop_options = [ options.check_conflicts, dry_run_mode, options.dump_env_script, options.inject_checksums ] if any(no_ec_opts) or any(stop_options): cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) cleanup(logfile, eb_tmpdir, testing, silent=True) sys.exit(0) # submit build as job(s), clean up and exit if options.job: submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now") cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # build software, will exit when errors occurs (except when testing) if not testing or (testing and do_build): exit_on_failure = not (options.dump_test_report or options.upload_test_report) hooks = load_hooks(options.hooks) ecs_with_res = build_and_install_software( ordered_ecs, init_session_state, exit_on_failure=exit_on_failure, hooks=hooks) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False) ]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) run_hook(END, hooks) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing) if __name__ == "__main__": try: main() except EasyBuildError as err: print_error(err.msg) except KeyboardInterrupt: print_error("Cancelled by user (keyboard interrupt)")
def main(args=None, logfile=None, do_build=None, testing=False, modtool=None): """ Main function: parse command line options, and act accordingly. :param args: command line arguments to use :param logfile: log file to use :param do_build: whether or not to actually perform the build :param testing: enable testing mode """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() eb_go, cfg_settings = set_up_configuration(args=args, logfile=logfile, testing=testing) options, orig_paths = eb_go.options, eb_go.args global _log (build_specs, _log, logfile, robot_path, search_query, eb_tmpdir, try_to_generate, tweaked_ecs_paths) = cfg_settings # load hook implementations (if any) hooks = load_hooks(options.hooks) run_hook(START, hooks) if modtool is None: modtool = modules_tool(testing=testing) # check whether any (EasyBuild-generated) modules are loaded already in the current session modtool.check_loaded_modules() if options.last_log: # print location to last log file, and exit last_log = find_last_log(logfile) or '(none)' print_msg(last_log, log=_log, prefix=False) # check whether packaging is supported when it's being used if options.package: check_pkg_support() else: _log.debug("Packaging not enabled, so not checking for packaging support.") # search for easyconfigs, if a query is specified if search_query: search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename, terse=options.terse) # GitHub options that warrant a silent cleanup & exit if options.check_github: check_github() elif options.install_github_token: install_github_token(options.github_user, silent=build_option('silent')) elif options.close_pr: close_pr(options.close_pr, motivation_msg=options.close_pr_msg) elif options.list_prs: print(list_prs(options.list_prs)) elif options.merge_pr: merge_pr(options.merge_pr) elif options.review_pr: print(review_pr(pr=options.review_pr, colored=use_color(options.color))) elif options.list_installed_software: detailed = options.list_installed_software == 'detailed' print(list_software(output_format=options.output_format, detailed=detailed, only_installed=True)) elif options.list_software: print(list_software(output_format=options.output_format, detailed=options.list_software == 'detailed')) # non-verbose cleanup after handling GitHub integration stuff or printing terse info early_stop_options = [ options.check_github, options.install_github_token, options.list_installed_software, options.list_software, options.close_pr, options.list_prs, options.merge_pr, options.review_pr, options.terse, search_query, ] if any(early_stop_options): clean_exit(logfile, eb_tmpdir, testing, silent=True) # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = modtool.list() # build options must be initialized first before 'module list' works init_session_state.update({'easybuild_configuration': eb_config}) init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning("Failed to determine install path for easybuild-easyconfigs package.") if options.install_latest_eb_release: if orig_paths: raise EasyBuildError("Installing the latest EasyBuild release can not be combined with installing " "other easyconfigs") else: eb_file = find_easybuild_easyconfig() orig_paths.append(eb_file) categorized_paths = categorize_files_by_type(orig_paths) # command line options that do not require any easyconfigs to be specified new_update_preview_pr = options.new_pr or options.update_pr or options.preview_pr no_ec_opts = [options.aggregate_regtest, options.regtest, search_query, new_update_preview_pr] # determine paths to easyconfigs determined_paths = det_easyconfig_paths(categorized_paths['easyconfigs']) if determined_paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in determined_paths] else: if 'name' in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif any(no_ec_opts): paths = determined_paths else: print_error(("Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs(paths, validate=not options.inject_checksums) # handle --check-contrib & --check-style options if run_contrib_style_checks([ec['ec'] for ec in easyconfigs], options.check_contrib, options.check_style): clean_exit(logfile, eb_tmpdir, testing) # verify easyconfig filenames, if desired if options.verify_easyconfig_filenames: _log.info("Verifying easyconfig filenames...") for easyconfig in easyconfigs: verify_easyconfig_filename(easyconfig['spec'], easyconfig['ec'], parsed_ec=easyconfig['ec']) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, modtool, targetdirs=tweaked_ecs_paths) if options.containerize: # if --containerize/-C create a container recipe (and optionally container image), and stop containerize(easyconfigs) clean_exit(logfile, eb_tmpdir, testing) forced = options.force or options.rebuild dry_run_mode = options.dry_run or options.dry_run_short # skip modules that are already installed unless forced, or unless an option is used that warrants not skipping if not (forced or dry_run_mode or options.extended_dry_run or new_update_preview_pr or options.inject_checksums): retained_ecs = skip_available(easyconfigs, modtool) if not testing: for skipped_ec in [ec for ec in easyconfigs if ec not in retained_ecs]: print_msg("%s is already installed (module found), skipping" % skipped_ec['full_mod_name']) easyconfigs = retained_ecs # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: # resolve dependencies if robot is enabled, except in dry run mode # one exception: deps *are* resolved with --new-pr or --update-pr when dry run mode is enabled if options.robot and (not dry_run_mode or new_update_preview_pr): print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies(easyconfigs, modtool) else: ordered_ecs = easyconfigs elif new_update_preview_pr: ordered_ecs = None else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] # creating/updating PRs if new_update_preview_pr: if options.new_pr: new_pr(categorized_paths, ordered_ecs, title=options.pr_title, descr=options.pr_descr, commit_msg=options.pr_commit_msg) elif options.preview_pr: print(review_pr(paths=determined_paths, colored=use_color(options.color))) else: update_pr(options.update_pr, categorized_paths, ordered_ecs, commit_msg=options.pr_commit_msg) # dry_run: print all easyconfigs and dependencies, and whether they are already built elif dry_run_mode: txt = dry_run(easyconfigs, modtool, short=not options.dry_run) print_msg(txt, log=_log, silent=testing, prefix=False) elif options.check_conflicts: if check_conflicts(easyconfigs, modtool): print_error("One or more conflicts detected!") sys.exit(1) else: print_msg("\nNo conflicts detected!\n", prefix=False) # dump source script to set up build environment elif options.dump_env_script: dump_env_script(easyconfigs) elif options.inject_checksums: inject_checksums(ordered_ecs, options.inject_checksums) # cleanup and exit after dry run, searching easyconfigs or submitting regression test stop_options = [options.check_conflicts, dry_run_mode, options.dump_env_script, options.inject_checksums] if any(no_ec_opts) or any(stop_options): clean_exit(logfile, eb_tmpdir, testing) # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) clean_exit(logfile, eb_tmpdir, testing, silent=True) # submit build as job(s), clean up and exit if options.job: submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now") clean_exit(logfile, eb_tmpdir, testing) # build software, will exit when errors occurs (except when testing) if not testing or (testing and do_build): exit_on_failure = not (options.dump_test_report or options.upload_test_report) ecs_with_res = build_and_install_software(ordered_ecs, init_session_state, exit_on_failure=exit_on_failure) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False)]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) run_hook(END, hooks) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) run_hook(END, hooks) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing) if __name__ == "__main__": try: main() except EasyBuildError as err: print_error(err.msg) except KeyboardInterrupt: print_error("Cancelled by user (keyboard interrupt)")
repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) run_hook(END, hooks) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing) if __name__ == "__main__": try: main() except EasyBuildError as err: print_error(err.msg) except KeyboardInterrupt as err: print_error("Cancelled by user: %s" % err)
len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir path) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing) if __name__ == "__main__": try: main() except EasyBuildError, e: print_error(e.msg)
def main(args=None, logfile=None, do_build=None, testing=False, modtool=None): """ Main function: parse command line options, and act accordingly. :param args: command line arguments to use :param logfile: log file to use :param do_build: whether or not to actually perform the build :param testing: enable testing mode """ register_lock_cleanup_signal_handlers() # if $CDPATH is set, unset it, it'll only cause trouble... # see https://github.com/easybuilders/easybuild-framework/issues/2944 if 'CDPATH' in os.environ: del os.environ['CDPATH'] # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() eb_go, cfg_settings = set_up_configuration(args=args, logfile=logfile, testing=testing) options, orig_paths = eb_go.options, eb_go.args global _log (build_specs, _log, logfile, robot_path, search_query, eb_tmpdir, try_to_generate, tweaked_ecs_paths) = cfg_settings # load hook implementations (if any) hooks = load_hooks(options.hooks) run_hook(START, hooks) if modtool is None: modtool = modules_tool(testing=testing) # check whether any (EasyBuild-generated) modules are loaded already in the current session modtool.check_loaded_modules() if options.last_log: # print location to last log file, and exit last_log = find_last_log(logfile) or '(none)' print_msg(last_log, log=_log, prefix=False) # check whether packaging is supported when it's being used if options.package: check_pkg_support() else: _log.debug("Packaging not enabled, so not checking for packaging support.") # search for easyconfigs, if a query is specified if search_query: search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename, terse=options.terse) # GitHub options that warrant a silent cleanup & exit if options.check_github: check_github() elif options.install_github_token: install_github_token(options.github_user, silent=build_option('silent')) elif options.close_pr: close_pr(options.close_pr, motivation_msg=options.close_pr_msg) elif options.list_prs: print(list_prs(options.list_prs)) elif options.merge_pr: merge_pr(options.merge_pr) elif options.review_pr: print(review_pr(pr=options.review_pr, colored=use_color(options.color))) elif options.list_installed_software: detailed = options.list_installed_software == 'detailed' print(list_software(output_format=options.output_format, detailed=detailed, only_installed=True)) elif options.list_software: print(list_software(output_format=options.output_format, detailed=options.list_software == 'detailed')) elif options.create_index: print_msg("Creating index for %s..." % options.create_index, prefix=False) index_fp = dump_index(options.create_index, max_age_sec=options.index_max_age) index = load_index(options.create_index) print_msg("Index created at %s (%d files)" % (index_fp, len(index)), prefix=False) # non-verbose cleanup after handling GitHub integration stuff or printing terse info early_stop_options = [ options.check_github, options.create_index, options.install_github_token, options.list_installed_software, options.list_software, options.close_pr, options.list_prs, options.merge_pr, options.review_pr, options.terse, search_query, ] if any(early_stop_options): clean_exit(logfile, eb_tmpdir, testing, silent=True) # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = modtool.list() # build options must be initialized first before 'module list' works init_session_state.update({'easybuild_configuration': eb_config}) init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning("Failed to determine install path for easybuild-easyconfigs package.") if options.install_latest_eb_release: if orig_paths: raise EasyBuildError("Installing the latest EasyBuild release can not be combined with installing " "other easyconfigs") else: eb_file = find_easybuild_easyconfig() orig_paths.append(eb_file) if len(orig_paths) == 1: # if only one easyconfig file is specified, use current directory as target directory target_path = os.getcwd() elif orig_paths: # last path is target when --copy-ec is used, so remove that from the list target_path = orig_paths.pop() if options.copy_ec else None categorized_paths = categorize_files_by_type(orig_paths) # command line options that do not require any easyconfigs to be specified pr_options = options.new_branch_github or options.new_pr or options.new_pr_from_branch or options.preview_pr pr_options = pr_options or options.sync_branch_with_develop or options.sync_pr_with_develop pr_options = pr_options or options.update_branch_github or options.update_pr no_ec_opts = [options.aggregate_regtest, options.regtest, pr_options, search_query] # determine paths to easyconfigs determined_paths = det_easyconfig_paths(categorized_paths['easyconfigs']) if (options.copy_ec and not tweaked_ecs_paths) or options.fix_deprecated_easyconfigs or options.show_ec: if options.copy_ec: if len(determined_paths) == 1: copy_file(determined_paths[0], target_path) print_msg("%s copied to %s" % (os.path.basename(determined_paths[0]), target_path), prefix=False) elif len(determined_paths) > 1: copy_files(determined_paths, target_path) print_msg("%d file(s) copied to %s" % (len(determined_paths), target_path), prefix=False) else: raise EasyBuildError("One of more files to copy should be specified!") elif options.fix_deprecated_easyconfigs: fix_deprecated_easyconfigs(determined_paths) elif options.show_ec: for path in determined_paths: print_msg("Contents of %s:" % path) print_msg(read_file(path), prefix=False) clean_exit(logfile, eb_tmpdir, testing) if determined_paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in determined_paths] elif 'name' in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif any(no_ec_opts): paths = determined_paths else: print_error("Please provide one or multiple easyconfig files, or use software build " + "options to make EasyBuild search for easyconfigs", log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) _log.debug("Paths: %s", paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs(paths, validate=not options.inject_checksums) # handle --check-contrib & --check-style options if run_contrib_style_checks([ec['ec'] for ec in easyconfigs], options.check_contrib, options.check_style): clean_exit(logfile, eb_tmpdir, testing) # verify easyconfig filenames, if desired if options.verify_easyconfig_filenames: _log.info("Verifying easyconfig filenames...") for easyconfig in easyconfigs: verify_easyconfig_filename(easyconfig['spec'], easyconfig['ec'], parsed_ec=easyconfig['ec']) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, modtool, targetdirs=tweaked_ecs_paths) if options.containerize: # if --containerize/-C create a container recipe (and optionally container image), and stop containerize(easyconfigs) clean_exit(logfile, eb_tmpdir, testing) forced = options.force or options.rebuild dry_run_mode = options.dry_run or options.dry_run_short or options.missing_modules # skip modules that are already installed unless forced, or unless an option is used that warrants not skipping if not (forced or dry_run_mode or options.extended_dry_run or pr_options or options.inject_checksums): retained_ecs = skip_available(easyconfigs, modtool) if not testing: for skipped_ec in [ec for ec in easyconfigs if ec not in retained_ecs]: print_msg("%s is already installed (module found), skipping" % skipped_ec['full_mod_name']) easyconfigs = retained_ecs # keep track for which easyconfigs we should set the corresponding module as default if options.set_default_module: for easyconfig in easyconfigs: easyconfig['ec'].set_default_module = True # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: # resolve dependencies if robot is enabled, except in dry run mode # one exception: deps *are* resolved with --new-pr or --update-pr when dry run mode is enabled if options.robot and (not dry_run_mode or pr_options): print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies(easyconfigs, modtool) else: ordered_ecs = easyconfigs elif pr_options: ordered_ecs = None else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] if options.copy_ec and tweaked_ecs_paths: all_specs = [spec['spec'] for spec in resolve_dependencies(easyconfigs, modtool, retain_all_deps=True, raise_error_missing_ecs=False)] tweaked_ecs_in_all_ecs = [path for path in all_specs if any(tweaked_ecs_path in path for tweaked_ecs_path in tweaked_ecs_paths)] if tweaked_ecs_in_all_ecs: # Clean them, then copy them clean_up_easyconfigs(tweaked_ecs_in_all_ecs) copy_files(tweaked_ecs_in_all_ecs, target_path) print_msg("%d file(s) copied to %s" % (len(tweaked_ecs_in_all_ecs), target_path), prefix=False) # creating/updating PRs if pr_options: if options.new_pr: new_pr(categorized_paths, ordered_ecs) elif options.new_branch_github: new_branch_github(categorized_paths, ordered_ecs) elif options.new_pr_from_branch: new_pr_from_branch(options.new_pr_from_branch) elif options.preview_pr: print(review_pr(paths=determined_paths, colored=use_color(options.color))) elif options.sync_branch_with_develop: sync_branch_with_develop(options.sync_branch_with_develop) elif options.sync_pr_with_develop: sync_pr_with_develop(options.sync_pr_with_develop) elif options.update_branch_github: update_branch(options.update_branch_github, categorized_paths, ordered_ecs) elif options.update_pr: update_pr(options.update_pr, categorized_paths, ordered_ecs) else: raise EasyBuildError("Unknown PR option!") # dry_run: print all easyconfigs and dependencies, and whether they are already built elif dry_run_mode: if options.missing_modules: txt = missing_deps(easyconfigs, modtool) else: txt = dry_run(easyconfigs, modtool, short=not options.dry_run) print_msg(txt, log=_log, silent=testing, prefix=False) elif options.check_conflicts: if check_conflicts(easyconfigs, modtool): print_error("One or more conflicts detected!") sys.exit(1) else: print_msg("\nNo conflicts detected!\n", prefix=False) # dump source script to set up build environment elif options.dump_env_script: dump_env_script(easyconfigs) elif options.inject_checksums: inject_checksums(ordered_ecs, options.inject_checksums) # cleanup and exit after dry run, searching easyconfigs or submitting regression test stop_options = [options.check_conflicts, dry_run_mode, options.dump_env_script, options.inject_checksums] if any(no_ec_opts) or any(stop_options): clean_exit(logfile, eb_tmpdir, testing) # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) clean_exit(logfile, eb_tmpdir, testing, silent=True) # submit build as job(s), clean up and exit if options.job: submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now") clean_exit(logfile, eb_tmpdir, testing) # build software, will exit when errors occurs (except when testing) if not testing or (testing and do_build): exit_on_failure = not (options.dump_test_report or options.upload_test_report) ecs_with_res = build_and_install_software(ordered_ecs, init_session_state, exit_on_failure=exit_on_failure) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False)]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) run_hook(END, hooks) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
def main(testing_data=(None, None, None)): """ Main function: parse command line options, and act accordingly. @param testing_data: tuple with command line arguments, log file and boolean indicating whether or not to build """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() # steer behavior when testing main testing = testing_data[0] is not None args, logfile, do_build = testing_data # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set temporary directory to use eb_tmpdir = set_tmpdir(options.tmpdir) # initialise logging for main global _log _log, logfile = init_logging(logfile, logtostdout=options.logtostdout, testing=testing) # disallow running EasyBuild as root if os.getuid() == 0: raise EasyBuildError( "You seem to be running EasyBuild with root privileges which is not wise, " "so let's end this here.") # log startup info eb_cmd_line = eb_go.generate_cmd_line() + eb_go.args log_start(eb_cmd_line, eb_tmpdir) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) # determine robot path # --try-X, --dep-graph, --search use robot path for searching, so enable it with path of installed easyconfigs tweaked_ecs = try_to_generate and build_specs tweaked_ecs_path, pr_path = alt_easyconfig_paths(eb_tmpdir, tweaked_ecs=tweaked_ecs, from_pr=options.from_pr) auto_robot = try_to_generate or options.dep_graph or options.search or options.search_short robot_path = det_robot_path(options.robot_paths, tweaked_ecs_path, pr_path, auto_robot=auto_robot) _log.debug("Full robot path: %s" % robot_path) # configure & initialize build options config_options_dict = eb_go.get_options_by_section('config') build_options = { 'build_specs': build_specs, 'command_line': eb_cmd_line, 'pr_path': pr_path, 'robot_path': robot_path, 'silent': testing, 'try_to_generate': try_to_generate, 'valid_stops': [x[0] for x in EasyBlock.get_steps()], } # initialise the EasyBuild configuration & build options config.init(options, config_options_dict) config.init_build_options(build_options=build_options, cmdline_options=options) # update session state eb_config = eb_go.generate_cmd_line(add_default=True) modlist = session_module_list( testing=testing ) # build options must be initialized first before 'module list' works init_session_state.update({'easybuild_configuration': eb_config}) init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # search for easyconfigs, if a query is specified query = options.search or options.search_short if query: search_easyconfigs(query, short=not options.search) # determine easybuild-easyconfigs package install path easyconfigs_pkg_paths = get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR) if not easyconfigs_pkg_paths: _log.warning( "Failed to determine install path for easybuild-easyconfigs package." ) # determine paths to easyconfigs paths = det_easyconfig_paths(orig_paths) if paths: # transform paths into tuples, use 'False' to indicate the corresponding easyconfig files were not generated paths = [(p, False) for p in paths] else: if 'name' in build_specs: # try to obtain or generate an easyconfig file via build specifications if a software name is provided paths = find_easyconfigs_by_specs(build_specs, robot_path, try_to_generate, testing=testing) elif not any([ options.aggregate_regtest, options.search, options.search_short, options.regtest ]): print_error(( "Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") # fallback: easybuild-easyconfigs install path regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs, generated_ecs = parse_easyconfigs(paths) # tweak obtained easyconfig files, if requested # don't try and tweak anything if easyconfigs were generated, since building a full dep graph will fail # if easyconfig files for the dependencies are not available if try_to_generate and build_specs and not generated_ecs: easyconfigs = tweak(easyconfigs, build_specs, targetdir=tweaked_ecs_path) # dry_run: print all easyconfigs and dependencies, and whether they are already built if options.dry_run or options.dry_run_short: txt = dry_run(easyconfigs, short=not options.dry_run, build_specs=build_specs) print_msg(txt, log=_log, silent=testing, prefix=False) # cleanup and exit after dry run, searching easyconfigs or submitting regression test if any([ options.dry_run, options.dry_run_short, options.regtest, options.search, options.search_short ]): cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # skip modules that are already installed unless forced if not options.force: retained_ecs = skip_available(easyconfigs) if not testing: for skipped_ec in [ ec for ec in easyconfigs if ec not in retained_ecs ]: print_msg("%s is already installed (module found), skipping" % skipped_ec['full_mod_name']) easyconfigs = retained_ecs # determine an order that will allow all specs in the set to build if len(easyconfigs) > 0: if options.robot: print_msg("resolving dependencies ...", log=_log, silent=testing) ordered_ecs = resolve_dependencies(easyconfigs, build_specs=build_specs) else: ordered_ecs = easyconfigs else: print_msg("No easyconfigs left to be built.", log=_log, silent=testing) ordered_ecs = [] # create dependency graph and exit if options.dep_graph: _log.info("Creating dependency graph %s" % options.dep_graph) dep_graph(options.dep_graph, ordered_ecs) sys.exit(0) # submit build as job(s), clean up and exit if options.job: job_info_txt = submit_jobs(ordered_ecs, eb_go.generate_cmd_line(), testing=testing) if not testing: print_msg("Submitted parallel build jobs, exiting now: %s" % job_info_txt) cleanup(logfile, eb_tmpdir, testing) sys.exit(0) # build software, will exit when errors occurs (except when testing) exit_on_failure = not options.dump_test_report and not options.upload_test_report if not testing or (testing and do_build): ecs_with_res = build_and_install_software( ordered_ecs, init_session_state, exit_on_failure=exit_on_failure) else: ecs_with_res = [(ec, {}) for ec in ordered_ecs] correct_builds_cnt = len([ ec_res for (_, ec_res) in ecs_with_res if ec_res.get('success', False) ]) overall_success = correct_builds_cnt == len(ordered_ecs) success_msg = "Build succeeded for %s out of %s" % (correct_builds_cnt, len(ordered_ecs)) repo = init_repository(get_repository(), get_repositorypath()) repo.cleanup() # dump/upload overall test report test_report_msg = overall_test_report(ecs_with_res, len(paths), overall_success, success_msg, init_session_state) if test_report_msg is not None: print_msg(test_report_msg) print_msg(success_msg, log=_log, silent=testing) # cleanup and spec files for ec in easyconfigs: if 'original_spec' in ec and os.path.isfile(ec['spec']): os.remove(ec['spec']) # stop logging and cleanup tmp log file, unless one build failed (individual logs are located in eb_tmpdir path) stop_logging(logfile, logtostdout=options.logtostdout) if overall_success: cleanup(logfile, eb_tmpdir, testing)
def main(testing_data=(None, None)): """ Main function: @arg options: a tuple: (options, paths, logger, logfile, hn) as defined in parse_options This function will: - read easyconfig - build software """ # disallow running EasyBuild as root if os.getuid() == 0: sys.stderr.write( "ERROR: You seem to be running EasyBuild with root privileges.\n" "That's not wise, so let's end this here.\n" "Exiting.\n" ) sys.exit(1) # steer behavior when testing main testing = testing_data[0] is not None args, logfile = testing_data # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # initialise logging for main if options.logtostdout: fancylogger.logToScreen(enable=True, stdout=True) else: if logfile is None: # mkstemp returns (fd,filename), fd is from os.open, not regular open! fd, logfile = tempfile.mkstemp(suffix=".log", prefix="easybuild-") os.close(fd) fancylogger.logToFile(logfile) print_msg("temporary log file in case of crash %s" % (logfile), log=None, silent=testing) global _log _log = fancylogger.getLogger(fname=False) # hello world! _log.info(this_is_easybuild()) # set strictness of filetools module if options.strict: filetools.strictness = options.strict if not options.robot is None: if options.robot: _log.info("Using robot path: %s" % options.robot) else: _log.error("No robot path specified, and unable to determine easybuild-easyconfigs install path.") # determine easybuild-easyconfigs package install path easyconfigs_paths = get_paths_for("easyconfigs", robot_path=options.robot) easyconfigs_pkg_full_path = None search_path = os.getcwd() if easyconfigs_paths: easyconfigs_pkg_full_path = easyconfigs_paths[0] if not options.robot: search_path = easyconfigs_pkg_full_path else: search_path = options.robot else: _log.info("Failed to determine install path for easybuild-easyconfigs package.") if options.robot: easyconfigs_paths = [options.robot] + easyconfigs_paths # initialise the easybuild configuration config.init(options, eb_go.get_options_by_section("config")) # search for easyconfigs if options.search: search_file(search_path, options.search, silent=testing) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, software_build_specs) = process_software_build_specs(options) paths = [] if len(orig_paths) == 0: if software_build_specs.has_key("name"): paths = [ obtain_path( software_build_specs, easyconfigs_paths, try_to_generate=try_to_generate, exit_on_error=not testing ) ] elif not any([options.aggregate_regtest, options.search, options.regtest]): print_error( ( "Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs" ), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing, ) else: # look for easyconfigs with relative paths in easybuild-easyconfigs package, # unless they we found at the given relative paths if easyconfigs_pkg_full_path: # create a mapping from filename to path in easybuild-easyconfigs package install path easyconfigs_map = {} for (subpath, _, filenames) in os.walk(easyconfigs_pkg_full_path): for filename in filenames: easyconfigs_map.update({filename: os.path.join(subpath, filename)}) # try and find non-existing non-absolute eaysconfig paths in easybuild-easyconfigs package install path for idx, orig_path in enumerate(orig_paths): if not os.path.isabs(orig_path) and not os.path.exists(orig_path): if orig_path in easyconfigs_map: _log.info( "Found %s in %s: %s" % (orig_path, easyconfigs_pkg_full_path, easyconfigs_map[orig_path]) ) orig_paths[idx] = easyconfigs_map[orig_path] # indicate that specified paths do not contain generated easyconfig files paths = [(path, False) for path in orig_paths] _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") if paths: regtest_ok = regtest(options, [path[0] for path in paths]) else: # fallback: easybuild-easyconfigs install path regtest_ok = regtest(options, [easyconfigs_pkg_full_path]) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 if any([options.search, options.regtest]): cleanup_logfile_and_exit(logfile, testing, True) # building a dependency graph implies force, so that all dependencies are retained # and also skips validation of easyconfigs (e.g. checking os dependencies) validate_easyconfigs = True retain_all_deps = False if options.dep_graph: _log.info("Enabling force to generate dependency graph.") options.force = True validate_easyconfigs = False retain_all_deps = True # read easyconfig files easyconfigs = [] for (path, generated) in paths: path = os.path.abspath(path) if not (os.path.exists(path)): print_error("Can't find path %s" % path) try: files = find_easyconfigs(path) for f in files: if not generated and try_to_generate and software_build_specs: ec_file = easyconfig.tools.tweak(f, None, software_build_specs) else: ec_file = f easyconfigs.extend(process_easyconfig(ec_file, options.only_blocks, validate=validate_easyconfigs)) except IOError, err: _log.error("Processing easyconfigs in path %s failed: %s" % (path, err))
def main(testing_data=(None, None, None)): """ Main function: @arg options: a tuple: (options, paths, logger, logfile, hn) as defined in parse_options This function will: - read easyconfig - build software """ # purposely session state very early, to avoid modules loaded by EasyBuild meddling in init_session_state = session_state() # disallow running EasyBuild as root if os.getuid() == 0: sys.stderr.write( "ERROR: You seem to be running EasyBuild with root privileges.\n" "That's not wise, so let's end this here.\n" "Exiting.\n") sys.exit(1) # steer behavior when testing main testing = testing_data[0] is not None args, logfile, do_build = testing_data # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args eb_config = eb_go.generate_cmd_line(add_default=True) init_session_state.update({'easybuild_configuration': eb_config}) # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set temporary directory to use eb_tmpdir = set_tmpdir(options.tmpdir) # initialise logging for main if options.logtostdout: fancylogger.logToScreen(enable=True, stdout=True) else: if logfile is None: # mkstemp returns (fd,filename), fd is from os.open, not regular open! fd, logfile = tempfile.mkstemp(suffix='.log', prefix='easybuild-') os.close(fd) fancylogger.logToFile(logfile) print_msg('temporary log file in case of crash %s' % (logfile), log=None, silent=testing) global _log _log = fancylogger.getLogger(fname=False) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # hello world! _log.info(this_is_easybuild()) # how was EB called? eb_command_line = eb_go.generate_cmd_line() + eb_go.args _log.info("Command line: %s" % (" ".join(eb_command_line))) _log.info("Using %s as temporary directory" % eb_tmpdir) if not options.robot is None: if options.robot: _log.info("Using robot path(s): %s" % options.robot) else: _log.error( "No robot paths specified, and unable to determine easybuild-easyconfigs install path." ) # do not pass options.robot, it's not a list instance (and it shouldn't be modified) robot_path = None if options.robot: robot_path = list(options.robot) # determine easybuild-easyconfigs package install path easyconfigs_paths = get_paths_for("easyconfigs", robot_path=robot_path) # keep track of paths for install easyconfigs, so we can obtain find specified easyconfigs easyconfigs_pkg_full_paths = easyconfigs_paths[:] if not easyconfigs_paths: _log.warning( "Failed to determine install path for easybuild-easyconfigs package." ) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) # specified robot paths are preferred over installed easyconfig files # --try-X and --dep-graph both require --robot, so enable it with path of installed easyconfigs if robot_path or try_to_generate or options.dep_graph: if robot_path is None: robot_path = [] robot_path.extend(easyconfigs_paths) easyconfigs_paths = robot_path[:] _log.info( "Extended list of robot paths with paths for installed easyconfigs: %s" % robot_path) # initialise the easybuild configuration config.init(options, eb_go.get_options_by_section('config')) # building a dependency graph implies force, so that all dependencies are retained # and also skips validation of easyconfigs (e.g. checking os dependencies) retain_all_deps = False if options.dep_graph: _log.info("Enabling force to generate dependency graph.") options.force = True retain_all_deps = True config.init_build_options({ 'aggregate_regtest': options.aggregate_regtest, 'allow_modules_tool_mismatch': options.allow_modules_tool_mismatch, 'check_osdeps': not options.ignore_osdeps, 'cleanup_builddir': options.cleanup_builddir, 'command_line': eb_command_line, 'debug': options.debug, 'dry_run': options.dry_run, 'easyblock': options.easyblock, 'experimental': options.experimental, 'force': options.force, 'github_user': options.github_user, 'group': options.group, 'ignore_dirs': options.ignore_dirs, 'modules_footer': options.modules_footer, 'only_blocks': options.only_blocks, 'recursive_mod_unload': options.recursive_module_unload, 'regtest_output_dir': options.regtest_output_dir, 'retain_all_deps': retain_all_deps, 'robot_path': robot_path, 'sequential': options.sequential, 'silent': testing, 'set_gid_bit': options.set_gid_bit, 'skip': options.skip, 'skip_test_cases': options.skip_test_cases, 'sticky_bit': options.sticky_bit, 'stop': options.stop, 'umask': options.umask, 'valid_module_classes': module_classes(), 'valid_stops': [x[0] for x in EasyBlock.get_steps()], 'validate': not options.force, }) # obtain list of loaded modules, build options must be initialized first modlist = session_module_list() init_session_state.update({'module_list': modlist}) _log.debug("Initial session state: %s" % init_session_state) # search for easyconfigs if options.search or options.search_short: search_path = [os.getcwd()] if easyconfigs_paths: search_path = easyconfigs_paths query = options.search or options.search_short ignore_dirs = config.build_option('ignore_dirs') silent = config.build_option('silent') search_file(search_path, query, short=not options.search, ignore_dirs=ignore_dirs, silent=silent) paths = [] if len(orig_paths) == 0: if options.from_pr: pr_path = os.path.join(eb_tmpdir, "files_pr%s" % options.from_pr) pr_files = fetch_easyconfigs_from_pr( options.from_pr, path=pr_path, github_user=options.github_user) paths = [(path, False) for path in pr_files if path.endswith('.eb')] elif 'name' in build_specs: paths = [ obtain_path(build_specs, easyconfigs_paths, try_to_generate=try_to_generate, exit_on_error=not testing) ] elif not any([ options.aggregate_regtest, options.search, options.search_short, options.regtest ]): print_error(( "Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) else: # look for easyconfigs with relative paths in easybuild-easyconfigs package, # unless they were found at the given relative paths if easyconfigs_pkg_full_paths: # determine which easyconfigs files need to be found, if any ecs_to_find = [] for idx, orig_path in enumerate(orig_paths): if orig_path == os.path.basename( orig_path) and not os.path.exists(orig_path): ecs_to_find.append((idx, orig_path)) _log.debug("List of easyconfig files to find: %s" % ecs_to_find) # find missing easyconfigs by walking paths with installed easyconfig files for path in easyconfigs_pkg_full_paths: _log.debug( "Looking for missing easyconfig files (%d left) in %s..." % (len(ecs_to_find), path)) for (subpath, dirnames, filenames) in os.walk(path, topdown=True): for idx, orig_path in ecs_to_find[:]: if orig_path in filenames: full_path = os.path.join(subpath, orig_path) _log.info("Found %s in %s: %s" % (orig_path, path, full_path)) orig_paths[idx] = full_path # if file was found, stop looking for it (first hit wins) ecs_to_find.remove((idx, orig_path)) # stop os.walk insanity as soon as we have all we need (os.walk loop) if len(ecs_to_find) == 0: break # ignore subdirs specified to be ignored by replacing items in dirnames list used by os.walk dirnames[:] = [ d for d in dirnames if not d in options.ignore_dirs ] # stop os.walk insanity as soon as we have all we need (paths loop) if len(ecs_to_find) == 0: break # indicate that specified paths do not contain generated easyconfig files paths = [(path, False) for path in orig_paths] _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") if paths: ec_paths = [path[0] for path in paths] else: # fallback: easybuild-easyconfigs install path ec_paths = easyconfigs_pkg_full_paths regtest_ok = regtest(ec_paths) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs = [] for (path, generated) in paths: path = os.path.abspath(path) if not os.path.exists(path): print_error("Can't find path %s" % path) try: ec_files = find_easyconfigs(path, ignore_dirs=options.ignore_dirs) for ec_file in ec_files: # only pass build specs when not generating easyconfig files if try_to_generate: ecs = process_easyconfig(ec_file) else: ecs = process_easyconfig(ec_file, build_specs=build_specs) easyconfigs.extend(ecs) except IOError, err: _log.error("Processing easyconfigs in path %s failed: %s" % (path, err))
def main(testing_data=(None, None, None)): """ Main function: @arg options: a tuple: (options, paths, logger, logfile, hn) as defined in parse_options This function will: - read easyconfig - build software """ # disallow running EasyBuild as root if os.getuid() == 0: sys.stderr.write("ERROR: You seem to be running EasyBuild with root privileges.\n" "That's not wise, so let's end this here.\n" "Exiting.\n") sys.exit(1) # steer behavior when testing main testing = testing_data[0] is not None args, logfile, do_build = testing_data # initialise options eb_go = eboptions.parse_options(args=args) options = eb_go.options orig_paths = eb_go.args # set umask (as early as possible) if options.umask is not None: new_umask = int(options.umask, 8) old_umask = os.umask(new_umask) # set temporary directory to use eb_tmpdir = set_tmpdir(options.tmpdir) # initialise logging for main if options.logtostdout: fancylogger.logToScreen(enable=True, stdout=True) else: if logfile is None: # mkstemp returns (fd,filename), fd is from os.open, not regular open! fd, logfile = tempfile.mkstemp(suffix='.log', prefix='easybuild-') os.close(fd) fancylogger.logToFile(logfile) print_msg('temporary log file in case of crash %s' % (logfile), log=None, silent=testing) global _log _log = fancylogger.getLogger(fname=False) if options.umask is not None: _log.info("umask set to '%s' (used to be '%s')" % (oct(new_umask), oct(old_umask))) # hello world! _log.info(this_is_easybuild()) # how was EB called? eb_command_line = eb_go.generate_cmd_line() + eb_go.args _log.info("Command line: %s" % (" ".join(eb_command_line))) _log.info("Using %s as temporary directory" % eb_tmpdir) if not options.robot is None: if options.robot: _log.info("Using robot path(s): %s" % options.robot) else: _log.error("No robot paths specified, and unable to determine easybuild-easyconfigs install path.") # do not pass options.robot, it's not a list instance (and it shouldn't be modified) robot_path = None if options.robot: robot_path = list(options.robot) # determine easybuild-easyconfigs package install path easyconfigs_paths = get_paths_for("easyconfigs", robot_path=robot_path) # keep track of paths for install easyconfigs, so we can obtain find specified easyconfigs easyconfigs_pkg_full_paths = easyconfigs_paths[:] if not easyconfigs_paths: _log.warning("Failed to determine install path for easybuild-easyconfigs package.") # specified robot paths are preferred over installed easyconfig files if robot_path: robot_path.extend(easyconfigs_paths) easyconfigs_paths = robot_path[:] _log.info("Extended list of robot paths with paths for installed easyconfigs: %s" % robot_path) # initialise the easybuild configuration config.init(options, eb_go.get_options_by_section('config')) # building a dependency graph implies force, so that all dependencies are retained # and also skips validation of easyconfigs (e.g. checking os dependencies) retain_all_deps = False if options.dep_graph: _log.info("Enabling force to generate dependency graph.") options.force = True retain_all_deps = True config.init_build_options({ 'aggregate_regtest': options.aggregate_regtest, 'allow_modules_tool_mismatch': options.allow_modules_tool_mismatch, 'check_osdeps': not options.ignore_osdeps, 'command_line': eb_command_line, 'debug': options.debug, 'dry_run': options.dry_run, 'easyblock': options.easyblock, 'experimental': options.experimental, 'force': options.force, 'group': options.group, 'ignore_dirs': options.ignore_dirs, 'modules_footer': options.modules_footer, 'only_blocks': options.only_blocks, 'recursive_mod_unload': options.recursive_module_unload, 'regtest_online': options.regtest_online, 'regtest_output_dir': options.regtest_output_dir, 'retain_all_deps': retain_all_deps, 'robot_path': robot_path, 'sequential': options.sequential, 'silent': testing, 'set_gid_bit': options.set_gid_bit, 'skip': options.skip, 'skip_test_cases': options.skip_test_cases, 'sticky_bit': options.sticky_bit, 'stop': options.stop, 'umask': options.umask, 'valid_module_classes': module_classes(), 'valid_stops': [x[0] for x in EasyBlock.get_steps()], 'validate': not options.force, }) # search for easyconfigs if options.search or options.search_short: search_path = [os.getcwd()] if easyconfigs_paths: search_path = easyconfigs_paths query = options.search or options.search_short ignore_dirs = config.build_option('ignore_dirs') silent = config.build_option('silent') search_file(search_path, query, short=not options.search, ignore_dirs=ignore_dirs, silent=silent) # process software build specifications (if any), i.e. # software name/version, toolchain name/version, extra patches, ... (try_to_generate, build_specs) = process_software_build_specs(options) paths = [] if len(orig_paths) == 0: if 'name' in build_specs: paths = [obtain_path(build_specs, easyconfigs_paths, try_to_generate=try_to_generate, exit_on_error=not testing)] elif not any([options.aggregate_regtest, options.search, options.search_short, options.regtest]): print_error(("Please provide one or multiple easyconfig files, or use software build " "options to make EasyBuild search for easyconfigs"), log=_log, opt_parser=eb_go.parser, exit_on_error=not testing) else: # look for easyconfigs with relative paths in easybuild-easyconfigs package, # unless they were found at the given relative paths if easyconfigs_pkg_full_paths: # determine which easyconfigs files need to be found, if any ecs_to_find = [] for idx, orig_path in enumerate(orig_paths): if orig_path == os.path.basename(orig_path) and not os.path.exists(orig_path): ecs_to_find.append((idx, orig_path)) _log.debug("List of easyconfig files to find: %s" % ecs_to_find) # find missing easyconfigs by walking paths with installed easyconfig files for path in easyconfigs_pkg_full_paths: _log.debug("Looking for missing easyconfig files (%d left) in %s..." % (len(ecs_to_find), path)) for (subpath, dirnames, filenames) in os.walk(path, topdown=True): for idx, orig_path in ecs_to_find[:]: if orig_path in filenames: full_path = os.path.join(subpath, orig_path) _log.info("Found %s in %s: %s" % (orig_path, path, full_path)) orig_paths[idx] = full_path # if file was found, stop looking for it (first hit wins) ecs_to_find.remove((idx, orig_path)) # stop os.walk insanity as soon as we have all we need (os.walk loop) if len(ecs_to_find) == 0: break # ignore subdirs specified to be ignored by replacing items in dirnames list used by os.walk dirnames[:] = [d for d in dirnames if not d in options.ignore_dirs] # stop os.walk insanity as soon as we have all we need (paths loop) if len(ecs_to_find) == 0: break # indicate that specified paths do not contain generated easyconfig files paths = [(path, False) for path in orig_paths] _log.debug("Paths: %s" % paths) # run regtest if options.regtest or options.aggregate_regtest: _log.info("Running regression test") if paths: ec_paths = [path[0] for path in paths] else: # fallback: easybuild-easyconfigs install path ec_paths = easyconfigs_pkg_full_paths regtest_ok = regtest(ec_paths) if not regtest_ok: _log.info("Regression test failed (partially)!") sys.exit(31) # exit -> 3x1t -> 31 # read easyconfig files easyconfigs = [] for (path, generated) in paths: path = os.path.abspath(path) if not os.path.exists(path): print_error("Can't find path %s" % path) try: files = find_easyconfigs(path, ignore_dirs=options.ignore_dirs) for f in files: if not generated and try_to_generate and build_specs: ec_file = tweak(f, None, build_specs) else: ec_file = f ecs = process_easyconfig(ec_file, build_specs=build_specs) easyconfigs.extend(ecs) except IOError, err: _log.error("Processing easyconfigs in path %s failed: %s" % (path, err))
except EasyBuildError, err: _log.warn("Unable to commit easyconfig to repository: %s", err) exitCode = 0 succ = "successfully" summary = "COMPLETED" # cleanup logs app.close_log() try: if not os.path.isdir(newLogDir): os.makedirs(newLogDir) applicationLog = os.path.join(newLogDir, get_log_filename(app.name, app.version)) shutil.move(app.logfile, applicationLog) except IOError, err: print_error("Failed to move log file %s to new log file %s: %s" % (app.logfile, applicationLog, err)) try: shutil.copy(spec, os.path.join(newLogDir, "%s-%s.eb" % (app.name, app.get_installversion()))) except IOError, err: print_error("Failed to move easyconfig %s to log dir %s: %s" % (spec, newLogDir, err)) # build failed else: exitCode = 1 summary = "FAILED" buildDir = '' if app.builddir: buildDir = " (build directory: %s)" % (app.builddir) succ = "unsuccessfully%s:\n%s" % (buildDir, errormsg)