def main(): """Implement "rose suite-hook" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("mail_cc", "mail", "retrieve_job_logs", "shutdown") opts, args = opt_parser.parse_args() for key in ["mail_cc"]: values = [] if getattr(opts, key): for value in getattr(opts, key): values.extend(value.split(",")) setattr(opts, key, values) report = Reporter(opts.verbosity - opts.quietness - 1) # Reduced default popen = RosePopener(event_handler=report) suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=report, popen=popen) args = suite_engine_proc.process_suite_hook_args(*args, **vars(opts)) hook = RoseSuiteHook(event_handler=report, popen=popen, suite_engine_proc=suite_engine_proc) hook(*args, should_mail=opts.mail, mail_cc_list=opts.mail_cc, should_shutdown=opts.shutdown, should_retrieve_job_logs=opts.retrieve_job_logs)
def main(): """Implement "rose suite-shutdown".""" argv = sys.argv[1:] method_name = argv.pop(0) opt_parser = RoseOptionParser() opt_parser.add_my_options("name", "non_interactive") opts, args = opt_parser.parse_args(argv) event_handler = Reporter(opts.verbosity - opts.quietness) suite_control = SuiteControl(event_handler=event_handler) method = getattr(suite_control, method_name) confirm = None suite_names = [] if not opts.non_interactive: confirm = prompt else: if opts.name: suite_names.append(opts.name) else: try: suite_name = get_suite_name(event_handler) suite_names.append(suite_name) except SuiteNotFoundError as exc: event_handler(exc) sys.exit(1) if opts.debug_mode: for sname in suite_names: method(sname, confirm, sys.stderr, sys.stdout, *args) else: for sname in suite_names: try: method(sname, confirm, sys.stderr, sys.stdout, *args) except Exception as exc: event_handler(exc) sys.exit(1)
def main(): """Launcher for the CLI.""" opt_parser = RoseOptionParser() opt_parser.add_my_options('name') opts, args = opt_parser.parse_args(sys.argv[1:]) event_handler = Reporter(opts.verbosity - opts.quietness) suite_vc_cmp = SuiteVCComparator(event_handler) suite_name = opts.name if not suite_name and args: suite_name = args[0] if not suite_name: suite_name = os.getenv(suite_vc_cmp.suite_engine_proc.SUITE_NAME_ENV) if not suite_name: opt_parser.print_usage(sys.stderr) sys.exit(2) try: lines = suite_vc_cmp.cmp_source_vc_info(suite_name=suite_name) except Exception as exc: event_handler(exc) traceback.print_exc() sys.exit(2) else: if lines is None: event_handler( '%s: rose-suite-run.version: VC info not found' % ( suite_name), kind=Reporter.KIND_ERR, level=Reporter.FAIL) sys.exit(2) lines = list(line for line in lines) for line in lines: event_handler('%s\n' % line, prefix='') if lines: sys.exit(1) else: sys.exit(0)
def main(): """Implement "rose env-cat".""" opt_parser = RoseOptionParser(usage='rose env-cat [OPTIONS] [FILE ...]', description=r''' Substitute environment variables in input files and print. If no argument is specified, read from STDIN. One `FILE` argument may be `-`, which means read from STDIN. In `match-mode=default`, the command will look for `$NAME` or `${NAME}` syntax and substitute them with the value of the environment variable `NAME`. A backslash in front of the syntax, e.g. `\$NAME` or `\${NAME}` will escape the substitution. In `match-mode=brace`, the command will look for `${NAME}` syntax only. EXAMPLES rose env-cat [OPTIONS] [FILE ...] ''') opt_parser.add_my_options("match_mode", "output_file", "unbound") opt_parser.modify_option( 'output_file', help=("Specify an output file." "\nIf no output file is specified or if `FILE`" "is `-`, write output to STDOUT."), ) opts, args = opt_parser.parse_args() rose_env_cat(args, opts)
def main(): """Implement the "rose config-dump" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("conf_dir", "files", "no_pretty_mode") opts = opt_parser.parse_args()[0] verbosity = opts.verbosity - opts.quietness report = Reporter(verbosity) fs_util = FileSystemUtil(report) if opts.conf_dir: fs_util.chdir(opts.conf_dir) file_names = [] if opts.files: file_names = opts.files else: for dirpath, _, filenames in os.walk("."): for filename in fnmatch.filter(filenames, "rose-*.conf"): path = os.path.join(dirpath, filename)[2:] # remove leading ./ file_names.append(path) for file_name in file_names: handle = NamedTemporaryFile() node = ConfigLoader()(file_name) if (not opts.no_pretty_mode and os.path.basename(file_name) != META_CONFIG_NAME): pretty_format_config(node, ignore_error=True) ConfigDumper()(node, handle) handle.seek(0) if not filecmp.cmp(handle.name, file_name, shallow=False): report(ConfigDumpEvent(file_name)) ConfigDumper()(node, file_name)
def main(): """Launcher for command line invokation of metomi.rose stem.""" # Process options opt_parser = RoseOptionParser() option_keys = SuiteRunner.OPTIONS + OPTIONS opt_parser.add_my_options(*option_keys) opts, args = opt_parser.parse_args() # Set up a runner instance and process the options stem = StemRunner(opts) if opts.debug_mode: opts = stem.process() else: try: opts = stem.process() except Exception as exc: stem.reporter(exc) sys.exit(1) # Get the suiterunner object and execute runner = SuiteRunner(event_handler=stem.reporter, popen=stem.popen, fs_util=stem.fs_util) if opts.debug_mode: sys.exit(runner(opts, args)) try: sys.exit(runner(opts, args)) except Exception as exc: runner.handle_event(exc) if isinstance(exc, RosePopenError): sys.exit(exc.ret_code) else: sys.exit(1)
def main(): """rose task-env.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("cycle", "cycle_offsets", "path_globs", "prefix_delim", "suffix_delim") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness - 1) suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=report) kwargs = dict(vars(opts)) try: task_props = suite_engine_proc.get_task_props(*args, **kwargs) for key, value in task_props: report(str(EnvExportEvent(key, value)) + "\n", level=0) path_globs = opts.path_globs if path_globs is None: path_globs = [] prepend_paths_map = get_prepend_paths(report, task_props.suite_dir, path_globs, full_mode=True) for key, prepend_paths in prepend_paths_map.items(): orig_paths = [] orig_v = os.getenv(key, "") if orig_v: orig_paths = orig_v.split(os.pathsep) path = os.pathsep.join(prepend_paths + orig_paths) report(str(EnvExportEvent(key, path)) + "\n", level=0) except Exception as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1)
def parse_cli(*args, **kwargs): """Parse command line, start/stop ad-hoc server. Return a CLI instruction tuple for a valid command instruction, else False: ("start", Boolean, port): start server on 'port', [2]==True indicating non_interactive mode. ("stop", Boolean): stop server, [2]==True indicating service_root_mode. None: bare command, requesting to print server status """ opt_parser = RoseOptionParser() opt_parser.add_my_options("non_interactive", "service_root_mode") opts, args = opt_parser.parse_args() arg = None if args: arg = args[0] if arg == "start": port = DEFAULT_PORT if args[1:]: try: port = int(args[1]) except ValueError: print("Invalid port specified. Using the default port.") return ("start", opts.service_root_mode, port) elif arg == "stop": return ("stop", opts.non_interactive) elif arg: # unrecognised (invalid) argument, to ignore return False # False to distinguish from None for no arguments given
def main(): """Implement "rose env-cat".""" opt_parser = RoseOptionParser() opt_parser.add_my_options("match_mode", "output_file", "unbound") opts, args = opt_parser.parse_args() if not args: args = ["-"] if not opts.output_file or opts.output_file == "-": out_handle = sys.stdout else: out_handle = open(opts.output_file, "wb") for arg in args: if arg == "-": in_handle = sys.stdin else: in_handle = open(arg) line_num = 0 while True: line_num += 1 line = in_handle.readline() if not line: break try: out_handle.write( env_var_process(line, opts.unbound, opts.match_mode)) except UnboundEnvironmentVariableError as exc: name = arg if arg == "-": name = "<STDIN>" sys.exit("%s:%s: %s" % (name, line_num, str(exc))) in_handle.close() out_handle.close()
def main(): """Implement "rose env-cat".""" opt_parser = RoseOptionParser(usage='rose env-cat [OPTIONS] [FILE ...]', description=r''' Substitute environment variables in input files and print. If no argument is specified, read from STDIN. One `FILE` argument may be `-`, which means read from STDIN. In `match-mode=default`, the command will look for `$NAME` or `${NAME}` syntax and substitute them with the value of the environment variable `NAME`. A backslash in front of the syntax, e.g. `\$NAME` or `\${NAME}` will escape the substitution. In `match-mode=brace`, the command will look for `${NAME}` syntax only. EXAMPLES rose env-cat [OPTIONS] [FILE ...] ''') opt_parser.add_my_options("match_mode", "output_file", "unbound") opt_parser.modify_option( 'output_file', help=("Specify an output file." "\nIf no output file is specified or if `FILE`" "is `-`, write output to STDOUT."), ) opts, args = opt_parser.parse_args() if not args: args = ["-"] if not opts.output_file or opts.output_file == "-": out_handle = sys.stdout else: out_handle = open(opts.output_file, "wb") for arg in args: if arg == "-": in_handle = sys.stdin else: in_handle = open(arg) line_num = 0 while True: line_num += 1 line = in_handle.readline() if not line: break try: out_handle.write( env_var_process(line, opts.unbound, opts.match_mode)) except UnboundEnvironmentVariableError as exc: name = arg if arg == "-": name = "<STDIN>" sys.exit("%s:%s: %s" % (name, line_num, str(exc))) in_handle.close() out_handle.close()
def main(): """Launcher for the CLI.""" opt_parser = RoseOptionParser( usage='%prog [OPTIONS] [--] [COMMAND ...]', description=''' Run an application according to its configuration. May run a builtin application (if the `mode` setting in the configuration specifies the name of a builtin application) or a command. Determine the command to run in this order: 1. If `COMMAND` is specified, invoke the command. 2. If the `--command-key=KEY` option is defined, invoke the command specified in `[command]KEY`. 3. If the `ROSE_APP_COMMAND_KEY` environment variable is set, the command specified in the `[command]KEY` setting in the application configuration whose `KEY` matches it is used. 4. If the environment variable `ROSE_TASK_NAME` is defined and a setting in the `[command]` section has a key matching the value of the environment variable, then the value of the setting is used as the command. 5. Invoke the command specified in `[command]default`. ''', epilog=''' ENVIRONMENT VARIABLES optional ROSE_APP_COMMAND_KEY Switch to a particular command specified in `[command]KEY`. optional ROSE_APP_MODE Specifies a builtin application to run. optional ROSE_APP_OPT_CONF_KEYS Each `KEY` in this space delimited list switches on an optional configuration. The configurations are applied first-to-last. optional ROSE_FILE_INSTALL_ROOT If specified, change to the specified directory to install files. ''' ) option_keys = AppRunner.OPTIONS opt_parser.add_my_options(*option_keys) opts, args = opt_parser.parse_args() event_handler = Reporter(opts.verbosity - opts.quietness) runner = AppRunner(event_handler) try: sys.exit(runner(opts, args)) except Exception as exc: runner.handle_event(exc) if opts.debug_mode: traceback.print_exc() if isinstance(exc, RosePopenError): sys.exit(exc.ret_code) else: sys.exit(1)
def main(): """Launcher for the CLI.""" opt_parser = RoseOptionParser( usage='rose task-run [OPTIONS] [--] [APP-COMMAND ...]', description=''' Provide an environment to run a suite task. Provides environment variables documented in `rose task-env`. It is worth noting that if the environment variables are already provided by `rose task-env`, this command will not override them. Normally, the suite task will select a Rose application configuration that has the same name as the task. This can be overridden by the `--app-key=KEY` option or the `ROSE_TASK_APP` environment variable. SHORT OPTIONS All options of `rose app-run` and `rose task-env` are supported. Additional options are: --app-key=KEY Specify a named application configuration. ''', epilog=''' ENVIRONMENT VARIABLES All environment variables of `rose app-run` and `rose task-env` are supported. All environment variables documented in `rose task-env` are passed to the application `rose task-run` runs. The following environment variables are used by `rose task-run`: ROSE_TASK_APP Specify a named application configuration. SEE ALSO * `rose app-run` * `rose task-env` ''', ) option_keys = TaskRunner.OPTIONS opt_parser.add_my_options(*option_keys) opts, args = opt_parser.parse_args() event_handler = Reporter(opts.verbosity - opts.quietness) runner = TaskRunner(event_handler) try: sys.exit(runner(opts, args)) except Exception as exc: runner.handle_event(exc) if opts.debug_mode: traceback.print_exc() if isinstance(exc, RosePopenError): sys.exit(exc.ret_code) else: sys.exit(1)
def main(): """Implement "rose date".""" opt_parser = RoseOptionParser() opt_parser.add_my_options( "calendar", "diff", "offsets1", "offsets2", "parse_format", "print_format", "task_cycle_time_mode", "as_total", "utc_mode", ) opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) ref_point_str = None if opts.task_cycle_time_mode: ref_point_str = os.getenv(RoseDateTimeOperator.TASK_CYCLE_TIME_ENV) if ref_point_str is None: exc = UnboundEnvironmentVariableError( RoseDateTimeOperator.TASK_CYCLE_TIME_ENV) report(exc) if opts.debug_mode: raise exc sys.exit(1) date_time_oper = RoseDateTimeOperator( parse_format=opts.parse_format, utc_mode=opts.utc_mode, calendar_mode=opts.calendar, ref_point_str=ref_point_str, ) try: if len(args) < 2: if opts.duration_print_format: _convert_duration(date_time_oper, opts, args) else: _print_time_point(date_time_oper, opts, args) else: _print_duration(date_time_oper, opts, args) except OffsetValueError as exc: report(exc) if opts.debug_mode: raise exc sys.exit(1)
def main(): """Implement "rose suite-log" CLI.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("archive_mode", "force_mode", "name", "non_interactive", "prune_remote_mode", "update_mode", "user", "view_mode") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) try: suite_log_view(opts, args, report) except Exception as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1)
def main(): """CLI for "rose namelist-dump".""" opt_parser = RoseOptionParser( usage='rose-namelist-dump [OPTIONS] [FILE ...]', description=''' Convert namelist files into a Rose application configuration snippet. Each argument should be the path to an empty file or a file containing Fortran namelist groups. A `-` can be used once in the argument list to specify the standard input. If no argument is given, it assumes the standard input is specified. Where possible, use relative path for file names, as the file names appear as-specified in the generated configuration. ''', ) opt_parser.add_my_options("case_mode", "lower", "output_file", "upper") opts, args = opt_parser.parse_args() return namelist_dump(args, opts.output_file, opts.case_mode)
def main(): """Launcher for the CLI.""" opt_parser = RoseOptionParser() option_keys = AppRunner.OPTIONS opt_parser.add_my_options(*option_keys) opts, args = opt_parser.parse_args(sys.argv[1:]) event_handler = Reporter(opts.verbosity - opts.quietness) runner = AppRunner(event_handler) try: sys.exit(runner(opts, args)) except Exception as exc: runner.handle_event(exc) if opts.debug_mode: traceback.print_exc() if isinstance(exc, RosePopenError): sys.exit(exc.ret_code) else: sys.exit(1)
def main(): """Implement the "rose suite-id" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("latest", "next", "to_local_copy", "to_origin", "to_output", "to_web") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) SuiteId.svn.event_handler = report # FIXME: ugly? arg = None if args: arg = args[0] try: if opts.to_origin: for arg in args: report(str(SuiteId(id_text=arg).to_origin()) + "\n", level=0) elif opts.to_local_copy: for arg in args: report(str(SuiteId(id_text=arg).to_local_copy()) + "\n", level=0) elif opts.to_output: for arg in args: url = SuiteId(id_text=arg).to_output() report(str(url) + "\n", level=0) elif opts.to_web: for arg in args: report(str(SuiteId(id_text=arg).to_web()) + "\n", level=0) elif opts.latest: suite_id = SuiteId.get_latest(prefix=arg) if suite_id is not None: report(str(suite_id) + "\n", level=0) elif opts.next: suite_id = SuiteId.get_next(prefix=arg) if suite_id is not None: report(str(suite_id) + "\n", level=0) else: if not arg: arg = os.getcwd() report(str(SuiteId(location=arg)) + "\n", level=0) except (NoSuiteLogError, SuiteIdError) as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1)
def main(): """Implement the "rose config-dump" command.""" opt_parser = RoseOptionParser(description=''' Re-dump Rose configuration files in the common format. Load and dump `"rose-*.conf"` files in place. Apply format-specific pretty-printing. By default, it recursively loads and dumps all `rose-*.conf` files in the current working directory. EXAMPLES rose config-dump rose config-dump -C /path/to/conf/dir rose config-dump -f /path/to/file1 -f /path/to/file2 ''') opt_parser.add_my_options("conf_dir", "files", "no_pretty_mode") opts = opt_parser.parse_args()[0] verbosity = opts.verbosity - opts.quietness report = Reporter(verbosity) fs_util = FileSystemUtil(report) if opts.conf_dir: fs_util.chdir(opts.conf_dir) file_names = [] if opts.files: file_names = opts.files else: for dirpath, _, filenames in os.walk("."): for filename in fnmatch.filter(filenames, "rose-*.conf"): path = os.path.join(dirpath, filename)[2:] # remove leading ./ file_names.append(path) for file_name in file_names: handle = NamedTemporaryFile() node = ConfigLoader()(file_name) if (not opts.no_pretty_mode and os.path.basename(file_name) != META_CONFIG_NAME): pretty_format_config(node, ignore_error=True) ConfigDumper()(node, handle) handle.seek(0) if not filecmp.cmp(handle.name, file_name, shallow=False): report(ConfigDumpEvent(file_name)) ConfigDumper()(node, file_name)
def main(): """Implement the "rose host-select" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("choice", "rank_method", "thresholds", "timeout") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) popen = RosePopener(event_handler=report) select = HostSelector(event_handler=report, popen=popen) try: host_score_list = select(names=args, rank_method=opts.rank_method, thresholds=opts.thresholds, ssh_cmd_timeout=opts.timeout) except (NoHostError, NoHostSelectError) as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1) opts.choice = int(opts.choice) report(choice(host_score_list[0:opts.choice])[0] + "\n", level=0)
def main(): """Launcher for the CLI.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("host", "name") opts, args = opt_parser.parse_args(sys.argv[1:]) event_handler = Reporter(opts.verbosity - opts.quietness) suite_restarter = SuiteRestarter(event_handler) try: sys.exit(suite_restarter.restart( suite_name=opts.name, host=opts.host, args=args)) except Exception as exc: event_handler(exc) if opts.debug_mode: traceback.print_exc() if isinstance(exc, RosePopenError): sys.exit(exc.ret_code) else: sys.exit(1)
def parse_cli(*args, **kwargs): """Parse command line, start/stop ad-hoc server. Return a CLI instruction tuple for a valid command instruction, else False: ("start", Boolean, port): start server on 'port', [2]==True indicating non_interactive mode. ("stop", Boolean): stop server, [2]==True indicating service_root_mode. None: bare command, requesting to print server status """ opt_parser = RoseOptionParser(description=''' Start/stop ad-hoc Rosie suite discovery web service server. For `rosie disco start`, if `PORT` is not specified, use port 8080. Examples: rosie disco start [PORT] # start ad-hoc web service server (on PORT) rosie disco stop # stop ad-hoc web service server rosie disco stop -y # stop ad-hoc web service server w/o prompting rosie disco # print status of ad-hoc web service server ''', ) opt_parser.add_my_options("non_interactive", "service_root_mode") opts, args = opt_parser.parse_args() arg = None if args: arg = args[0] if arg == "start": port = DEFAULT_PORT if args[1:]: try: port = int(args[1]) except ValueError: print("Invalid port specified. Using the default port.") return ("start", opts.service_root_mode, port) elif arg == "stop": return ("stop", opts.non_interactive) elif arg: # unrecognised (invalid) argument, to ignore return False # False to distinguish from None for no arguments given
def main(): """Implement the "rose suite-clean" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("name", "non_interactive", "only_items") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) cleaner = SuiteRunCleaner(event_handler=report) if opts.name: args.append(opts.name) if not args: args = [os.path.basename(os.getcwd())] os.chdir(os.path.expanduser('~')) n_done = 0 for arg in args: if not opts.non_interactive: try: answer = input("Clean %s? y/n (default n) " % arg) except EOFError: sys.exit(1) if answer not in ["Y", "y"]: continue try: cleaner.clean(arg, opts.only_items) except ( OSError, IOError, ConfigSyntaxError, RosePopenError, SuiteStillRunningError, ) as exc: report(exc) if opts.debug_mode: traceback.print_exc() else: n_done += 1 sys.exit(len(args) - n_done) # Return 0 if everything done
def main(): """Implement the "rose suite-id" command.""" opt_parser = RoseOptionParser(description=''' Utility for working with suite IDs. EXAMPLES: # Print the repository URL of a given suite ID rosie id --to-origin mo1-abc45 # Print the local location of a given suite ID rosie id --to-local-copy mo1-abc45 # Print the web URL of a given suite ID rosie id --to-web mo1-abc45 # Print suite ID of working copy in $PWD rosie id # Print suite ID of working copy in a directory rosie id /path/to/working/copy # Print suite ID of a given URL rosie id svn://fcm1/rose_mo1_svn/a/b/c/4/5 # Print latest suite ID in the default repository rosie id --latest # Print latest suite ID in the given repository rosie id --latest mot # Print next suite ID in the default repository rosie id --next ''', ) opt_parser.add_my_options("latest", "next", "to_local_copy", "to_origin", "to_web") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) SuiteId.svn.event_handler = report # FIXME: ugly? arg = None if args: arg = args[0] try: if opts.to_origin: for arg in args: report(str(SuiteId(id_text=arg).to_origin()) + "\n", level=0) elif opts.to_local_copy: for arg in args: report(str(SuiteId(id_text=arg).to_local_copy()) + "\n", level=0) elif opts.to_web: for arg in args: report(str(SuiteId(id_text=arg).to_web()) + "\n", level=0) elif opts.latest: suite_id = SuiteId.get_latest(prefix=arg) if suite_id is not None: report(str(suite_id) + "\n", level=0) elif opts.next: suite_id = SuiteId.get_next(prefix=arg) if suite_id is not None: report(str(suite_id) + "\n", level=0) else: if not arg: arg = os.getcwd() report(str(SuiteId(location=arg)) + "\n", level=0) except (NoSuiteLogError, SuiteIdError) as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1)
def main(): """Implement the "rose config" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("default", "env_var_process_mode", "files", "keys", "meta", "meta_key", "no_ignore", "no_opts", "print_conf_mode") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) metomi.rose.macro.add_meta_paths() if opts.meta_key: opts.meta = True if opts.files and opts.meta_key: report(Exception("Cannot specify both a file and meta key.")) sys.exit(1) config_loader = ConfigLoader() sources = [] if opts.files: root_node = ConfigNode() for fname in opts.files: if fname == "-": sources.append(sys.stdin) else: if opts.meta: try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) rel_path = os.sep.join(fname.split(os.sep)[:-1]) fpath = get_meta_path(root_node, rel_path) if fpath is None: report(MetadataNotFoundEvent(fname)) else: sources.append(fpath) else: sources.append(fname) elif opts.meta: root_node = ConfigNode() if opts.meta_key: root_node.set(["meta"], opts.meta_key) else: fname = os.path.join(os.getcwd(), metomi.rose.SUB_CONFIG_NAME) try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) fpath = get_meta_path(root_node, meta_key=opts.meta_key) root_node.unset(["meta"]) if fpath is None: report(Exception("Metadata not found")) sys.exit(1) else: sources.append(fpath) else: root_node = ResourceLocator.default().get_conf() for source in sources: try: if opts.meta or opts.no_opts: config_loader.load(source, root_node) else: config_loader.load_with_opts(source, root_node) except (ConfigSyntaxError, IOError) as exc: report(exc) sys.exit(1) if source is sys.stdin: source.close() if opts.quietness: sys.exit(root_node.get(args, opts.no_ignore) is None) if opts.keys_mode: try: keys = list(root_node.get(args, opts.no_ignore).value) except AttributeError: sys.exit(1) keys.sort() for key in keys: print(key) sys.exit() conf_dump = ConfigDumper() if len(args) == 0: conf_dump(root_node, concat_mode=opts.print_conf_mode) sys.exit() node = root_node.get(args, opts.no_ignore) if node is not None and isinstance(node.value, dict): if opts.print_conf_mode: conf_dump(ConfigNode().set(args, node.value), concat_mode=True) sys.exit() keys = list(node.value) keys.sort() for key in keys: node_of_key = node.get([key], opts.no_ignore) if node_of_key: value = node_of_key.value state = node_of_key.state string = "%s%s=%s" % (state, key, value) lines = string.splitlines() print(lines[0]) i_equal = len(state + key) + 1 for line in lines[1:]: print(" " * i_equal + line) sys.exit() if node is None: if opts.default is None: sys.exit(1) value = opts.default elif opts.env_var_process_mode: value = env_var_process(node.value) else: value = node.value if opts.print_conf_mode: conf_dump(ConfigNode().set(args, value), concat_mode=True) else: print(value) sys.exit()
def main(): """Implement the "rose host-select" command.""" opt_parser = RoseOptionParser( usage='rose host-select [OPTIONS] [GROUP/HOST ...]', description=''' Select a host from a set of groups or names by load, by free memory or by random. Print the selected host name. ''', epilog=''' RANKING METHODS IN DETAIL (--rank-method): `load` Rank by average load as reported by `uptime` divided by number of virtual processors. If `METHOD-ARG` is specified, it must be `1`, `5` or `15`. The default is to use the 15 minute load. `fs` Rank by % usage of a file system as reported by `df`. `METHOD-ARG` must be a valid file system in all the given hosts and host groups. The default is to use the `~` directory. `mem` Rank by largest amount of free memory. Uses `free -m` to return memory in Mb `random` No ranking is used. CONFIGURATION The command reads its settings from the `[rose-host-select]` section in the Rose configuration. All settings are optional. Type `rose config rose-host-select` to print settings. Valid settings are: default = GROUP/HOST ... The default arguments to use for this command. group{NAME} = GROUP/HOST ... Declare a named group of hosts. method{NAME} = METHOD[:METHOD-ARG] Declare the default ranking method for a group of hosts. thresholds{NAME} = [METHOD[:METHOD-ARG]:]VALUE ... Declare the default threshold(s) for a group of hosts. timeout = FLOAT Set the timeout in seconds of SSH commands to hosts. (default=10.0) ''' ) opt_parser.add_my_options("choice", "rank_method", "thresholds", "timeout") opt_parser.modify_option( 'timeout', help='Set the timeout in seconds of SSH commands to hosts.', ) opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) popen = RosePopener(event_handler=report) select = HostSelector(event_handler=report, popen=popen) try: host_score_list = select( names=args, rank_method=opts.rank_method, thresholds=opts.thresholds, ssh_cmd_timeout=opts.timeout, ) except (NoHostError, NoHostSelectError) as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1) opts.choice = int(opts.choice) report(choice(host_score_list[0 : opts.choice])[0] + "\n", level=0)
def create(argv): """CLI function: create and copy.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("checkout_mode", "info_file", "meta_suite_mode", "non_interactive", "prefix", "project") opts, args = opt_parser.parse_args(argv) verbosity = opts.verbosity - opts.quietness client = RosieVCClient(event_handler=Reporter(verbosity)) SuiteId.svn.event_handler = client.event_handler from_id = None if args: from_id = SuiteId(id_text=args[0]) if from_id.branch is None: from_id.branch = from_id.BRANCH_TRUNK if from_id.revision is None: from_id.revision = from_id.REV_HEAD from_id = SuiteId(id_text=from_id.to_string_with_version()) interactive_mode = not opts.non_interactive if opts.info_file is None: info_config = client.generate_info_config(from_id, opts.prefix, opts.project) if from_id is not None: meta_config = load_meta_config( info_config, directory=None, config_type=metomi.rose.INFO_CONFIG_NAME, error_handler=None, ignore_meta_error=False) for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.replace("=", "") if key == "copy-mode" and value == "clear": info_config.set([sect], "") if key == "copy-mode" and value == "never": info_config.unset([sect]) info_config = _edit_info_config(opts, client, info_config) else: file_ = opts.info_file if opts.info_file == "-": file_ = sys.stdin info_config = metomi.rose.config.load(file_) info_config = _validate_info_config(opts, client, info_config) if interactive_mode: prefix = opts.prefix if from_id: if not prefix: prefix = from_id.prefix question = PROMPT_COPY % (from_id.to_string_with_version(), prefix) else: if not prefix: prefix = SuiteId.get_prefix_default() question = PROMPT_CREATE % prefix try: response = input(question) except EOFError: sys.exit(1) if response != YES: sys.exit(1) try: id_ = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteIdOverflowError) as exc: client.event_handler(exc) sys.exit(1) if opts.checkout_mode: try: client.checkout(id_) except (FileExistError, RosePopenError) as exc: client.event_handler(exc) sys.exit(1)
def create(): """CLI function: create and copy.""" opt_parser = RoseOptionParser( usage=('rosie create [OPTIONS]' '\n rosie copy [OPTIONS] ID-OF-EXISTING-SUITE'), description=''' rosie create: Create a new suite rosie copy : Create a new suite and copy content from an existing one. Assign a new `ID` and create the directory structure in the central repository for a new suite. The location of the repository for the new suite is determined in order of preference: 1. `--prefix=PREFIX` option 2. prefix of the `ID-OF-EXISTING-SUITE` 3. `[rosie-id]prefix-default` option in the site/user configuration. If `ID-OF-EXISTING-SUITE` is specified, copy items from the existing suite `ID-OF-EXISTING-SUITE` when the suite is created. It is worth noting that revision history of the copied items can only be preserved if `ID-OF-EXISTING-SUITE` is in the same repository of the new suite The syntax of the ID-OF-EXISTING-SUITE is PREFIX-xxNNN[/BRANCH][@REV] (e.g. my-su173, my-su173/trunk, my-su173/trunk@HEAD). If REV is not specified, the last changed revision of the branch is used. If BRANCH is not specified, "trunk" is used. NOTE: ID-OF-EXISTING-SUITE is _not_ a filepath. ''', ) opt_parser.add_my_options( "checkout_mode", "info_file", "meta_suite_mode", "non_interactive", "prefix", "project", ) opts, args = opt_parser.parse_args() verbosity = opts.verbosity - opts.quietness client = RosieVCClient(event_handler=Reporter(verbosity)) SuiteId.svn.event_handler = client.event_handler from_id = None if args: from_id = SuiteId(id_text=args[0]) if from_id.branch is None: from_id.branch = from_id.BRANCH_TRUNK if from_id.revision is None: from_id.revision = from_id.REV_HEAD from_id = SuiteId(id_text=from_id.to_string_with_version()) interactive_mode = not opts.non_interactive if opts.info_file is None: info_config = client.generate_info_config(from_id, opts.prefix, opts.project) if from_id is not None: meta_config = load_meta_config( info_config, directory=None, config_type=metomi.rose.INFO_CONFIG_NAME, error_handler=None, ignore_meta_error=False, ) for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.replace("=", "") if key == "copy-mode" and value == "clear": info_config.set([sect], "") if key == "copy-mode" and value == "never": info_config.unset([sect]) info_config = _edit_info_config(opts, client, info_config) else: file_ = opts.info_file if opts.info_file == "-": file_ = sys.stdin info_config = metomi.rose.config.load(file_) info_config = _validate_info_config(opts, client, info_config) if interactive_mode: prefix = opts.prefix if from_id: if not prefix: prefix = from_id.prefix question = PROMPT_COPY % (from_id.to_string_with_version(), prefix) else: if not prefix: prefix = SuiteId.get_prefix_default() question = PROMPT_CREATE % prefix try: response = input(question) except EOFError: sys.exit(1) if response != YES: sys.exit(1) try: id_ = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteIdOverflowError) as exc: client.event_handler(exc) sys.exit(1) if opts.checkout_mode: try: client.checkout(id_) except (FileExistError, RosePopenError) as exc: client.event_handler(exc) sys.exit(1)
def main(): """CLI for "rose namelist-dump".""" opt_parser = RoseOptionParser() opt_parser.add_my_options("case_mode", "lower", "output_file", "upper") opts, args = opt_parser.parse_args() return namelist_dump(args, opts.output_file, opts.case_mode)
def main(): """Implement the "rose config" command.""" opt_parser = RoseOptionParser(description=''' Parse and print rose configuration files. With no option and no argument, print the rose site + user configuration. EXAMPLES # Print the value of OPTION in SECTION. rose config SECTION OPTION # Print the value of OPTION in SECTION in FILE. rose config --file=FILE SECTION OPTION # Print the value of OPTION in SECTION if exists, or VALUE otherwise. rose config --default=VALUE SECTION OPTION # Print the OPTION=VALUE pairs in SECTION. rose config SECTION # Print the value of a top level OPTION. rose config OPTION # Print the OPTION keys in SECTION. rose config --keys SECTION # Print the SECTION keys. rose config --keys # Exit with 0 if OPTION exists in SECTION, or 1 otherwise. rose config -q SECTION OPTION # Exit with 0 if SECTION exists, or 1 otherwise. rose config -q SECTION # Combine the configurations in FILE1 and FILE2, and dump the result. rose config --file=FILE1 --file=FILE2 # Print the value of OPTION in SECTION of the metadata associated with # the specified config FILE rose config --file=FILE --meta SECTION OPTION # Print the value of a specified metadata KEY rose config --meta-key=KEY ''', epilog=''' ENVIRONMENT VARIABLES optional ROSE_META_PATH Prepend `$ROSE_META_PATH` to the metadata search path. ''') opt_parser.add_my_options( "default", "env_var_process_mode", "files", "keys", "meta", "meta_key", "no_ignore", "no_opts", "print_conf_mode", ) # the quietness argument is non-standard for this command opt_parser.modify_option( 'quietness', help=("Exit with 0 if the specified `SECTION` and/or `OPTION` exist in" " the configuration, or 1 otherwise."), ) opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) metomi.rose.macro.add_meta_paths() if opts.meta_key: opts.meta = True if opts.files and opts.meta_key: report(Exception("Cannot specify both a file and meta key.")) sys.exit(1) config_loader = ConfigLoader() sources = [] if opts.files: root_node = ConfigNode() for fname in opts.files: if fname == "-": sources.append(sys.stdin) else: if opts.meta: try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) rel_path = os.sep.join(fname.split(os.sep)[:-1]) fpath = get_meta_path(root_node, rel_path) if fpath is None: report(MetadataNotFoundEvent(fname)) else: sources.append(fpath) else: sources.append(fname) elif opts.meta: root_node = ConfigNode() if opts.meta_key: root_node.set(["meta"], opts.meta_key) else: fname = os.path.join(os.getcwd(), metomi.rose.SUB_CONFIG_NAME) try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) fpath = get_meta_path(root_node, meta_key=opts.meta_key) root_node.unset(["meta"]) if fpath is None: report(Exception("Metadata not found")) sys.exit(1) else: sources.append(fpath) else: root_node = ResourceLocator.default().get_conf() for source in sources: try: if opts.meta or opts.no_opts: config_loader.load(source, root_node) else: config_loader.load_with_opts(source, root_node) except (ConfigSyntaxError, IOError) as exc: report(exc) sys.exit(1) if source is sys.stdin: source.close() if opts.quietness: sys.exit(root_node.get(args, opts.no_ignore) is None) if opts.keys_mode: try: keys = list(root_node.get(args, opts.no_ignore).value) except AttributeError: sys.exit(1) keys.sort() for key in keys: print(key) sys.exit() conf_dump = ConfigDumper() if len(args) == 0: conf_dump(root_node, concat_mode=opts.print_conf_mode) sys.exit() node = root_node.get(args, opts.no_ignore) if node is not None and isinstance(node.value, dict): if opts.print_conf_mode: conf_dump(ConfigNode().set(args, node.value), concat_mode=True) sys.exit() keys = list(node.value) keys.sort() for key in keys: node_of_key = node.get([key], opts.no_ignore) if node_of_key: value = node_of_key.value state = node_of_key.state string = "%s%s=%s" % (state, key, value) lines = string.splitlines() print(lines[0]) i_equal = len(state + key) + 1 for line in lines[1:]: print(" " * i_equal + line) sys.exit() if node is None: if opts.default is None: sys.exit(1) value = opts.default elif opts.env_var_process_mode: value = env_var_process(node.value) else: value = node.value if opts.print_conf_mode: conf_dump(ConfigNode().set(args, value), concat_mode=True) else: print(value) sys.exit()
def main(): """rose task-env.""" opt_parser = RoseOptionParser( description=''' STANDARD USAGE: eval $(rose task-env) Provide an environment for cycling suite task. Print `KEY=VALUE` of the following to the STDOUT: `ROSE_SUITE_DIR` The path to the root directory of the running suite. `ROSE_SUITE_DIR_REL` The path to the root directory of the running suite relative to `$HOME`. `ROSE_SUITE_NAME` The name of the running suite. `ROSE_TASK_NAME` The name of the suite task. `ROSE_TASK_CYCLE_TIME` The cycle time of the suite task, if there is one. `ROSE_CYCLING_MODE` The cycling mode of the running suite. `ROSE_TASK_LOG_ROOT` The root path for log files of the suite task. `ROSE_DATA` The path to the data directory of the running suite. `ROSE_DATAC` The path to the data directory of this cycle time in the running suite. `ROSE_DATAC????` The path to the data directory of the cycle time with an offset relative to the current cycle time. `????` is a duration: A `__` (double underscore) prefix denotes a cycle time in the future (because a minus sign cannot be used in an environment variable). Otherwise, it is a cycle time in the past. The rest should be either an ISO 8601 duration, such as: * `P2W` - 2 weeks * `PT12H` - 12 hours * `P1DT6H` - 1 day, 6 hours * `P4M` - 4 months * `PT5M` - 5 minutes Or, for the case of integer cycling suites: * `P1` - 1 cycle before the current cycle * `P5` - 5 cycles before the current cycle Deprecated syntax: * `nW` denotes `n` weeks. * `n` or `nD` denotes `n` days. * `Tn` or `TnH` denotes `n` hours. * `TnM` denotes `n` minutes. * `TnS` denotes `s` seconds. E.g. `ROSE_DATACPT6H` is the data directory of 6 hours before the current cycle time. E.g. `ROSE_DATACP1D` and `ROSE_DATACPT24H` are both the data directory of 1 day before the current cycle time. `ROSE_ETC` The path to the etc directory of the running suite. `ROSE_TASK_PREFIX` The prefix in the task name. `ROSE_TASK_SUFFIX` The suffix in the task name. ''', epilog=''' USAGE IN SUITES rose `task-env` can be used to make environment variables available to a suite by defining its `flow.cylc` `env-script` option as `env-script = eval $(rose task-env)`. ''', ) opt_parser.add_my_options("cycle", "cycle_offsets", "path_globs", "prefix_delim", "suffix_delim") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness - 1) suite_engine_proc = SuiteEngineProcessor.get_processor( event_handler=report) kwargs = dict(vars(opts)) try: task_props = suite_engine_proc.get_task_props(*args, **kwargs) for key, value in task_props: report(str(EnvExportEvent(key, value)) + "\n", level=0) path_globs = opts.path_globs if path_globs is None: path_globs = [] prepend_paths_map = get_prepend_paths(report, task_props.suite_dir, path_globs, full_mode=True) for key, prepend_paths in prepend_paths_map.items(): orig_paths = [] orig_v = os.getenv(key, "") if orig_v: orig_paths = orig_v.split(os.pathsep) path = os.pathsep.join(prepend_paths + orig_paths) report(str(EnvExportEvent(key, path)) + "\n", level=0) except Exception as exc: report(exc) if opts.debug_mode: traceback.print_exc() sys.exit(1)