def whoami_command(linked_identities): """ Executor for `globus whoami` """ client = get_auth_client() # get userinfo from auth. # if we get back an error the user likely needs to log in again try: res = client.oauth2_userinfo() except AuthAPIError: safeprint( "Unable to get user information. Please try " "logging in again.", write_to_stderr=True, ) click.get_current_context().exit(1) print_command_hint( "For information on which identities are in session see\n" " globus session show\n" ) # --linked-identities either displays all usernames or a table if verbose if linked_identities: try: formatted_print( res["identity_set"], fields=[ ("Username", "username"), ("Name", "name"), ("ID", "sub"), ("Email", "email"), ], simple_text=( None if is_verbose() else "\n".join([x["username"] for x in res["identity_set"]]) ), ) except KeyError: safeprint( "Your current login does not have the consents required " "to view your full identity set. Please log in again " "to agree to the required consents.", write_to_stderr=True, ) # Default output is the top level data else: formatted_print( res, text_format=FORMAT_TEXT_RECORD, fields=[ ("Username", "preferred_username"), ("Name", "name"), ("ID", "sub"), ("Email", "email"), ], simple_text=(None if is_verbose() else res["preferred_username"]), )
def whoami_command(linked_identities): """ Executor for `globus whoami` """ client = get_auth_client() # get userinfo from auth. # if we get back an error the user likely needs to log in again try: res = client.oauth2_userinfo() except AuthAPIError: click.echo( "Unable to get user information. Please try logging in again.", err=True) click.get_current_context().exit(1) print_command_hint( "For information on which identities are in session see\n" " globus session show\n") # --linked-identities either displays all usernames or a table if verbose if linked_identities: try: formatted_print( res["identity_set"], fields=[ ("Username", "username"), ("Name", "name"), ("ID", "sub"), ("Email", "email"), ], simple_text=(None if is_verbose() else "\n".join( [x["username"] for x in res["identity_set"]])), ) except KeyError: click.echo( "Your current login does not have the consents required " "to view your full identity set. Please log in again " "to agree to the required consents.", err=True, ) # Default output is the top level data else: formatted_print( res, text_format=FORMAT_TEXT_RECORD, fields=[ ("Username", "preferred_username"), ("Name", "name"), ("ID", "sub"), ("Email", "email"), ], simple_text=(None if is_verbose() else res["preferred_username"]), )
def bookmark_show(bookmark_id_or_name): """ Given a single bookmark ID or bookmark name, show the bookmark details. By default, when the format is TEXT, this will display the endpoint ID and path in 'ENDPOINT_ID:PATH' notation. The default output is suitable for use in a subshell in another command. If *-v, --verbose* is given, several fields will be displayed. """ client = get_client() res = resolve_id_or_name(client, bookmark_id_or_name) formatted_print( res, text_format=FORMAT_TEXT_RECORD, fields=( ("ID", "id"), ("Name", "name"), ("Endpoint ID", "endpoint_id"), ("Path", "path"), ), simple_text=( # standard output is endpoint:path format "{}:{}".format(res["endpoint_id"], res["path"]) # verbose output includes all fields if not is_verbose() else None), )
def print_version(): """ Print out the current version, and at least try to fetch the latest from PyPi to print alongside it. It may seem odd that this isn't in globus_cli.version , but it's done this way to separate concerns over printing the version from looking it up. """ latest, current = get_versions() if latest is None: click.echo( ("Installed Version: {0}\n" "Failed to lookup latest version.").format( current ) ) else: click.echo( ("Installed Version: {0}\n" "Latest Version: {1}\n" "\n{2}").format( current, latest, "You are running the latest version of the Globus CLI" if current == latest else ( "You should update your version of the Globus CLI with\n" " globus update" ) if current < latest else "You are running a preview version of the Globus CLI", ) ) # verbose shows more platform and python info # it also includes versions of some CLI dependencies if is_verbose(): moddata = _get_package_data() click.echo("\nVerbose Data\n---") click.echo("platform:") click.echo(" platform: {}".format(platform.platform())) click.echo(" py_implementation: {}".format(platform.python_implementation())) click.echo(" py_version: {}".format(platform.python_version())) click.echo(" sys.executable: {}".format(sys.executable)) click.echo(" site.USER_BASE: {}".format(site.USER_BASE)) click.echo("modules:") for mod, modversion, modfile, modpath in moddata: click.echo(" {}:".format(mod)) click.echo(" __version__: {}".format(modversion)) click.echo(" __file__: {}".format(modfile)) click.echo(" __path__: {}".format(modpath))
def print_version(): """ Print out the current version, and at least try to fetch the latest from PyPi to print alongside it. It may seem odd that this isn't in globus_cli.version , but it's done this way to separate concerns over printing the version from looking it up. """ latest, current = get_versions() if latest is None: safeprint( ("Installed Version: {0}\n" "Failed to lookup latest version.").format( current ) ) else: safeprint( ("Installed Version: {0}\n" "Latest Version: {1}\n" "\n{2}").format( current, latest, "You are running the latest version of the Globus CLI" if current == latest else ( "You should update your version of the Globus CLI with\n" " globus update" ) if current < latest else "You are running a preview version of the Globus CLI", ) ) # verbose shows more platform and python info # it also includes versions of some CLI dependencies if is_verbose(): moddata = _get_package_data() safeprint("\nVerbose Data\n---") safeprint("platform:") safeprint(" platform: {}".format(platform.platform())) safeprint(" py_implementation: {}".format(platform.python_implementation())) safeprint(" py_version: {}".format(platform.python_version())) safeprint(" sys.executable: {}".format(sys.executable)) safeprint(" site.USER_BASE: {}".format(site.USER_BASE)) safeprint("modules:") for mod, modversion, modfile, modpath in moddata: safeprint(" {}:".format(mod)) safeprint(" __version__: {}".format(modversion)) safeprint(" __file__: {}".format(modfile)) safeprint(" __path__: {}".format(modpath))
def bookmark_show(bookmark_id_or_name): """ Executor for `globus bookmark show` """ client = get_client() res = resolve_id_or_name(client, bookmark_id_or_name) formatted_print( res, text_format=FORMAT_TEXT_RECORD, fields=( ("ID", "id"), ("Name", "name"), ("Endpoint ID", "endpoint_id"), ("Path", "path"), ), simple_text=( # standard output is endpoint:path format "{}:{}".format(res["endpoint_id"], res["path"]) # verbose output includes all fields if not is_verbose() else None), )
def print_version(): """ Print out the current version, and at least try to fetch the latest from PyPi to print alongside it. It may seem odd that this isn't in globus_cli.version , but it's done this way to separate concerns over printing the version from looking it up. """ upgrade_target, latest, current = get_versions() if latest is None: click.echo(("Installed Version: {0}\nFailed to lookup latest version." ).format(current)) else: click.echo( _get_versionblock_message(current, latest, upgrade_target) + "\n\n" + _get_post_message(current, latest, upgrade_target)) # verbose shows more platform and python info # it also includes versions of some CLI dependencies if is_verbose(): moddata = _get_package_data() click.echo("\nVerbose Data\n---") click.echo("platform:") click.echo(" platform: {}".format(platform.platform())) click.echo(" py_implementation: {}".format( platform.python_implementation())) click.echo(" py_version: {}".format(platform.python_version())) click.echo(" sys.executable: {}".format(sys.executable)) click.echo(" site.USER_BASE: {}".format(site.USER_BASE)) click.echo("modules:") for mod, modversion, modfile, modpath in moddata: click.echo(" {}:".format(mod)) click.echo(" __version__: {}".format(modversion)) click.echo(" __file__: {}".format(modfile)) click.echo(" __path__: {}".format(modpath))
def bookmark_show(bookmark_id_or_name): """ Executor for `globus bookmark show` """ client = get_client() res = resolve_id_or_name(client, bookmark_id_or_name) formatted_print( res, text_format=FORMAT_TEXT_RECORD, fields=( ("ID", "id"), ("Name", "name"), ("Endpoint ID", "endpoint_id"), ("Path", "path"), ), simple_text=( # standard output is endpoint:path format "{}:{}".format(res["endpoint_id"], res["path"]) # verbose output includes all fields if not is_verbose() else None ), )
def ls_command( endpoint_plus_path, recursive_depth_limit, recursive, long_output, show_hidden, filter_val, ): """ List the contents of a directory on an endpoint. If no path is given, the default directory on that endpoint will be used. If using text output files and directories are printed with one entry per line in alphabetical order. Directories are always displayed with a trailing '/'. \b === Filtering --filter takes "filter patterns" subject to the following rules. \b Filter patterns must start with "=", "~", "!", or "!~" If none of these are given, "=" will be used \b "=" does exact matching "~" does regex matching, supporting globs (*) "!" does inverse "=" matching "!~" does inverse "~" matching \b "~*.txt" matches all .txt files, for example {AUTOMATIC_ACTIVATION} """ endpoint_id, path = endpoint_plus_path # do autoactivation before the `ls` call so that recursive invocations # won't do this repeatedly, and won't have to instantiate new clients client = get_client() autoactivate(client, endpoint_id, if_expires_in=60) # create the query paramaters to send to operation_ls ls_params = {"show_hidden": int(show_hidden)} if path: ls_params["path"] = path if filter_val: # this char has special meaning in the LS API's filter clause # can't be part of the pattern (but we don't support globbing across # dir structures anyway) if "/" in filter_val: raise click.UsageError('--filter cannot contain "/"') # format into a simple filter clause which operates on filenames ls_params["filter"] = "name:{}".format(filter_val) # get the `ls` result if recursive: # NOTE: # --recursive and --filter have an interplay that some users may find # surprising # if we're asked to change or "improve" the behavior in the future, we # could do so with "type:dir" or "type:file" filters added in, and # potentially work out some viable behavior based on what people want res = client.recursive_operation_ls(endpoint_id, depth=recursive_depth_limit, **ls_params) else: res = client.operation_ls(endpoint_id, **ls_params) def cleaned_item_name(item): return item["name"] + ("/" if item["type"] == "dir" else "") # and then print it, per formatting rules formatted_print( res, fields=[ ("Permissions", "permissions"), ("User", "user"), ("Group", "group"), ("Size", "size"), ("Last Modified", "last_modified"), ("File Type", "type"), ("Filename", cleaned_item_name), ], simple_text=(None if long_output or is_verbose() or not outformat_is_text() else "\n".join( cleaned_item_name(x) for x in res)), json_converter=iterable_response_to_dict, )
def get_identities_command(values): """ Executor for `globus get-identities` """ client = get_auth_client() resolved_values = [_try_b32_decode(v) or v for v in values] # since API doesn't accept mixed ids and usernames, # split input values into separate lists ids = [] usernames = [] for val in resolved_values: try: uuid.UUID(val) ids.append(val) except ValueError: usernames.append(val) # make two calls to get_identities with ids and usernames # then combine the calls into one response results = [] if len(ids): results += client.get_identities(ids=ids)["identities"] if len(usernames): results += client.get_identities(usernames=usernames)["identities"] res = GlobusResponse({"identities": results}) def _custom_text_format(identities): """ Non-verbose text output is customized """ def resolve_identity(value): """ helper to deal with variable inputs and uncertain response order """ for identity in identities: if identity["id"] == value: return identity["username"] if identity["username"] == value: return identity["id"] return "NO_SUCH_IDENTITY" # standard output is one resolved identity per line in the same order # as the inputs. A resolved identity is either a username if given a # UUID vice versa, or "NO_SUCH_IDENTITY" if the identity could not be # found for val in resolved_values: safeprint(resolve_identity(val)) formatted_print( res, response_key="identities", fields=[ ("ID", "id"), ("Username", "username"), ("Full Name", "name"), ("Organization", "organization"), ("Email Address", "email"), ], # verbose output is a table. Order not guaranteed, may contain # duplicates text_format=(FORMAT_TEXT_TABLE if is_verbose() else _custom_text_format), )
def ls_command( endpoint_plus_path, recursive_depth_limit, recursive, long_output, show_hidden, filter_val, ): """ Executor for `globus ls` """ endpoint_id, path = endpoint_plus_path # do autoactivation before the `ls` call so that recursive invocations # won't do this repeatedly, and won't have to instantiate new clients client = get_client() autoactivate(client, endpoint_id, if_expires_in=60) # create the query paramaters to send to operation_ls ls_params = {"show_hidden": int(show_hidden)} if path: ls_params["path"] = path if filter_val: # this char has special meaning in the LS API's filter clause # can't be part of the pattern (but we don't support globbing across # dir structures anyway) if "/" in filter_val: raise click.UsageError('--filter cannot contain "/"') # format into a simple filter clause which operates on filenames ls_params["filter"] = "name:{}".format(filter_val) # get the `ls` result if recursive: # NOTE: # --recursive and --filter have an interplay that some users may find # surprising # if we're asked to change or "improve" the behavior in the future, we # could do so with "type:dir" or "type:file" filters added in, and # potentially work out some viable behavior based on what people want res = client.recursive_operation_ls( endpoint_id, depth=recursive_depth_limit, **ls_params ) else: res = client.operation_ls(endpoint_id, **ls_params) def cleaned_item_name(item): return item["name"] + ("/" if item["type"] == "dir" else "") # and then print it, per formatting rules formatted_print( res, fields=[ ("Permissions", "permissions"), ("User", "user"), ("Group", "group"), ("Size", "size"), ("Last Modified", "last_modified"), ("File Type", "type"), ("Filename", cleaned_item_name), ], simple_text=( None if long_output or is_verbose() or not outformat_is_text() else "\n".join(cleaned_item_name(x) for x in res) ), json_converter=iterable_response_to_dict, )
def get_identities_command(values): """ Executor for `globus get-identities` """ client = get_auth_client() resolved_values = [_try_b32_decode(v) or v for v in values] # since API doesn't accept mixed ids and usernames, # split input values into separate lists ids = [] usernames = [] for val in resolved_values: try: uuid.UUID(val) ids.append(val) except ValueError: usernames.append(val) # make two calls to get_identities with ids and usernames # then combine the calls into one response results = [] if len(ids): results += client.get_identities(ids=ids)["identities"] if len(usernames): results += client.get_identities(usernames=usernames)["identities"] res = GlobusResponse({"identities": results}) def _custom_text_format(identities): """ Non-verbose text output is customized """ def resolve_identity(value): """ helper to deal with variable inputs and uncertain response order """ for identity in identities: if identity["id"] == value: return identity["username"] if identity["username"] == value: return identity["id"] return "NO_SUCH_IDENTITY" # standard output is one resolved identity per line in the same order # as the inputs. A resolved identity is either a username if given a # UUID vice versa, or "NO_SUCH_IDENTITY" if the identity could not be # found for val in resolved_values: click.echo(resolve_identity(val)) formatted_print( res, response_key="identities", fields=[ ("ID", "id"), ("Username", "username"), ("Full Name", "name"), ("Organization", "organization"), ("Email Address", "email"), ], # verbose output is a table. Order not guaranteed, may contain # duplicates text_format=(FORMAT_TEXT_TABLE if is_verbose() else _custom_text_format), )
def get_identities_command(values, provision): """ Lookup Globus Auth Identities given one or more uuids and/or usernames. Default output resolves each UUID to a username and each username to a UUID, with one output per line in the same order as the inputs. If a particular input had no corresponding identity in Globus Auth, "NO_SUCH_IDENTITY" is printed instead. If more fields are desired, --verbose will give tabular output, but does not guarantee order and ignores inputs with no corresponding Globus Auth identity. """ client = get_auth_client() resolved_values = [_try_b32_decode(v) or v for v in values] # since API doesn't accept mixed ids and usernames, # split input values into separate lists ids = [] usernames = [] for val in resolved_values: try: uuid.UUID(val) ids.append(val) except ValueError: usernames.append(val) # make two calls to get_identities with ids and usernames # then combine the calls into one response results = [] if len(ids): results += client.get_identities(ids=ids, provision=provision)["identities"] if len(usernames): results += client.get_identities(usernames=usernames, provision=provision)["identities"] res = GlobusResponse({"identities": results}) def _custom_text_format(identities): """ Non-verbose text output is customized """ def resolve_identity(value): """ helper to deal with variable inputs and uncertain response order """ for identity in identities: if identity["id"] == value: return identity["username"] if identity["username"] == value: return identity["id"] return "NO_SUCH_IDENTITY" # standard output is one resolved identity per line in the same order # as the inputs. A resolved identity is either a username if given a # UUID vice versa, or "NO_SUCH_IDENTITY" if the identity could not be # found for val in resolved_values: click.echo(resolve_identity(val)) formatted_print( res, response_key="identities", fields=[ ("ID", "id"), ("Username", "username"), ("Full Name", "name"), ("Organization", "organization"), ("Email Address", "email"), ], # verbose output is a table. Order not guaranteed, may contain # duplicates text_format=(FORMAT_TEXT_TABLE if is_verbose() else _custom_text_format), )