def find_recent_history(self, history: FileHistory) -> str: if not self.is_recent_history: return "" recent_history = history.load_history_strings() try: recent_value = next(recent_history) except StopIteration: recent_value = "" return str(recent_value)
class ClickCmd(Cmd, object): """A custom Cmd implemenation that delegates commands to click and handles prompt_toolkit/readline functions""" # Cmd string overrides identchars = Cmd.identchars + '-' nohelp = "No help on %s" nocommand = "\n\t{}Command not found: {}%s{}".format( colors.COMMAND_NOT_FOUND_TEXT_STYLE, colors.COMMAND_NOT_FOUND_TEXT_FORE, Style.RESET_ALL) def __init__(self, ctx: click.Context = None, on_finished=None, hist_file=None, before_start=None, readline=None, complete_while_typing=True, fuzzy_completion=True, mouse_support=False, lexer=True, *args, **kwargs): self._stdout = kwargs.get('stdout') super(ClickCmd, self).__init__(*args, **kwargs) # readline overrides self.old_completer = None self.old_delims = None self.readline = readline # Prompt Toolkit Settings self.complete_while_typing = complete_while_typing self.fuzzy_completion = fuzzy_completion self.mouse_support = mouse_support self.lexer = lexer self._pipe_input = create_pipe_input() if not self.readline else None # A callback function that will be excuted before loading up the shell. # By default this changes the color to 0a on a Windows machine self.before_start = before_start # Save the click.Context and callback for when the shell completes self.ctx = ctx self.on_finished = on_finished # Define the history file hist_file = hist_file or os.path.join(os.path.expanduser('~'), globs.HISTORY_FILENAME) self.hist_file = os.path.abspath(hist_file) if not os.path.isdir(os.path.dirname(self.hist_file)): os.makedirs(os.path.dirname(self.hist_file)) self.history = FileHistory(self.hist_file) self.history.load_history_strings() def clear_history(self) -> bool: try: if self.readline: readline.clear_history() else: if not len(self.prompter.history._loaded_strings): return True os.remove(self.hist_file) self.prompter.history._loaded_strings = [] return True except Exception as e: return False # ---------------------------------------------------------------------------------------------- # ANCHOR Cmd Loop Overrides # ---------------------------------------------------------------------------------------------- def preloop(self): if self.readline: # Read history file when cmdloop() begins try: readline.read_history_file(self.hist_file) except IOError: pass def postloop(self): if self.readline: # Write history before cmdloop() returns try: readline.set_history_length(1000) readline.write_history_file(self.hist_file) except IOError: pass # Invoke callback before shell closes if self.on_finished: self.on_finished(self.ctx) def cmdloop(self, intro=None): self.preloop() # Readline Handling if self.readline: if self.completekey and readline: self.old_completer = readline.get_completer() self.old_delims = readline.get_completer_delims() readline.set_completer(self.complete) readline.set_completer_delims(' \n\t') to_parse = self.completekey + ': complete' if readline.__doc__ and 'libedit' in readline.__doc__: # Mac OSX to_parse = 'bind ^I rl_complete' readline.parse_and_bind(to_parse) try: # Call an optional callback function before writing the intro and initializing/starting the shell if self.before_start: if callable(self.before_start): self.before_start() # Write an intro for the shell application if intro is not None: self.intro = intro if self.intro: click.echo(self.intro, file=self._stdout) stop = None if not self.readline: # Initialize Completion Tree for Master Shell if globs.__MASTER_SHELL__ == self.ctx.command.name: BuildCompletionTree(self.ctx) # Initialize Prompter try: from ._lexer import ShellLexer except: pass from prompt_toolkit.output.color_depth import ColorDepth message = [ ('class:name', self.get_prompt()), ('class:prompt', PROMPT_SYMBOL), ] self.prompter = PromptSession( message, style=colors.prompt_style, color_depth=ColorDepth.TRUE_COLOR, history=self.history, enable_history_search=not self.complete_while_typing, mouse_support=self.mouse_support, completer=get_completer(self.fuzzy_completion), complete_in_thread=self.complete_while_typing, complete_while_typing=self.complete_while_typing, lexer=PygmentsLexer(ShellLexer) if self.lexer else None) self.piped_prompter = PromptSession( message, style=colors.prompt_style, color_depth=ColorDepth.TRUE_COLOR, input=self._pipe_input, key_bindings=None, is_password=True, lexer=PygmentsLexer(ShellLexer) if self.lexer else None) # Start Shell Application Loop while not stop: if self.cmdqueue: line = self.cmdqueue.pop(0) else: try: if self.readline: line = get_input(self.get_prompt() + PROMPT_SYMBOL) else: if not globs.__IS_REPEAT_EOF__: line = self.prompter.prompt() elif self._pipe_input: if not globs.__IS_EXITING__: line = self.piped_prompter.prompt() else: return except EOFError: if not globs.__IS_REPEAT_EOF__: # Exits the Shell Application when stdin stream ends click.echo(file=self._stdout) break else: # Swap STDIN from Programmatic Input back to User Input globs.__IS_REPEAT_EOF__ = False if self.readline: sys.stdin = globs.__PREV_STDIN__ # Prevent empty lines from being created from null input print('\n' + IGNORE_LINE) continue except KeyboardInterrupt: # Do not exit the shell on a keyboard interrupt try: if line != '': click.echo(file=self._stdout) continue except: pass # Prevent empty lines from being created from null input if not self.readline: click.echo(IGNORE_LINE) else: print('\n' + IGNORE_LINE) continue # Safely handle calling command and pretty-displaying output / errors if line.strip(): if globs.__IS_REPEAT__: if not globs.__IS_EXITING__: # If stream source is from the 'repeat' command, display the "visible" repeated command click.echo(globs.__LAST_COMMAND_VISIBLE__) def fixTupleSpacing(val): if '[' in val or ']' in val: val = re.sub(r"(\[[\s])", '[', val) val = re.sub(r"([\s]\])", ']', val) val = re.sub(r"(\[,)", ']', val) val = re.sub(r"(,\])", ']', val) if ',' in val: val = re.sub(r"(\",\")", "\", \"", val) val = re.sub(r"([,]{1,999}.(?<=,))", ',', val) return val line = fixTupleSpacing(line) globs.__CURRENT_LINE__ = line try: line = self.precmd(line) stop = self.onecmd(line) stop = self.postcmd(stop, line) if not stop and not globs.__IS_EXITING__: line = '' click.echo(file=self._stdout) except KeyboardInterrupt: click.echo(file=self._stdout) continue finally: # Will tell the next loop to switch stdin back to user input after completing a "repeated" command if line[0:6] != 'repeat' and globs.__IS_REPEAT__: globs.__IS_REPEAT__ = False globs.__IS_REPEAT_EOF__ = True if (not self.readline) and self._pipe_input: if globs.__LAST_COMMAND__ and not globs.__IS_EXITING__: self._pipe_input.send_text( globs.__LAST_COMMAND__ + '\r') elif self._pipe_input and globs.__IS_REPEAT_EOF__: globs.__IS_REPEAT_EOF__ = False else: # Prevent empty lines from being created from null input if not self.readline: click.echo(IGNORE_LINE) else: print(IGNORE_LINE) continue finally: self.postloop() if self.completekey: try: if self.readline: readline.set_completer(self.old_completer) readline.set_completer_delims(self.old_delims) except IOError: pass # ---------------------------------------------------------------------------------------------- # ANCHOR Default Handling & Click Forwards # ---------------------------------------------------------------------------------------------- def get_prompt(self): if callable(self.prompt): kwargs = {} if hasattr(inspect, 'signature'): sig = inspect.signature(self.prompt) if 'ctx' in sig.parameters: kwargs['ctx'] = self.ctx return self.prompt(**kwargs) else: return self.prompt def emptyline(self): return False def default(self, line): self.VerifyCommand(line) def get_names(self): return dir(self) def VerifyCommand(self, line): commands = [] names = self.get_names() for key in names: if not '--' in key: if 'do_' in key[0:3]: if not 'hidden_{}'.format(key[3:]) in names: commands.append(key[3:]) elif 'orig_{}'.format(key[3:]) in names: commands.append(key[3:]) suggest = utils.suggest(commands, line) if len(commands) else None click.echo(self.nocommand % line if not suggest else (self.nocommand % line) + '.\n\n\t{}{}Did you mean "{}{}{}"?{}'.format( colors.SUGGEST_TEXT_STYLE, colors.SUGGEST_TEXT_COLOR, colors.SUGGEST_ITEMS_STYLE, suggest, colors.SUGGEST_TEXT_COLOR, Style.RESET_ALL), file=self._stdout) # ---------------------------------------------------------------------------------------------- # ANCHOR Explicit Command definitions # ---------------------------------------------------------------------------------------------- # Can be overrided by defined commands of the same name def do_exit(self, arg): return True def do_help(self, arg): if not arg: super(ClickCmd, self).do_help(arg) return try: func = getattr(self, 'help_' + arg) except AttributeError: try: do_fun = getattr(self, 'do_' + arg, None) if do_fun is None: self.VerifyCommand(arg) return doc = do_fun.__doc__ if doc: click.echo(doc, file=self._stdout) return except AttributeError: pass click.echo(self.nohelp % arg, file=self._stdout) return func() # ---------------------------------------------------------------------------------------------- # ANCHOR Default "Help" Overrides # ---------------------------------------------------------------------------------------------- def __strip_hidden(self, cmds) -> List[str]: ret: List[str] = [] for cmd in cmds: try: hidden: bool = getattr(self, 'hidden_' + cmd) if not hidden: ret.append(cmd) except AttributeError: ret.append(cmd) return ret def print_topics(self, header, cmds, cmdlen, maxcol): if header is not None: if cmds: click.echo(header, file=self._stdout) if Cmd.doc_header in header or Cmd.undoc_header in header: cmds = self.__strip_hidden(cmds) if self.ruler: click.echo(str(self.ruler * len(header)), file=self._stdout) self.columnize(cmds, maxcol - 1) click.echo(file=self._stdout)
def main(): """ The main function """ history = FileHistory(os.path.join(Path.home(), ".pip_login_history")) history.load_history_strings() try: version = pkg_resources.get_distribution(__name__).version except pkg_resources.DistributionNotFound: version = __name__ + " Unknown version" parser = ArgumentParser(description="pip login") parser.add_argument("--version", action="version", version=version) parser.add_argument("url", nargs="?", type=str, default=None, help="The repository index URL.") parser.add_argument("-u", "--username", type=str, default=None, help="The username.") parser.add_argument("-p", "--password", type=str, default=None, help="The password.") args = parser.parse_args() url = os.environ.get("PIP_LOGIN_REPOSITORY") username = os.environ.get("PIP_LOGIN_USERNAME") password = os.environ.get("PIP_LOGIN_PASSWORD") if args.url: url = args.url if args.username: username = args.username if args.password: password = args.password if not url: url = prompt("Repository URL: ", history=history, auto_suggest=AutoSuggestFromHistory()) if not username: username = prompt("Username: "******"@")[-1] keyring.set_password(netloc, username, password) pip_conf_path = os.environ.get("VIRTUAL_ENV") if platform.system() == "Linux": if pip_conf_path: pip_conf_path = os.path.join(pip_conf_path, "pip.conf") else: pip_conf_path = os.path.join(Path.home(), ".config", "pip", "pip.conf") elif platform.system() == "Darwin": if pip_conf_path: pip_conf_path = os.path.join(pip_conf_path, "pip.conf") else: pip_conf_path = os.path.join(Path.home(), "Library", "Application Support", "pip", "pip.conf") elif platform.system() == "Windows": if pip_conf_path: pip_conf_path = os.path.join(pip_conf_path, "pip.ini") else: appdata = os.environ.get("APPDATA") if appdata: os.path.join(appdata, "pip", "pip.ini") if not parsed_url.username: parsed_url = parsed_url._replace(netloc=f"{username}@{netloc}") extra_index_url = parsed_url.geturl() config = ConfigParser() if pip_conf_path: config.read(pip_conf_path) if "global" not in config: config["global"] = {} if "extra-index-url" not in config["global"]: config["global"]["extra-index-url"] = extra_index_url else: idx_url = config["global"]["extra-index-url"] if extra_index_url not in idx_url: config["global"][ "extra-index-url"] = f"{idx_url}\n{extra_index_url}" if not os.path.exists(os.path.dirname(pip_conf_path)): os.makedirs(os.path.dirname(pip_conf_path)) with open(pip_conf_path, "w+") as config_file: config.write(config_file) print(f"pip config written to: {pip_conf_path}")
def run(args): # print(sys.version + "/n") if len(args) > 0 and args[0] in ["version", "update"]: check_for_update(verbose=True) return # Exit early # Ensure the config directory exists os.makedirs(CONFIG_HOME_DIR, exist_ok=True) commits_file_path = os.path.join(CONFIG_HOME_DIR, "commit_msg_history") commit_msg_history = FileHistory(commits_file_path) if WINDOW_WIDTH < 80: Ansi.print_error( f"It is recommended you increase your window width ({WINDOW_WIDTH}) to at least 80." ) commit_msg = "" if len(args) > 0 and args[0] == "retry": args = args[1:] # consume the "retry" first arg cm_histories_iter = commit_msg_history.load_history_strings() last_commit_msg = next(cm_histories_iter, "") if last_commit_msg == "": Ansi.print_error("Could not find a previous commit message") commit_msg = last_commit_msg if commit_msg == "": print("Starting a conventional git commit...") print( Ansi.colour(Ansi.fg.bright_red, "Tip: Press the up arrow key to recall history!")) commit_msg = add_type(commit_msg) commit_msg = add_scope(commit_msg) check_if_breaking_change() commit_msg = add_description(commit_msg) commit_msg = add_body(commit_msg) commit_msg = add_footer(commit_msg) print() Ansi.print_ok("This is your commit message:") print() print(commit_msg) print() # print("\nNOTE: This was a dry run and no commit was made.\n") # It is expected that all remaining args at this point are for the git # commit command args_string = " ".join(args) text = Ansi.colour(Ansi.fg.bright_yellow, "Extra args for git commit: ") extra_args_file_path = os.path.join(CONFIG_HOME_DIR, "extra_args_history") extra_args_str = prompt( ANSI(text), default=args_string, history=FileHistory(extra_args_file_path), key_bindings=bindings, ) if extra_args_str != "": argv_passthrough = extra_args_str.split(" ") else: argv_passthrough = [] # Ask for confirmation to commit confirmation_validator = YesNoValidator(answer_required=True) text = Ansi.b_yellow("Do you want to make your commit? [y/n] ") confirm = prompt(ANSI(text), validator=confirmation_validator, key_bindings=bindings).lower() if confirm in confirmation_validator.confirmations: commit_msg_history.store_string(commit_msg) cmds = ["git", "commit", "-m", commit_msg] + argv_passthrough returncode = subprocess.run(cmds).returncode print() if returncode == 0: Ansi.print_ok( "\nCommit has been made to conventional commits standards!") else: Ansi.print_error( "\nThere was an error whilst attempting the commit!") elif confirm in confirmation_validator.rejections: print("Aborting the commit...") check_for_update()