Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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}")
Exemplo n.º 4
0
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()