def __init__(self, event_handler=None, popen=None, config_pm=None, fs_util=None, suite_engine_proc=None): if not self.CONF_NAME: self.CONF_NAME = self.NAME self.event_handler = event_handler if popen is None: popen = RosePopener(event_handler) self.popen = popen if fs_util is None: fs_util = FileSystemUtil(event_handler) self.fs_util = fs_util if config_pm is None: config_pm = ConfigProcessorsManager(event_handler, popen, fs_util) self.config_pm = config_pm if suite_engine_proc is None: suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=event_handler, popen=popen, fs_util=fs_util) self.suite_engine_proc = suite_engine_proc self.conf_tree_loader = ConfigTreeLoader()
class Runner(object): """Invoke a Rose application or a Rose suite.""" CONF_NAME = None NAME = None OPTIONS = [] def __init__(self, event_handler=None, popen=None, config_pm=None, fs_util=None, suite_engine_proc=None): if not self.CONF_NAME: self.CONF_NAME = self.NAME self.event_handler = event_handler if popen is None: popen = RosePopener(event_handler) self.popen = popen if fs_util is None: fs_util = FileSystemUtil(event_handler) self.fs_util = fs_util if config_pm is None: config_pm = ConfigProcessorsManager(event_handler, popen, fs_util) self.config_pm = config_pm if suite_engine_proc is None: suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=event_handler, popen=popen, fs_util=fs_util) self.suite_engine_proc = suite_engine_proc self.conf_tree_loader = ConfigTreeLoader() def handle_event(self, *args, **kwargs): """Handle an event using the runner's event handler.""" if callable(self.event_handler): return self.event_handler(*args, **kwargs) def config_load(self, opts): """Combine main config file with optional ones and defined ones. Return an instance of rose.config_tree.ConfigTree. """ # Main configuration file conf_dir = opts.conf_dir if conf_dir is None: conf_dir = os.getcwd() conf_dir_orig = conf_dir conf_name = "rose-" + self.CONF_NAME + ".conf" while not os.access(os.path.join(conf_dir, conf_name), os.F_OK | os.R_OK): conf_dir = self.fs_util.dirname(conf_dir) if conf_dir == self.fs_util.dirname(conf_dir): # is root raise ConfigNotFoundError(conf_dir_orig, conf_name) # Optional configuration files opt_conf_keys = [] opt_conf_keys_env = os.getenv("ROSE_%s_OPT_CONF_KEYS" % self.CONF_NAME.upper()) if opt_conf_keys_env: opt_conf_keys += shlex.split(opt_conf_keys_env) if opts.opt_conf_keys: opt_conf_keys += opts.opt_conf_keys self.handle_event(RunConfigLoadEvent( conf_dir, conf_name, opt_conf_keys, opts.defines, getattr(opts, 'defines_suite', []))) conf_tree = self.conf_tree_loader.load(conf_dir, conf_name, opt_keys=opt_conf_keys) # Optional defines if opts.defines: self.conf_tree_loader.node_loader.load_defines(opts.defines, conf_tree.node) return conf_tree def run(self, opts, args): """Initiates a run with this runner, using the options and arguments. opts is a dict or object with relevant flags args is a list of strings. """ if isinstance(opts, dict): opts = Dummy(**opts) cwd = os.getcwd() environ = dict(os.environ) uuid = str(uuid4()) work_files = [] try: return self.run_impl(opts, args, uuid, work_files) finally: # Close handle on specific log file try: self.event_handler.contexts[uuid].handle.close() except (KeyError, IOError, AttributeError): pass # Remove work files for work_file in work_files: try: if os.path.isfile(work_file) or os.path.islink(work_file): os.unlink(work_file) elif os.path.isdir(work_file): shutil.rmtree(work_file) except OSError: pass # Change back to original working directory try: os.chdir(cwd) except OSError: pass # Reset os.environ os.environ = dict(environ) __call__ = run def run_impl(self, opts, args, uuid, work_files): """Sub-class should implement the actual logic for a run. uuid is a unique identifier for a run. work_files is a list of files, which are removed at the end of a run. """ raise NotImplementedError()
class Runner(object): """Invoke a Rose application or a Rose suite.""" CONF_NAME = None NAME = None OPTIONS = [] def __init__(self, event_handler=None, popen=None, config_pm=None, fs_util=None, suite_engine_proc=None): if not self.CONF_NAME: self.CONF_NAME = self.NAME self.event_handler = event_handler if popen is None: popen = RosePopener(event_handler) self.popen = popen if fs_util is None: fs_util = FileSystemUtil(event_handler) self.fs_util = fs_util if config_pm is None: config_pm = ConfigProcessorsManager(event_handler, popen, fs_util) self.config_pm = config_pm if suite_engine_proc is None: suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=event_handler, popen=popen, fs_util=fs_util) self.suite_engine_proc = suite_engine_proc self.conf_tree_loader = ConfigTreeLoader() def handle_event(self, *args, **kwargs): """Handle an event using the runner's event handler.""" if callable(self.event_handler): return self.event_handler(*args, **kwargs) def config_load(self, opts): """Combine main config file with optional ones and defined ones. Return an instance of rose.config_tree.ConfigTree. """ # Main configuration file conf_dir = opts.conf_dir if conf_dir is None: conf_dir = os.getcwd() conf_dir_orig = conf_dir conf_name = "rose-" + self.CONF_NAME + ".conf" while not os.access(os.path.join(conf_dir, conf_name), os.F_OK | os.R_OK): conf_dir = self.fs_util.dirname(conf_dir) if conf_dir == self.fs_util.dirname(conf_dir): # is root raise ConfigNotFoundError(conf_dir_orig, conf_name) # Optional configuration files opt_conf_keys = [] opt_conf_keys_env = os.getenv("ROSE_%s_OPT_CONF_KEYS" % self.CONF_NAME.upper()) if opt_conf_keys_env: opt_conf_keys += shlex.split(opt_conf_keys_env) if opts.opt_conf_keys: opt_conf_keys += opts.opt_conf_keys self.handle_event( RunConfigLoadEvent(conf_dir, conf_name, opt_conf_keys, opts.defines, getattr(opts, 'defines_suite', []))) conf_tree = self.conf_tree_loader.load(conf_dir, conf_name, opt_keys=opt_conf_keys) # Optional defines if opts.defines: self.conf_tree_loader.node_loader.load_defines( opts.defines, conf_tree.node) return conf_tree def run(self, opts, args): """Initiates a run with this runner, using the options and arguments. opts is a dict or object with relevant flags args is a list of strings. """ if isinstance(opts, dict): opts = Dummy(**opts) cwd = os.getcwd() environ = dict(os.environ) uuid = str(uuid4()) work_files = [] try: return self.run_impl(opts, args, uuid, work_files) finally: # Close handle on specific log file try: self.event_handler.contexts[uuid].handle.close() except (KeyError, IOError, AttributeError): pass # Remove work files for work_file in work_files: try: if os.path.isfile(work_file) or os.path.islink(work_file): os.unlink(work_file) elif os.path.isdir(work_file): shutil.rmtree(work_file) except OSError: pass # Change back to original working directory try: os.chdir(cwd) except OSError: pass # Reset os.environ os.environ = dict(environ) __call__ = run def run_impl(self, opts, args, uuid, work_files): """Sub-class should implement the actual logic for a run. uuid is a unique identifier for a run. work_files is a list of files, which are removed at the end of a run. """ raise NotImplementedError()
class Runner(object): """Invoke a Rose application or a Rose suite.""" CONF_NAME = None NAME = None OPTIONS = [] REC_OPT_DEFINE = re.compile(r"\A(?:\[([^\]]+)\])?([^=]+)?(?:=(.*))?\Z") def __init__(self, event_handler=None, popen=None, config_pm=None, fs_util=None, suite_engine_proc=None): if not self.CONF_NAME: self.CONF_NAME = self.NAME self.event_handler = event_handler if popen is None: popen = RosePopener(event_handler) self.popen = popen if fs_util is None: fs_util = FileSystemUtil(event_handler) self.fs_util = fs_util if config_pm is None: config_pm = ConfigProcessorsManager(event_handler, popen, fs_util) self.config_pm = config_pm if suite_engine_proc is None: suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=event_handler, popen=popen, fs_util=fs_util) self.suite_engine_proc = suite_engine_proc self.conf_tree_loader = ConfigTreeLoader() def handle_event(self, *args, **kwargs): """Handle an event using the runner's event handler.""" if callable(self.event_handler): return self.event_handler(*args, **kwargs) def config_load(self, opts): """Combine main config file with optional ones and defined ones. Return an instance of rose.config_tree.ConfigTree. """ # Main configuration file conf_dir = opts.conf_dir if conf_dir is None: conf_dir = os.getcwd() conf_dir_orig = conf_dir conf_name = "rose-" + self.CONF_NAME + ".conf" while not os.access(os.path.join(conf_dir, conf_name), os.F_OK | os.R_OK): conf_dir = self.fs_util.dirname(conf_dir) if conf_dir == self.fs_util.dirname(conf_dir): # is root raise ConfigNotFoundError(conf_dir_orig, conf_name) # Optional configuration files opt_conf_keys = [] opt_conf_keys_env = os.getenv("ROSE_%s_OPT_CONF_KEYS" % self.CONF_NAME.upper()) if opt_conf_keys_env: opt_conf_keys += shlex.split(opt_conf_keys_env) if opts.opt_conf_keys: opt_conf_keys += opts.opt_conf_keys self.handle_event( RunConfigLoadEvent(conf_dir, conf_name, opt_conf_keys, opts.defines)) conf_tree = self.conf_tree_loader.load(conf_dir, conf_name, opt_keys=opt_conf_keys) # Optional defines # N.B. In theory, we should write the values in "opts.defines" to # "conf_tree.node" directly. However, the values in "opts.defines" may # contain "ignore" flags. Rather than replicating the logic for parsing # ignore flags in here, it is actually easier to write the values in # "opts.defines" to a file and pass it to the loader to parse it. if opts.defines: source = TemporaryFile() for define in opts.defines: sect, key, value = self.REC_OPT_DEFINE.match(define).groups() if sect is None: sect = "" if value is None: value = "" source.write("[%s]\n" % sect) if key is not None: source.write("%s=%s\n" % (key, value)) source.seek(0) self.conf_tree_loader.node_loader.load(source, conf_tree.node) return conf_tree def run(self, opts, args): """Initiates a run with this runner, using the options and arguments. opts is a dict or object with relevant flags args is a list of strings. """ if isinstance(opts, dict): opts = Dummy(**opts) cwd = os.getcwd() environ = {} for k, v in os.environ.items(): environ[k] = v uuid = str(uuid4()) work_files = [] try: return self.run_impl(opts, args, uuid, work_files) finally: # Close handle on specific log file try: self.event_handler.contexts.get(uuid).handle.close() except: pass # Remove work files for work_file in work_files: try: if os.path.isfile(work_file) or os.path.islink(work_file): os.unlink(work_file) elif os.path.isdir(work_file): shutil.rmtree(work_file) except: pass # Change back to original working directory try: os.chdir(cwd) except: pass # Reset os.environ os.environ = {} for k, v in environ.items(): os.environ[k] = v __call__ = run def run_impl(self, opts, args, uuid, work_files): """Sub-class should implement the actual logic for a run. uuid is a unique identifier for a run. work_files is a list of files, which are removed at the end of a run. """ raise NotImplementedError()
class Runner(object): """Invoke a Rose application or a Rose suite.""" CONF_NAME = None NAME = None OPTIONS = [] REC_OPT_DEFINE = re.compile(r"\A(?:\[([^\]]+)\])?([^=]+)?(?:=(.*))?\Z") def __init__(self, event_handler=None, popen=None, config_pm=None, fs_util=None, suite_engine_proc=None): if not self.CONF_NAME: self.CONF_NAME = self.NAME self.event_handler = event_handler if popen is None: popen = RosePopener(event_handler) self.popen = popen if fs_util is None: fs_util = FileSystemUtil(event_handler) self.fs_util = fs_util if config_pm is None: config_pm = ConfigProcessorsManager(event_handler, popen, fs_util) self.config_pm = config_pm if suite_engine_proc is None: suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=event_handler, popen=popen, fs_util=fs_util) self.suite_engine_proc = suite_engine_proc self.conf_tree_loader = ConfigTreeLoader() def handle_event(self, *args, **kwargs): """Handle an event using the runner's event handler.""" if callable(self.event_handler): return self.event_handler(*args, **kwargs) def config_load(self, opts): """Combine main config file with optional ones and defined ones. Return an instance of rose.config_tree.ConfigTree. """ # Main configuration file conf_dir = opts.conf_dir if conf_dir is None: conf_dir = os.getcwd() conf_dir_orig = conf_dir conf_name = "rose-" + self.CONF_NAME + ".conf" while not os.access(os.path.join(conf_dir, conf_name), os.F_OK | os.R_OK): conf_dir = self.fs_util.dirname(conf_dir) if conf_dir == self.fs_util.dirname(conf_dir): # is root raise ConfigNotFoundError(conf_dir_orig, conf_name) # Optional configuration files opt_conf_keys = [] opt_conf_keys_env = os.getenv("ROSE_%s_OPT_CONF_KEYS" % self.CONF_NAME.upper()) if opt_conf_keys_env: opt_conf_keys += shlex.split(opt_conf_keys_env) if opts.opt_conf_keys: opt_conf_keys += opts.opt_conf_keys self.handle_event(RunConfigLoadEvent( conf_dir, conf_name, opt_conf_keys, opts.defines)) conf_tree = self.conf_tree_loader.load(conf_dir, conf_name, opt_keys=opt_conf_keys) # Optional defines # N.B. In theory, we should write the values in "opts.defines" to # "conf_tree.node" directly. However, the values in "opts.defines" may # contain "ignore" flags. Rather than replicating the logic for parsing # ignore flags in here, it is actually easier to write the values in # "opts.defines" to a file and pass it to the loader to parse it. if opts.defines: source = TemporaryFile() for define in opts.defines: sect, key, value = self.REC_OPT_DEFINE.match(define).groups() if sect is None: sect = "" if value is None: value = "" source.write("[%s]\n" % sect) if key is not None: source.write("%s=%s\n" % (key, value)) source.seek(0) self.conf_tree_loader.node_loader.load(source, conf_tree.node) return conf_tree def run(self, opts, args): """Initiates a run with this runner, using the options and arguments. opts is a dict or object with relevant flags args is a list of strings. """ if isinstance(opts, dict): opts = Dummy(**opts) cwd = os.getcwd() environ = {} for k, v in os.environ.items(): environ[k] = v uuid = str(uuid4()) work_files = [] try: return self.run_impl(opts, args, uuid, work_files) finally: # Close handle on specific log file try: self.event_handler.contexts.get(uuid).handle.close() except: pass # Remove work files for work_file in work_files: try: if os.path.isfile(work_file) or os.path.islink(work_file): os.unlink(work_file) elif os.path.isdir(work_file): shutil.rmtree(work_file) except: pass # Change back to original working directory try: os.chdir(cwd) except: pass # Reset os.environ os.environ = {} for k, v in environ.items(): os.environ[k] = v __call__ = run def run_impl(self, opts, args, uuid, work_files): """Sub-class should implement the actual logic for a run. uuid is a unique identifier for a run. work_files is a list of files, which are removed at the end of a run. """ raise NotImplementedError()