def checkout(): """CLI function: checkout.""" opt_parser = RoseOptionParser( usage='rosie checkout [OPTIONS] ID ...', description=''' Checkout local copies of suites. For each `ID` in the argument list, checkout a working copy of the suite identified by `ID` to the standard location. ''', ).add_my_options("force_mode") opt_parser.modify_option( 'force_mode', help=('If working copy for suite identified by `ID` already exists,' ' remove it. Continue to the next `ID` if checkout of a suite' ' fails.'), ) opts, args = opt_parser.parse_args() verbosity = opts.verbosity - opts.quietness report = Reporter(verbosity) client = RosieVCClient(event_handler=report, force_mode=opts.force_mode) SuiteId.svn.event_handler = client.event_handler ret_code = 0 for arg in args: try: client.checkout(arg) except (FileExistError, RosePopenError, SuiteIdPrefixError) as exc: ret_code = 1 report(exc) if not opts.force_mode: sys.exit(1) if ret_code: sys.exit(ret_code)
def delete(): """CLI function: delete.""" opt_parser = RoseOptionParser(usage='rosie delete [OPTIONS] [--] [ID ...]', description=''' Delete suites. Check the standard working copy location for a checked out suite matching `ID` and remove it if there is no uncommitted change (or if `--force` is specified). Delete the suite directory structure from the HEAD of the central repository matching the `ID`. If no `ID` is specified and `$PWD` is a working copy of a suite, use the `ID` of the suite in the working copy. ''').add_my_options("force_mode", "non_interactive", "local_only") opt_parser.modify_option( 'force_mode', help=("Remove working copies even if there are uncommitted changes." "\nContinue with the next `ID` if delete of a suite fails."), ) opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) client = RosieVCClient(event_handler=report, force_mode=opts.force_mode) SuiteId.svn.event_handler = client.event_handler if not args: args.append(SuiteId(location=os.getcwd())) interactive_mode = not opts.non_interactive prompt = PROMPT_DELETE if opts.local_only: prompt = PROMPT_DELETE_LOCAL ret_code = 0 for arg in args: if interactive_mode: try: response = input(prompt % arg) except EOFError: ret_code = 1 continue if response == YES_TO_ALL: interactive_mode = False elif response != YES: ret_code = 1 continue if opts.debug_mode: client.delete(arg, opts.local_only) else: try: client.delete(arg, opts.local_only) except ( LocalCopyStatusError, RosePopenError, SuiteIdPrefixError, ) as exc: client.event_handler(exc) ret_code = 1 if not opts.force_mode: sys.exit(1) if ret_code: sys.exit(ret_code)
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 "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 list_local_suites(): """CLI command to list all the locally checked out suites""" opt_parser = RoseOptionParser(description=''' List the local suites. Search for locally checked out suites and print their details. The default format includes a local working copy status field (`%local`) in the first column. A blank field means there is no related suite checked out. * `=` means that the suite is checked out at this branch and revision. * `<` means that the suite is checked out but at an older revision. * `>` means that the suite is checked out but at a newer revision. * `S` means that the suite is checked out but on a different branch. * `M` means that the suite is checked out and modified. * `X` means that the suite is checked out but is corrupted. ''', ).add_my_options("no_headers", "prefixes", "print_format", "reverse", "sort", "user") opt_parser.modify_option( 'verbosity', help=('Display full info for each returned suite.'), ) opts = opt_parser.parse_args()[0] report = Reporter(opts.verbosity - opts.quietness) if opts.user: alternative_roses_dir = SuiteId.get_local_copy_root(opts.user) report(UserSpecificRoses(alternative_roses_dir), prefix=None) ws_client = RosieWSClient(prefixes=opts.prefixes, event_handler=report) if ws_client.unreachable_prefixes: bad_prefix_string = " ".join(ws_client.unreachable_prefixes) report( RosieWSClientError( ERR_PREFIX_UNREACHABLE.format(bad_prefix_string))) _display_maps(opts, ws_client, ws_client.query_local_copies(opts.user))
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 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()