Ejemplo n.º 1
0
 def __init__(self, completekey='tab', stdin=None, stdout=None):
     BaseCmd.__init__(self, completekey, stdin, stdout)
     self.history = FileHistory(os.path.expanduser(HISTORY_PATH))
Ejemplo n.º 2
0
def implant_command_loop(implant_id, user):
    while (True):
        try:
            style = Style.from_dict({
                '': '#80d130',
            })
            session = PromptSession(history=FileHistory('%s/.implant-history' %
                                                        PoshProjectDirectory),
                                    auto_suggest=AutoSuggestFromHistory(),
                                    style=style)
            implant_id_orig = implant_id
            if ("-" in implant_id) or ("all" in implant_id) or (","
                                                                in implant_id):
                print(Colours.GREEN)
                prompt_commands = POSH_COMMANDS
                command = session.prompt("%s> " % implant_id,
                                         completer=FirstWordFuzzyWordCompleter(
                                             prompt_commands, WORD=True))
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return
            else:
                implant = get_implantbyid(implant_id)
                if not implant:
                    print_bad("Unrecognised implant id or command: %s" %
                              implant_id)
                    input("Press Enter to continue...")
                    clear()
                    return
                prompt_commands = POSH_COMMANDS
                if implant.Pivot.startswith('Python'):
                    prompt_commands = PY_COMMANDS
                if implant.Pivot.startswith('C#'):
                    prompt_commands = SHARP_COMMANDS
                if 'PB' in implant.Pivot:
                    style = Style.from_dict({
                        '': '#008ECC',
                    })
                    session = PromptSession(
                        history=FileHistory('%s/.implant-history' %
                                            PoshProjectDirectory),
                        auto_suggest=AutoSuggestFromHistory(),
                        style=style)
                    prompt_commands = SHARP_COMMANDS
                    print(Colours.BLUE)
                else:
                    print(Colours.GREEN)
                print("%s\\%s @ %s (PID:%s)" % (implant.Domain, implant.User,
                                                implant.Hostname, implant.PID))
                command = session.prompt(
                    "%s %s> " %
                    (get_implant_type_prompt_prefix(implant_id), implant_id),
                    completer=FirstWordFuzzyWordCompleter(prompt_commands,
                                                          WORD=True))
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return

            # if "all" run through all implants get_implants()
            if implant_id == "all":
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implants_split = get_implants()
                if implants_split:
                    for implant_details in implants_split:
                        # if "\n" in command run each command individually or ask the question if that's what they want to do
                        if "\n" in allcommands:
                            if ri.lower() == "y" or ri == "":
                                commands = allcommands.split('\n')
                                for command in commands:
                                    run_implant_command(
                                        command, implant_details.RandomURI,
                                        implant_id_orig, user)
                            else:
                                run_implant_command(command,
                                                    implant_details.RandomURI,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command,
                                                implant_details.RandomURI,
                                                implant_id_orig, user)

            # if "separated list" against single uri
            elif "," in implant_id:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_split = implant_id.split(",")
                for split_implant_id in implant_split:
                    implant_randomuri = get_randomuri(split_implant_id)
                    # if "\n" in command run each command individually or ask the question if that's what they want to do
                    if "\n" in allcommands:
                        if ri.lower() == "y" or ri == "":
                            commands = allcommands.split('\n')
                            for command in commands:
                                run_implant_command(command, implant_randomuri,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    else:
                        run_implant_command(command, implant_randomuri,
                                            implant_id_orig, user)

            # if "range" against single uri
            elif "-" in implant_id:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_split = implant_id.split("-")
                for range_implant_id in range(int(implant_split[0]),
                                              int(implant_split[1]) + 1):
                    try:
                        implant_randomuri = get_randomuri(range_implant_id)
                        # if "\n" in command run each command individually or ask the question if that's what they want to do
                        if "\n" in allcommands:
                            if ri.lower() == "y" or ri == "":
                                commands = allcommands.split('\n')
                                for command in commands:
                                    run_implant_command(
                                        command, implant_randomuri,
                                        implant_id_orig, user)
                            else:
                                run_implant_command(command, implant_randomuri,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    except Exception:
                        print_bad("Unknown ImplantID")

            # else run against single uri
            else:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_randomuri = get_randomuri(implant_id)
                # if "\n" in command run each command individually or ask the question if that's what they want to do
                if "\n" in allcommands:
                    if ri.lower() == "y" or ri == "":
                        commands = allcommands.split('\n')
                        for command in commands:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    else:
                        run_implant_command(command, implant_randomuri,
                                            implant_id_orig, user)
                else:
                    run_implant_command(command, implant_randomuri,
                                        implant_id_orig, user)

        except KeyboardInterrupt:
            continue
        except EOFError:
            new_c2_message("%s logged off." % user)
            sys.exit(0)
        except Exception as e:
            traceback.print_exc()
            print_bad(
                f"Error running against the selected implant ID, ensure you have typed the correct information: {e}"
            )
            return
Ejemplo n.º 3
0
def implant_handler_command_loop(user, printhelp="", autohide=None):
    while (True):
        session = PromptSession(history=FileHistory('%s/.top-history' %
                                                    PoshProjectDirectory),
                                auto_suggest=AutoSuggestFromHistory())

        try:
            if user is not None:
                print("User: "******"%s%s" % (user, Colours.GREEN))
                print()

            C2 = get_c2server_all()
            killdate = datetime.strptime(C2.KillDate, '%Y-%m-%d').date()
            datedifference = number_of_days(date.today(), killdate)
            if datedifference < 8:
                print(Colours.RED +
                      ("\nKill Date is - %s - expires in %s days" %
                       (C2.KillDate, datedifference)))
                print(Colours.END)
                print()

            implants = get_implants()
            if implants:
                for implant in implants:
                    ID = implant.ImplantID
                    LastSeen = implant.LastSeen
                    Hostname = implant.Hostname
                    Domain = implant.Domain
                    URLID = implant.URLID
                    DomainUser = implant.User
                    Arch = implant.Arch
                    PID = implant.PID
                    Pivot = implant.Pivot
                    Sleep = implant.Sleep.strip()
                    Label = implant.Label

                    apmsuspendshut = False

                    pwrStatus = get_powerstatusbyrandomuri(implant.RandomURI)
                    if pwrStatus is not None:
                        if Label is not None:
                            Label += " "
                        else:
                            Label = ""
                        apmstatus = pwrStatus[2].lower()

                        if (apmstatus == "shutdown"):
                            Label += "SHTDWN "
                            apmsuspendshut = True
                        elif (apmstatus == "suspend"
                              or apmstatus == "querysuspend"):
                            Label += "SUSPND "
                            apmsuspendshut = True

                        if not apmsuspendshut:
                            if (pwrStatus[7]):
                                Label += "LOCKED "
                            if (not pwrStatus[8]):
                                Label += "SCRN OFF "

                            if (not pwrStatus[3]):
                                if (pwrStatus[6] is not None
                                        and pwrStatus[6].isdigit()):
                                    Label += ("DSCHRG: %s%% " % pwrStatus[6])
                                else:
                                    Label += ("DSCHRG ")

                    Pivot = get_implant_type_prompt_prefix(ID)
                    LastSeenTime = datetime.strptime(LastSeen,
                                                     "%Y-%m-%d %H:%M:%S")
                    LastSeenTimeString = datetime.strftime(
                        LastSeenTime, "%Y-%m-%d %H:%M:%S")
                    now = datetime.now()
                    if (Sleep.endswith('s')):
                        sleep_int = int(Sleep[:-1])
                    elif (Sleep.endswith('m')):
                        sleep_int = int(Sleep[:-1]) * 60
                    elif (Sleep.endswith('h')):
                        sleep_int = int(Sleep[:-1]) * 60 * 60
                    else:
                        print(Colours.RED)
                        print("Incorrect sleep format: %s" % Sleep)
                        print(Colours.GREEN)
                        continue
                    nowMinus3Beacons = now - timedelta(seconds=(sleep_int * 3))
                    nowMinus10Beacons = now - timedelta(seconds=(sleep_int *
                                                                 10))
                    nowMinus30Beacons = now - timedelta(seconds=(sleep_int *
                                                                 30))
                    sID = "[" + str(ID) + "]"
                    if not Label:
                        sLabel = ""
                    else:
                        Label = Label.strip()
                        sLabel = Colours.BLUE + "[" + Label + "]" + Colours.GREEN

                    if "C#;PB" in Pivot:
                        print(
                            Colours.BLUE +
                            "%s: Seen:%s | PID:%s | %s | PBind | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, Domain, DomainUser, Hostname, Arch,
                               Pivot, sLabel))
                    elif nowMinus30Beacons > LastSeenTime and autohide:
                        pass
                    elif nowMinus10Beacons > LastSeenTime:
                        print(
                            Colours.RED +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
                    elif nowMinus3Beacons > LastSeenTime:
                        print(
                            Colours.YELLOW +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
                    else:
                        print(
                            Colours.GREEN +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
            else:
                now = datetime.now()
                print(Colours.RED + "No Implants as of: %s" %
                      now.strftime("%Y-%m-%d %H:%M:%S"))

            if printhelp:
                print(printhelp)

            command = session.prompt(
                "\nSelect ImplantID or ALL or Comma Separated List (Enter to refresh):: ",
                completer=FirstWordFuzzyWordCompleter(SERVER_COMMANDS,
                                                      WORD=True))
            print("")

            command = command.strip()
            if (command == "") or (command == "back") or (command == "clear"):
                do_back(user, command)
                continue
            if command.startswith("generate-reports"):
                do_generate_reports(user, command)
                continue
            if command.startswith("generate-csvs"):
                do_generate_csvs(user, command)
                continue
            if command.startswith("message "):
                do_message(user, command)
                continue
            if command.startswith("show-hosted-files"):
                do_show_hosted_files(user, command)
                continue
            if command.startswith("add-hosted-file"):
                do_add_hosted_file(user, command)
                continue
            if command.startswith("disable-hosted-file"):
                do_disable_hosted_file(user, command)
                continue
            if command.startswith("enable-hosted-file"):
                do_enable_hosted_file(user, command)
                continue
            if command.startswith("show-urls") or command.startswith(
                    "list-urls"):
                do_show_urls(user, command)
                continue
            if command.startswith("add-autorun"):
                do_add_autorun(user, command)
                continue
            if command.startswith("list-autorun"):
                do_list_autoruns(user, command)
                continue
            if command.startswith("del-autorun"):
                do_del_autorun(user, command)
                continue
            if command.startswith("nuke-autorun"):
                do_nuke_autoruns(user, command)
                continue
            if command.startswith("kill"):
                do_del_task(user, command)
                continue
            if command.startswith("show-serverinfo"):
                do_show_serverinfo(user, command)
                continue
            if command.startswith("turnoff-notifications"):
                do_turnoff_notifications(user, command)
                continue
            if command.startswith("turnon-notifications"):
                do_turnon_notifications(user, command)
                continue
            if command.startswith("set-pushover-applicationtoken"):
                do_set_pushover_applicationtoken(user, command)
                continue
            if command.startswith("set-pushover-userkeys"):
                do_set_pushover_userkeys(user, command)
                continue
            if command.startswith("get-killdate"):
                do_get_killdate(user, command)
                continue
            if command.startswith("set-killdate"):
                do_set_killdate(user, command)
                continue
            if command.startswith("set-defaultbeacon"):
                do_set_defaultbeacon(user, command)
                continue
            if command == "get-opsec-events":
                do_get_opsec_events(user, command)
                continue
            if command == "add-opsec-event":
                do_insert_opsec_events(user, command)
                continue
            if command == "del-opsec-event":
                do_del_opsec_events(user, command)
                continue
            if command.startswith("opsec"):
                do_opsec(user, command)
                continue
            if command.startswith("listmodules"):
                do_listmodules(user, command)
                continue
            if command.startswith('creds ') or command.strip() == "creds":
                do_creds(user, command)
                input("Press Enter to continue...")
                clear()
                continue
            if (command == "pwnself") or (command == "p"):
                do_pwnself(user, command)
                continue
            if command == "tasks":
                do_tasks(user, command)
                continue
            if command == "cleartasks":
                do_cleartasks(user, command)
                continue
            if command.startswith("quit"):
                do_quit(user, command)
                continue
            if command.startswith("createdaisypayload"):
                do_createdaisypayload(user, command)
                continue
            if command.startswith("createproxypayload"):
                do_createnewpayload(user, command)
                continue
            if command.startswith("createnewpayload"):
                do_createnewpayload(user, command)
                continue
            if command.startswith("createnewshellcode"):
                do_createnewpayload(user, command, shellcodeOnly=True)
                continue
            if command == "help":
                do_help(user, command)
                continue
            if command == "history":
                do_history(user, command)
                continue
            if command.startswith("use "):
                do_use(user, command)
            implant_command_loop(command, user)
        except KeyboardInterrupt:
            clear()
            continue
        except EOFError:
            new_c2_message("%s logged off." % user)
            sys.exit(0)
        except Exception as e:
            if 'unable to open database file' not in str(e):
                print_bad("Error: %s" % e)
                traceback.print_exc()
Ejemplo n.º 4
0
 def reset_history(self):
     history_file_path = os.path.join(self.config.get_config_dir(), self.config.get_history())
     os.remove(history_file_path)
     self.history = FileHistory(history_file_path)
     self.cli.buffers[DEFAULT_BUFFER].history = self.history
Ejemplo n.º 5
0
def cli(spec, env, url, http_options):
    click.echo('Version: %s' % __version__)

    copied, config_path = config.initialize()
    if copied:
        click.echo('Config file not found. Initialized a new one: %s' %
                   config_path)

    cfg = config.load()

    # Override pager/less options
    os.environ['PAGER'] = cfg['pager']
    os.environ['LESS'] = '-RXF'

    if spec:
        f = urlopen(spec)
        try:
            content = f.read().decode('utf-8')
            try:
                spec = json.loads(content)
            except json.JSONDecodeError:
                try:
                    spec = yaml.load(content)
                except yaml.YAMLError:
                    click.secho(
                        "Warning: Specification file '%s' is neither valid JSON nor YAML"
                        % spec,
                        err=True,
                        fg='red')
                    spec = None
        finally:
            f.close()

    if url:
        url = fix_incomplete_url(url)
    context = Context(url, spec=spec)

    output_style = cfg.get('output_style')
    if output_style:
        context.options['--style'] = output_style

    # For prompt-toolkit
    history = FileHistory(os.path.join(get_data_dir(), 'history'))
    lexer = PygmentsLexer(HttpPromptLexer)
    completer = HttpPromptCompleter(context)
    try:
        style_class = get_style_by_name(cfg['command_style'])
    except ClassNotFound:
        style_class = Solarized256Style
    style = style_from_pygments(style_class)

    listener = ExecutionListener(cfg)

    if len(sys.argv) == 1:
        # load previous context if nothing defined
        load_context(context)
    else:
        if env:
            load_context(context, env)
            if url:
                # Overwrite the env url if not default
                context.url = url

        if http_options:
            # Execute HTTPie options from CLI (can overwrite env file values)
            http_options = [smart_quote(a) for a in http_options]
            execute(' '.join(http_options), context, listener=listener)

    while True:
        try:
            text = prompt('%s> ' % context.url,
                          completer=completer,
                          lexer=lexer,
                          style=style,
                          history=history,
                          auto_suggest=AutoSuggestFromHistory(),
                          on_abort=AbortAction.RETRY,
                          vi_mode=cfg['vi'])
        except EOFError:
            break  # Control-D pressed
        else:
            execute(text, context, listener=listener, style=style_class)
            if context.should_exit:
                break

    click.echo("Goodbye!")
Ejemplo n.º 6
0
        text = document.text
        if text.startswith('\\'):
            return

        job_config = bigquery.QueryJobConfig(dry_run=True,
                                             use_query_cache=False)

        try:
            self.client.query(document.text, job_config=job_config)
        except Exception as e:
            error = e.errors[0]
            raise ValidationError(message=error['message'], cursor_position=0)


session = PromptSession(lexer=PygmentsLexer(SqlLexer),
                        history=FileHistory(config.history_path),
                        key_bindings=kb,
                        completer=sql_completer,
                        style=style,
                        validate_while_typing=False,
                        validator=SqlValidator(client))


@click.group()
def cli():
    pass


while True:
    try:
        text = session.prompt('> ', multiline=True)
Ejemplo n.º 7
0
def prompt_search_tags(prompt_text):
    r"""
    Do an interactive prompt search in the Bibmanager database by
    the given keywords, with auto-complete and auto-suggest only
    offering non-None values of the given field.
    Only one keyword must be set in the prompt.
    A bottom toolbar dynamically shows additional info.

    Parameters
    ----------
    prompt_text: String
        Text to display when launching the prompt.

    Returns
    -------
    kw_input: List of strings
        List of the parsed input (same order as keywords).
        Items are None for the keywords not defined.
    """
    bibs = load()
    bibkeys = [bib.key for bib in bibs]
    bibcodes = [bib.bibcode for bib in bibs if bib.bibcode is not None]
    tags = sorted(
        set(
            itertools.chain(
                *[bib.tags for bib in bibs if bib.tags is not None])))
    entries = bibkeys + bibcodes

    key_words = {
        '': entries,
        'tags:': tags,
    }
    completer = u.LastKeyCompleter(key_words)
    suggester = u.LastKeySuggestCompleter()
    validator = u.AlwaysPassValidator(
        bibs, toolbar_text="(Press 'tab' for autocomplete)")

    session = prompt_toolkit.PromptSession(
        history=FileHistory(u.BM_HISTORY_TAGS()))

    inputs = session.prompt(
        prompt_text,
        auto_suggest=suggester,
        completer=completer,
        complete_while_typing=False,
        validator=validator,
        validate_while_typing=True,
        bottom_toolbar=validator.bottom_toolbar,
    )

    text = inputs.replace(' tags:', ' tags: ')
    if text.startswith('tags:'):
        text = 'tags: ' + text[5:]

    input_strings = text.split()
    if 'tags:' not in input_strings:
        tag_index = len(input_strings)
    else:
        tag_index = input_strings.index('tags:')

    entries = input_strings[0:tag_index]
    tags = input_strings[tag_index + 1:]

    # Translate bibcodes to keys and keep only valid keys:
    keys = [
        find(bibcode=entry).key if entry in bibcodes else entry
        for entry in entries
    ]
    keys = [key for key in keys if key in bibkeys]

    return keys, tags
import io
import json

from prompt_toolkit.history import FileHistory

import splitwise
from bidi.algorithm import get_display
from prompt_toolkit import print_formatted_text, HTML, PromptSession

import config
import utils
from splitwise import Expense

_ = utils.load_translation()
session = PromptSession(history=FileHistory('storePromptHistory.hist'))

categories = [
    'Electronic maintenance', 'Plumbing', 'Deck', 'Sails', 'Engine',
    'General maintenance', 'Electricity', 'Berth', 'Dry dock', 'House',
    'Registration', 'Insurance', 'Electronics', 'Safety', 'Fuel (domestic)',
    'Other'
]


def create_details_json(remarks, category, store, upgrade):
    ret = {
        'remarks': remarks,
        'category': category,
        'store': store,
        'is_boat_upgrade': upgrade
    }
Ejemplo n.º 9
0
# !/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'bit4'
__github__ = 'https://github.com/bit4woo'

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.contrib.completers import WordCompleter
import click

SQLCompleter = WordCompleter(
    ['select', 'from', 'insert', 'update', 'delete', 'drop'], ignore_case=True)

while 1:
    user_input = prompt(
        u'SQL>',
        history=FileHistory('history.txt'),
        auto_suggest=AutoSuggestFromHistory(),
        completer=SQLCompleter,
    )
    click.echo_via_pager(user_input)
Ejemplo n.º 10
0
    def run_cli(self):
        iterations = 0
        sqlexecute = self.sqlexecute
        logger = self.logger
        self.configure_pager()
        self.refresh_completions()

        history_file = config_location() + "history"
        if dir_path_exists(history_file):
            history = FileHistory(history_file)
        else:
            history = None
            self.echo(
                'Error: Unable to open the history file "{}". '
                "Your query history will not be saved.".format(history_file),
                err=True,
                fg="red",
            )

        key_bindings = cli_bindings(self)

        if not self.less_chatty:
            print("Version:", __version__)
            print(
                "Mail: https://groups.google.com/forum/#!forum/litecli-users")
            print("Github: https://github.com/dbcli/litecli")
            # print("Home: https://litecli.com")

        def get_message():
            prompt = self.get_prompt(self.prompt_format)
            if (self.prompt_format == self.default_prompt
                    and len(prompt) > self.max_len_prompt):
                prompt = self.get_prompt("\\d> ")
            return [("class:prompt", prompt)]

        def get_continuation(width, line_number, is_soft_wrap):
            continuation = " " * (width - 1) + " "
            return [("class:continuation", continuation)]

        def show_suggestion_tip():
            return iterations < 2

        def one_iteration(text=None):
            if text is None:
                try:
                    text = self.prompt_app.prompt()
                except KeyboardInterrupt:
                    return

                special.set_expanded_output(False)

                try:
                    text = self.handle_editor_command(text)
                except RuntimeError as e:
                    logger.error("sql: %r, error: %r", text, e)
                    logger.error("traceback: %r", traceback.format_exc())
                    self.echo(str(e), err=True, fg="red")
                    return

            if not text.strip():
                return

            if self.destructive_warning:
                destroy = confirm_destructive_query(text)
                if destroy is None:
                    pass  # Query was not destructive. Nothing to do here.
                elif destroy is True:
                    self.echo("Your call!")
                else:
                    self.echo("Wise choice!")
                    return

            # Keep track of whether or not the query is mutating. In case
            # of a multi-statement query, the overall query is considered
            # mutating if any one of the component statements is mutating
            mutating = False

            try:
                logger.debug("sql: %r", text)

                special.write_tee(self.get_prompt(self.prompt_format) + text)
                if self.logfile:
                    self.logfile.write("\n# %s\n" % datetime.now())
                    self.logfile.write(text)
                    self.logfile.write("\n")

                successful = False
                start = time()
                res = sqlexecute.run(text)
                self.formatter.query = text
                successful = True
                result_count = 0
                for title, cur, headers, status in res:
                    logger.debug("headers: %r", headers)
                    logger.debug("rows: %r", cur)
                    logger.debug("status: %r", status)
                    threshold = 1000
                    if is_select(status) and cur and cur.rowcount > threshold:
                        self.echo(
                            "The result set has more than {} rows.".format(
                                threshold),
                            fg="red",
                        )
                        if not confirm("Do you want to continue?"):
                            self.echo("Aborted!", err=True, fg="red")
                            break

                    if self.auto_vertical_output:
                        max_width = self.prompt_app.output.get_size().columns
                    else:
                        max_width = None

                    formatted = self.format_output(
                        title, cur, headers, special.is_expanded_output(),
                        max_width)

                    t = time() - start
                    try:
                        if result_count > 0:
                            self.echo("")
                        try:
                            self.output(formatted, status)
                        except KeyboardInterrupt:
                            pass
                        self.echo("Time: %0.03fs" % t)
                    except KeyboardInterrupt:
                        pass

                    start = time()
                    result_count += 1
                    mutating = mutating or is_mutating(status)
                special.unset_once_if_written()
            except EOFError as e:
                raise e
            except KeyboardInterrupt:
                # get last connection id
                connection_id_to_kill = sqlexecute.connection_id
                logger.debug("connection id to kill: %r",
                             connection_id_to_kill)
                # Restart connection to the database
                sqlexecute.connect()
                try:
                    for title, cur, headers, status in sqlexecute.run(
                            "kill %s" % connection_id_to_kill):
                        status_str = str(status).lower()
                        if status_str.find("ok") > -1:
                            logger.debug(
                                "cancelled query, connection id: %r, sql: %r",
                                connection_id_to_kill,
                                text,
                            )
                            self.echo("cancelled query", err=True, fg="red")
                except Exception as e:
                    self.echo(
                        "Encountered error while cancelling query: {}".format(
                            e),
                        err=True,
                        fg="red",
                    )
            except NotImplementedError:
                self.echo("Not Yet Implemented.", fg="yellow")
            except OperationalError as e:
                logger.debug("Exception: %r", e)
                if e.args[0] in (2003, 2006, 2013):
                    logger.debug("Attempting to reconnect.")
                    self.echo("Reconnecting...", fg="yellow")
                    try:
                        sqlexecute.connect()
                        logger.debug("Reconnected successfully.")
                        one_iteration(text)
                        return  # OK to just return, cuz the recursion call runs to the end.
                    except OperationalError as e:
                        logger.debug("Reconnect failed. e: %r", e)
                        self.echo(str(e), err=True, fg="red")
                        # If reconnection failed, don't proceed further.
                        return
                else:
                    logger.error("sql: %r, error: %r", text, e)
                    logger.error("traceback: %r", traceback.format_exc())
                    self.echo(str(e), err=True, fg="red")
            except Exception as e:
                logger.error("sql: %r, error: %r", text, e)
                logger.error("traceback: %r", traceback.format_exc())
                self.echo(str(e), err=True, fg="red")
            else:
                if is_dropping_database(text, self.sqlexecute.dbname):
                    self.sqlexecute.dbname = None
                    self.sqlexecute.connect()

                # Refresh the table names and column names if necessary.
                if need_completion_refresh(text):
                    self.refresh_completions(reset=need_completion_reset(text))
            finally:
                if self.logfile is False:
                    self.echo("Warning: This query was not logged.",
                              err=True,
                              fg="red")
            query = Query(text, successful, mutating)
            self.query_history.append(query)

        get_toolbar_tokens = create_toolbar_tokens_func(
            self, show_suggestion_tip)

        if self.wider_completion_menu:
            complete_style = CompleteStyle.MULTI_COLUMN
        else:
            complete_style = CompleteStyle.COLUMN

        with self._completer_lock:

            if self.key_bindings == "vi":
                editing_mode = EditingMode.VI
            else:
                editing_mode = EditingMode.EMACS

            self.prompt_app = PromptSession(
                lexer=PygmentsLexer(LiteCliLexer),
                reserve_space_for_menu=self.get_reserved_space(),
                message=get_message,
                prompt_continuation=get_continuation,
                bottom_toolbar=get_toolbar_tokens,
                complete_style=complete_style,
                input_processors=[
                    ConditionalProcessor(
                        processor=HighlightMatchingBracketProcessor(
                            chars="[](){}"),
                        filter=HasFocus(DEFAULT_BUFFER) & ~IsDone(),
                    )
                ],
                tempfile_suffix=".sql",
                completer=DynamicCompleter(lambda: self.completer),
                history=history,
                auto_suggest=AutoSuggestFromHistory(),
                complete_while_typing=True,
                multiline=cli_is_multiline(self),
                style=style_factory(self.syntax_style, self.cli_style),
                include_default_pygments_style=False,
                key_bindings=key_bindings,
                enable_open_in_editor=True,
                enable_system_prompt=True,
                enable_suspend=True,
                editing_mode=editing_mode,
                search_ignore_case=True,
            )

        try:
            while True:
                one_iteration()
                iterations += 1
        except EOFError:
            special.close_tee()
            if not self.less_chatty:
                self.echo("Goodbye!")
Ejemplo n.º 11
0
    def __init__(
            self,
            get_globals=None,
            get_locals=None,
            stdin=None,
            stdout=None,
            vi_mode=False,
            history_filename=None,
            style=PythonStyle,
            autocompletion_style=AutoCompletionStyle.POPUP_MENU,
            always_multiline=False,

            # For internal use.
            _completer=None,
            _validator=None):

        self.get_globals = get_globals or (lambda: {})
        self.get_locals = get_locals or self.get_globals
        self.always_multiline = always_multiline
        self.autocompletion_style = autocompletion_style

        self.completer = _completer or PythonCompleter(self.get_globals,
                                                       self.get_locals)
        validator = _validator or PythonValidator()

        layout = Layout(
            input_processors=[BracketsMismatchProcessor()],
            min_height=7,
            lexer=PythonLexer,
            left_margin=PythonLeftMargin(),
            menus=[CompletionsMenu()]
            if autocompletion_style == AutoCompletionStyle.POPUP_MENU else [],
            bottom_toolbars=[
                ArgToolbar(),
                SignatureToolbar(),
                SearchToolbar(),
                SystemToolbar(),
                ValidationToolbar(),
            ] + ([CompletionsToolbar()] if autocompletion_style
                 == AutoCompletionStyle.HORIZONTAL_MENU else []) + [
                     PythonToolbar(vi_mode=vi_mode),
                 ],
            show_tildes=True)

        if history_filename:
            history = FileHistory(history_filename)
        else:
            history = History()

        if vi_mode:
            key_binding_factories = [vi_bindings, python_bindings]
        else:
            key_binding_factories = [emacs_bindings, python_bindings]

        line = PythonLine(always_multiline=always_multiline,
                          tempfile_suffix='.py',
                          history=history,
                          completer=self.completer,
                          validator=validator)

        #: Incremeting integer counting the current statement.
        self.current_statement_index = 1

        self.get_signatures_thread_running = False

        super(PythonCommandLineInterface,
              self).__init__(layout=layout,
                             style=style,
                             key_binding_factories=key_binding_factories,
                             line=line,
                             create_async_autocompleters=True)

        def on_input_timeout():
            """
            When there is no input activity,
            in another thread, get the signature of the current code.
            """
            # Never run multiple get-signature threads.
            if self.get_signatures_thread_running:
                return
            self.get_signatures_thread_running = True

            document = self.line.document

            def run():
                script = get_jedi_script_from_document(document,
                                                       self.get_locals(),
                                                       self.get_globals())

                # Show signatures in help text.
                if script:
                    try:
                        signatures = script.call_signatures()
                    except ValueError:
                        # e.g. in case of an invalid \\x escape.
                        signatures = []
                    except Exception:
                        # Sometimes we still get an exception (TypeError), because
                        # of probably bugs in jedi. We can silence them.
                        # See: https://github.com/davidhalter/jedi/issues/492
                        signatures = []
                else:
                    signatures = []

                self.get_signatures_thread_running = False

                # Set signatures and redraw if the text didn't change in the
                # meantime. Otherwise request new signatures.
                if self.line.text == document.text:
                    self.line.signatures = signatures
                    self.request_redraw()
                else:
                    on_input_timeout()

            self.run_in_executor(run)

        self.onInputTimeout += on_input_timeout
Ejemplo n.º 12
0
    def run_cli(self):
        iterations = 0
        sqlexecute = self.sqlexecute
        logger = self.logger
        self.configure_pager()

        if self.smart_completion:
            self.refresh_completions()

        author_file = os.path.join(PACKAGE_ROOT, 'AUTHORS')
        sponsor_file = os.path.join(PACKAGE_ROOT, 'SPONSORS')

        key_binding_manager = mycli_bindings()

        if not self.less_chatty:
            print('Version:', __version__)
            print('Chat: https://gitter.im/dbcli/mycli')
            print('Mail: https://groups.google.com/forum/#!forum/mycli-users')
            print('Home: http://mycli.net')
            print('Thanks to the contributor -',
                  thanks_picker([author_file, sponsor_file]))

        def prompt_tokens(cli):
            prompt = self.get_prompt(self.prompt_format)
            if self.prompt_format == self.default_prompt and len(
                    prompt) > self.max_len_prompt:
                prompt = self.get_prompt('\\d> ')
            return [(Token.Prompt, prompt)]

        def get_continuation_tokens(cli, width):
            continuation_prompt = self.get_prompt(
                self.prompt_continuation_format)
            return [(Token.Continuation, ' ' *
                     (width - len(continuation_prompt)) + continuation_prompt)]

        def show_suggestion_tip():
            return iterations < 2

        def one_iteration(document=None):
            if document is None:
                document = self.cli.run()

                special.set_expanded_output(False)

                try:
                    document = self.handle_editor_command(self.cli, document)
                except RuntimeError as e:
                    logger.error("sql: %r, error: %r", document.text, e)
                    logger.error("traceback: %r", traceback.format_exc())
                    self.echo(str(e), err=True, fg='red')
                    return

            if not document.text.strip():
                return

            if self.destructive_warning:
                destroy = confirm_destructive_query(document.text)
                if destroy is None:
                    pass  # Query was not destructive. Nothing to do here.
                elif destroy is True:
                    self.echo('Your call!')
                else:
                    self.echo('Wise choice!')
                    return

            # Keep track of whether or not the query is mutating. In case
            # of a multi-statement query, the overall query is considered
            # mutating if any one of the component statements is mutating
            mutating = False

            try:
                logger.debug('sql: %r', document.text)

                special.write_tee(
                    self.get_prompt(self.prompt_format) + document.text)
                if self.logfile:
                    self.logfile.write('\n# %s\n' % datetime.now())
                    self.logfile.write(document.text)
                    self.logfile.write('\n')

                successful = False
                start = time()
                res = sqlexecute.run(document.text)
                successful = True
                result_count = 0
                for title, cur, headers, status in res:
                    logger.debug("headers: %r", headers)
                    logger.debug("rows: %r", cur)
                    logger.debug("status: %r", status)
                    threshold = 1000
                    if (is_select(status) and cur
                            and cur.rowcount > threshold):
                        self.echo(
                            'The result set has more than {} rows.'.format(
                                threshold),
                            fg='red')
                        if not click.confirm('Do you want to continue?'):
                            self.echo("Aborted!", err=True, fg='red')
                            break

                    if self.auto_vertical_output:
                        max_width = self.cli.output.get_size().columns
                    else:
                        max_width = None

                    formatted = self.format_output(
                        title, cur, headers, special.is_expanded_output(),
                        max_width)

                    t = time() - start
                    try:
                        if result_count > 0:
                            self.echo('')
                        try:
                            self.output('\n'.join(formatted), status)
                        except KeyboardInterrupt:
                            pass
                        if special.is_timing_enabled():
                            self.echo('Time: %0.03fs' % t)
                    except KeyboardInterrupt:
                        pass

                    start = time()
                    result_count += 1
                    mutating = mutating or is_mutating(status)
                special.unset_once_if_written()
            except EOFError as e:
                raise e
            except KeyboardInterrupt:
                # get last connection id
                connection_id_to_kill = sqlexecute.connection_id
                logger.debug("connection id to kill: %r",
                             connection_id_to_kill)
                # Restart connection to the database
                sqlexecute.connect()
                try:
                    for title, cur, headers, status in sqlexecute.run(
                            'kill %s' % connection_id_to_kill):
                        status_str = str(status).lower()
                        if status_str.find('ok') > -1:
                            logger.debug(
                                "cancelled query, connection id: %r, sql: %r",
                                connection_id_to_kill, document.text)
                            self.echo("cancelled query", err=True, fg='red')
                except Exception as e:
                    self.echo(
                        'Encountered error while cancelling query: {}'.format(
                            e),
                        err=True,
                        fg='red')
            except NotImplementedError:
                self.echo('Not Yet Implemented.', fg="yellow")
            except OperationalError as e:
                logger.debug("Exception: %r", e)
                if (e.args[0] in (2003, 2006, 2013)):
                    logger.debug('Attempting to reconnect.')
                    self.echo('Reconnecting...', fg='yellow')
                    try:
                        sqlexecute.connect()
                        logger.debug('Reconnected successfully.')
                        one_iteration(document)
                        return  # OK to just return, cuz the recursion call runs to the end.
                    except OperationalError as e:
                        logger.debug('Reconnect failed. e: %r', e)
                        self.echo(str(e), err=True, fg='red')
                        # If reconnection failed, don't proceed further.
                        return
                else:
                    logger.error("sql: %r, error: %r", document.text, e)
                    logger.error("traceback: %r", traceback.format_exc())
                    self.echo(str(e), err=True, fg='red')
            except Exception as e:
                logger.error("sql: %r, error: %r", document.text, e)
                logger.error("traceback: %r", traceback.format_exc())
                self.echo(str(e), err=True, fg='red')
            else:
                if is_dropping_database(document.text, self.sqlexecute.dbname):
                    self.sqlexecute.dbname = None
                    self.sqlexecute.connect()

                # Refresh the table names and column names if necessary.
                if need_completion_refresh(document.text):
                    self.refresh_completions(
                        reset=need_completion_reset(document.text))
            finally:
                if self.logfile is False:
                    self.echo("Warning: This query was not logged.",
                              err=True,
                              fg='red')
            query = Query(document.text, successful, mutating)
            self.query_history.append(query)

        get_toolbar_tokens = create_toolbar_tokens_func(
            self.completion_refresher.is_refreshing, show_suggestion_tip)

        layout = create_prompt_layout(
            lexer=MyCliLexer,
            multiline=True,
            get_prompt_tokens=prompt_tokens,
            get_continuation_tokens=get_continuation_tokens,
            get_bottom_toolbar_tokens=get_toolbar_tokens,
            display_completions_in_columns=self.wider_completion_menu,
            extra_input_processors=[
                ConditionalProcessor(
                    processor=HighlightMatchingBracketProcessor(
                        chars='[](){}'),
                    filter=HasFocus(DEFAULT_BUFFER) & ~IsDone())
            ],
            reserve_space_for_menu=self.get_reserved_space())
        with self._completer_lock:
            buf = CLIBuffer(always_multiline=self.multi_line,
                            completer=self.completer,
                            history=FileHistory(
                                os.path.expanduser(
                                    os.environ.get('MYCLI_HISTFILE',
                                                   '~/.mycli-history'))),
                            auto_suggest=AutoSuggestFromHistory(),
                            complete_while_typing=Always(),
                            accept_action=AcceptAction.RETURN_DOCUMENT)

            if self.key_bindings == 'vi':
                editing_mode = EditingMode.VI
            else:
                editing_mode = EditingMode.EMACS

            application = Application(
                style=style_from_pygments(style_cls=self.output_style),
                layout=layout,
                buffer=buf,
                key_bindings_registry=key_binding_manager.registry,
                on_exit=AbortAction.RAISE_EXCEPTION,
                on_abort=AbortAction.RETRY,
                editing_mode=editing_mode,
                ignore_case=True)
            self.cli = CommandLineInterface(application=application,
                                            eventloop=create_eventloop())

        try:
            while True:
                one_iteration()
                iterations += 1
        except EOFError:
            special.close_tee()
            if not self.less_chatty:
                self.echo('Goodbye!')
Ejemplo n.º 13
0
    def __init__(
        self,
        get_globals: Optional[_GetNamespace] = None,
        get_locals: Optional[_GetNamespace] = None,
        history_filename: Optional[str] = None,
        vi_mode: bool = False,
        color_depth: Optional[ColorDepth] = None,
        # Input/output.
        input: Optional[Input] = None,
        output: Optional[Output] = None,
        # For internal use.
        extra_key_bindings: Optional[KeyBindings] = None,
        _completer: Optional[Completer] = None,
        _validator: Optional[Validator] = None,
        _lexer: Optional[Lexer] = None,
        _extra_buffer_processors=None,
        _extra_layout_body=None,
        _extra_toolbars=None,
        _input_buffer_height=None,
    ) -> None:

        self.get_globals: _GetNamespace = get_globals or (lambda: {})
        self.get_locals: _GetNamespace = get_locals or self.get_globals

        self._completer = _completer or FuzzyCompleter(
            PythonCompleter(
                self.get_globals,
                self.get_locals,
                lambda: self.enable_dictionary_completion,
            ),
            enable_fuzzy=Condition(lambda: self.enable_fuzzy_completion),
        )
        self._validator = _validator or PythonValidator(
            self.get_compiler_flags)
        self._lexer = _lexer or PygmentsLexer(PythonLexer)

        self.history: History
        if history_filename:
            self.history = ThreadedHistory(FileHistory(history_filename))
        else:
            self.history = InMemoryHistory()

        self._input_buffer_height = _input_buffer_height
        self._extra_layout_body = _extra_layout_body or []
        self._extra_toolbars = _extra_toolbars or []
        self._extra_buffer_processors = _extra_buffer_processors or []

        self.extra_key_bindings = extra_key_bindings or KeyBindings()

        # Settings.
        self.title: AnyFormattedText = ""
        self.show_signature: bool = False
        self.show_docstring: bool = False
        self.show_meta_enter_message: bool = True
        self.completion_visualisation: CompletionVisualisation = CompletionVisualisation.MULTI_COLUMN
        self.completion_menu_scroll_offset: int = 1

        self.show_line_numbers: bool = False
        self.show_status_bar: bool = True
        self.wrap_lines: bool = True
        self.complete_while_typing: bool = True
        self.paste_mode: bool = False  # When True, don't insert whitespace after newline.
        self.confirm_exit: bool = True  # Ask for confirmation when Control-D is pressed.
        self.accept_input_on_enter: int = 2  # Accept when pressing Enter 'n' times.
        # 'None' means that meta-enter is always required.
        self.enable_open_in_editor: bool = True
        self.enable_system_bindings: bool = True
        self.enable_input_validation: bool = True
        self.enable_auto_suggest: bool = False
        self.enable_mouse_support: bool = False
        self.enable_history_search: bool = False  # When True, like readline, going
        # back in history will filter the
        # history on the records starting
        # with the current input.

        self.enable_syntax_highlighting: bool = True
        self.enable_fuzzy_completion: bool = False
        self.enable_dictionary_completion: bool = False
        self.swap_light_and_dark: bool = False
        self.highlight_matching_parenthesis: bool = False
        self.show_sidebar: bool = False  # Currently show the sidebar.

        # When the sidebar is visible, also show the help text.
        self.show_sidebar_help: bool = True

        # Currently show 'Do you really want to exit?'
        self.show_exit_confirmation: bool = False

        # The title to be displayed in the terminal. (None or string.)
        self.terminal_title: Optional[str] = None

        self.exit_message: str = "Do you really want to exit?"
        self.insert_blank_line_after_output: bool = True  # (For the REPL.)

        # The buffers.
        self.default_buffer = self._create_buffer()
        self.search_buffer: Buffer = Buffer()
        self.docstring_buffer: Buffer = Buffer(read_only=True)

        # Tokens to be shown at the prompt.
        self.prompt_style: str = "classic"  # The currently active style.

        # Styles selectable from the menu.
        self.all_prompt_styles: Dict[str, PromptStyle] = {
            "ipython": IPythonPrompt(self),
            "classic": ClassicPrompt(),
        }

        self.get_input_prompt = lambda: self.all_prompt_styles[
            self.prompt_style].in_prompt()

        self.get_output_prompt = lambda: self.all_prompt_styles[
            self.prompt_style].out_prompt()

        #: Load styles.
        self.code_styles: Dict[str, BaseStyle] = get_all_code_styles()
        self.ui_styles = get_all_ui_styles()
        self._current_code_style_name: str = "default"
        self._current_ui_style_name: str = "default"

        if is_windows():
            self._current_code_style_name = "win32"

        self._current_style = self._generate_style()
        self.color_depth: ColorDepth = color_depth or ColorDepth.default()

        self.max_brightness: float = 1.0
        self.min_brightness: float = 0.0

        # Options to be configurable from the sidebar.
        self.options = self._create_options()
        self.selected_option_index: int = 0

        #: Incremeting integer counting the current statement.
        self.current_statement_index: int = 1

        # Code signatures. (This is set asynchronously after a timeout.)
        self.signatures: List[Any] = []

        # Boolean indicating whether we have a signatures thread running.
        # (Never run more than one at the same time.)
        self._get_signatures_thread_running: bool = False

        self.style_transformation = merge_style_transformations([
            ConditionalStyleTransformation(
                SwapLightAndDarkStyleTransformation(),
                filter=Condition(lambda: self.swap_light_and_dark),
            ),
            AdjustBrightnessStyleTransformation(lambda: self.min_brightness,
                                                lambda: self.max_brightness),
        ])
        self.ptpython_layout = PtPythonLayout(
            self,
            lexer=DynamicLexer(lambda: self._lexer if self.
                               enable_syntax_highlighting else SimpleLexer()),
            input_buffer_height=self._input_buffer_height,
            extra_buffer_processors=self._extra_buffer_processors,
            extra_body=self._extra_layout_body,
            extra_toolbars=self._extra_toolbars,
        )

        self.app = self._create_application(input, output)

        if vi_mode:
            self.app.editing_mode = EditingMode.VI
Ejemplo n.º 14
0
async def prompt_loop(cluster):
    output = __DEFAULT_OUTPUT
    connections = await cluster.connect()

    if None not in connections:
        logging.error('Could not setup a connection')
        await stop(cluster)
        return

    completer = SiriCompleter()

    try:
        path = os.path.join(os.path.expanduser('~'), '.siridb-prompt')
        if not os.path.isdir(path):
            os.mkdir(path)

        history_file = os.path.join(
            path, '{}@{}.history'.format(cluster._username, cluster._dbname))
        history = FileHistory(history_file)
    except Exception as e:
        history = InMemoryHistory()

    try:
        result = await cluster.query('show time_precision, version', timeout=5)
        writer.time_precision = result['data'][0]['value']
        version = result['data'][1]['value']
        if tuple(map(int, version.split('.')[:2])) != __version_info__[:2]:
            logging.warning('SiriDB Prompt is version is version {} while at '
                            'least one server your connecting to is running '
                            'version {}. This is not necessary a problem but '
                            'we recommend using the same version.'.format(
                                __version__, version))
    except Exception as e:
        logging.warning('Could not read the version and time precision, '
                        'timestamps will not be formatted and we are not sure '
                        'if the database is running a correct version. '
                        '(reason: {})'.format(e))

    sys.stdout.write('\x1b]2;{}@{}\x07'.format(cluster._username,
                                               cluster._dbname))

    while True:
        force_exit.clear()
        method = cluster.query
        inp = await prompt_async('{}@{}> '.format(cluster._username,
                                                  cluster._dbname),
                                 patch_stdout=True,
                                 key_bindings_registry=manager.registry,
                                 history=history,
                                 completer=completer)
        inp = inp.strip()

        if inp == 'exit':
            break

        if get_history(inp, history):
            continue

        if inp == 'clear':
            clear_history(history)
            print('History is cleared.\n')
            continue

        if inp == 'connections':
            writer.output_connections(cluster)
            continue

        if inp == 'get_output':
            print('{}\n'.format(output))
            continue

        if inp == 'get_loglevel':
            print('{}\n'.format(
                logging._levelToName[logging.getLogger().level]))
            continue

        if set_loglevel(inp):
            continue

        o = set_output(inp)
        if o:
            output = o
            continue

        try:
            data = await import_from_file(inp)
        except Exception as e:
            writer.error('Import error: {}'.format(e))
            continue
        else:
            if data is not None:
                inp = data
                method = cluster.insert

        try:
            result = await method(inp)
        except (QueryError, InsertError) as e:
            writer.error(e)
        except TimeoutError as e:
            logging.critical(
                '{} (You might receive another error \'Package ID '
                'not found\' if the result arrives)'.format(e))
        except asyncio.CancelledError:
            logging.critical('Request is cancelled...')
        except Exception as e:
            if str(e):
                logging.critical(e)
            else:
                logging.exception(e)
        else:
            if isinstance(result, str) or output == 'RAW':
                print('{}\n'.format(result))
            elif output == 'JSON':
                writer.output_json(result)
            elif output == 'PRETTY':
                writer.output_pretty(result)
            else:
                raise TypeError('Unknown output set: {}'.format(output))

    await stop(cluster)
    crop_history(history)
Ejemplo n.º 15
0
class PromptInterface(object):
    """
    class PromptInterface
    handle the wallet cli commands
    """

    commands = [
        'help', 'quit', 'create wallet {path}', 'open wallet {path}', 'close',
        'wallet', 'send {asset} {address} {amount}', 'history', 'lock cli',
        'unlock cli', 'gas configure {amount}', 'gas query'
    ]
    go_on = True
    Wallet = None
    history = FileHistory(FILENAME_PROMPT_HISTORY)
    locked = False

    def __init__(self):

        self.token_style = Style.from_dict({
            "command":
            preferences.token_style['Command'],
            "eth":
            preferences.token_style['Eth'],
            "default":
            preferences.token_style['Default'],
            "number":
            preferences.token_style['Number'],
        })

    def get_bottom_toolbar(self, cli=None):
        """

        :param cli:
        :return:
        """

        return '[%s]' % (settings.NET_NAME if not PromptInterface.locked else
                         settings.NET_NAME + " (Locked) ")

    def quit(self):
        self.go_on = False

    def help(self):
        tokens = []
        for c in self.commands:
            tokens.append(("class:command", "%s\n" % c))
        print_formatted_text(FormattedText(tokens), style=self.token_style)

    def do_create(self, arguments):
        """

        :param arguments:
        :return:
        """
        if self.Wallet:
            self.do_close_wallet()
        item = get_arg(arguments)
        if self.Wallet:
            self.do_close_wallet()

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

            if path:

                if os.path.exists(path):
                    print("File already exists")
                    return

                passwd1 = prompt("[Password 1]> ", is_password=True)
                passwd2 = prompt("[Password 2]> ", is_password=True)

                if passwd1 != passwd2 or len(passwd1) < 1:
                    print(
                        "please provide matching passwords that are at least 1 characters long"
                    )
                    return

                try:
                    self.Wallet = Wallet.Create(path=path, password=passwd1)
                    print("Wallet %s " %
                          json.dumps(self.Wallet.ToJson(), indent=4))
                except Exception as e:
                    print("Exception creating wallet: %s " % e)
                    self.Wallet = None
                    if os.path.isfile(path):
                        try:
                            os.remove(path)
                        except Exception as e:
                            print("Could not remove {}: {}".format(path, e))
                return

            else:
                print("Please specify a path")

    def do_open(self, arguments):
        """

        :param arguments:
        :return:
        """

        if self.Wallet:
            self.do_close_wallet()
        item = get_arg(arguments)
        if item and item == 'wallet':
            path = get_arg(arguments, 1)
            if path:
                if not os.path.exists(path):
                    print("wallet file not found")
                    return
                passwd = prompt("[Password]> ", is_password=True)
                try:
                    self.Wallet = Wallet.Open(path, passwd)
                    print("Opened wallet at %s" % path)
                except Exception as e:
                    print("could not open wallet: %s " % e)
            else:
                print("Please specify a path")
        else:
            print("please specify something to open")

    def do_close_wallet(self):
        """

        :return:
        """
        if self.Wallet:
            path = self.Wallet._path
            self.Wallet = None
            print("closed wallet %s " % path)

    @command_wapper("wallet")
    def show_wallet(self, arguments):
        """

        :param arguments:
        :return:
        """

        if not self.Wallet:
            print("please open a wallet")
            return

        item = get_arg(arguments)

        if not item:
            print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4))

            return

        else:
            print("wallet: '{}' is an invalid parameter".format(item))

    @command_wapper("import")
    def do_import(self, arguments):
        """

        :param arguments:
        :return:
        """

        item = get_arg(arguments)

        if not item:
            print("please specify something to import")
            return
        else:
            print("Import of '%s' not implemented" % item)

    @command_wapper("export")
    def do_export(self, arguments):
        """

        :param arguments:
        :return:
        """
        item = get_arg(arguments)

        if item == 'wif':
            if not self.Wallet:
                return print("please open a wallet")

            address = get_arg(arguments, 1)
            if not address:
                return print("Please specify an address")

            passwd = prompt("[Wallet Password]> ", is_password=True)
            if not self.Wallet.ValidatePassword(passwd):
                return print("Incorrect password")

            keys = self.Wallet.GetKeys()
            for key in keys:
                if key.GetAddress() == address:
                    export = key.Export()
                    print("WIF key export: %s" % export)
            return

        print("Command export %s not found" % item)

    @command_wapper("send")
    def do_send(self, arguments):
        """

        :param arguments:
        :return:
        """

        if not self.Wallet:
            print("please open a wallet")
            return False
        if len(arguments) < 3:
            print("Not enough arguments")
            return False

        assetId = get_arg(arguments).upper()
        address_to = get_arg(arguments, 1)
        amount = float(get_arg(arguments, 2))
        if amount <= 0:
            console_log.error("value can not less then 0")
            return None

        if not assetId in self.Wallet.SupportAssert:
            console_log.error("No support assert")
            return None

        gaslimit = int(get_arg(arguments, 3)) if get_arg(arguments,
                                                         3) else None
        gasprice = int(get_arg(arguments, 4)) if get_arg(arguments,
                                                         4) else None

        if assetId == "ETH":
            if amount >= self.Wallet.eth_balance:
                console_log.error("No balance")
                return None

            try:
                res = self.Wallet.send_eth(address_to, amount, gaslimit)
                print("txid: 0x" + res)
            except Exception as e:
                print("send failed %s" % e)
        elif assetId == "TNC":
            if amount > self.Wallet.tnc_balance or self.Wallet.eth_balance < 0:
                console_log.error("No balance")
                return None
            try:
                res = self.Wallet.send_erc20(assetId, address_to, amount,
                                             gaslimit, gasprice)
                print("txid: 0x" + res)
            except Exception as e:
                print("send failed %s" % e)

        else:
            pass
        return

    @command_wapper("unlock")
    def unlock(self, args):
        """

        :param args:
        :return:
        """

        item = get_arg(args)
        if item == "cli":
            if PromptInterface.locked:
                passwd = prompt("[Wallet Password]> ", is_password=True)
                if not self.Wallet.ValidatePassword(passwd):
                    print("Incorrect password")
                    return None
                PromptInterface.locked = False
                print("cli unlocked")
            else:
                print("cli not in locked mode")
        elif item == "wallet":
            pass
        else:
            print("please spacify unlock item [cli]")
        return None

    @command_wapper("lock")
    def do_lock(self, args):
        """

        :param args:
        :return:
        """
        item = get_arg(args)
        if item == "cli":
            if PromptInterface.locked:
                print("cli now is in locked mode")
            else:
                if self.Wallet:
                    PromptInterface.locked = True
                    print("lock cli with wallet %s" % self.Wallet.name)
                else:
                    print("No opened wallet")
        elif item == "wallet":
            pass
        else:
            print("please spacify lock item [cli]")
        return None

    @command_wapper("history")
    def show_tx(self, args):
        """

        :param args:
        :return:
        """
        history = self.Wallet.query_history()
        if history is EnumStatusCode.DBQueryWithoutMatchedItems:
            print("No tx history")
            return
        for item in history:
            print("*" * 20)
            print(item)
        return

    def parse_result(self, result):
        """

        :param result:
        :return:
        """
        if result.strip():
            commandParts = result.strip().split()
            return commandParts[0], commandParts[1:]
        return None, None

    @command_wapper("gas")
    def configure_gas(self, arguments):
        """

        :param arguments:
        :return:
        """
        subcommand = get_arg(arguments)
        if not subcommand:
            self.help()
            return False

        if subcommand == 'configure':
            coef = get_arg(arguments, 1, True)
            if coef is None or 0 >= coef:
                console_log.warn(
                    'Please use number. Attention: much larger, much more expensive charge.'
                )
                return False
            Client.set_gas_price(coef)
        elif subcommand == 'query':
            console_log.info('Current use {} GWEI'.format(
                Client.get_gas_price()))
        else:
            self.help()

        return

    def handle_commands(self, command, arguments):
        """

        :param command:
        :param arguments:
        :return:
        """
        if command == "unlock":
            self.unlock(arguments)
        elif command == 'quit' or command == 'exit':
            self.quit()
        elif command == 'help':
            self.help()
        elif command == 'wallet':
            self.show_wallet(arguments)
        elif command is None:
            print('please specify a command')
        elif command == 'create':
            self.do_create(arguments)
        elif command == 'close':
            self.do_close_wallet()
        elif command == 'open':
            self.do_open(arguments)
        elif command == 'export':
            self.do_export(arguments)
        elif command == 'wallet':
            self.show_wallet(arguments)
        elif command == 'send':
            self.do_send(arguments)
        elif command == 'history':
            self.show_tx(arguments)
        elif command == "lock":
            self.do_lock(arguments)
        elif command == "gas":
            self.configure_gas(arguments)
        else:
            print("command %s not found" % command)

    def handle_locked_command(self, command, arguments):
        """

        :param command:
        :param arguments:
        :return:
        """
        if command == "unlock":
            self.unlock(arguments)

        else:
            print("cli is in locked mode please unlock cli via 'unlock cli'")
            return None

    def get_completer(self):
        standard_completions = []
        for i in self.commands:
            sub_c = re.match(r"([^{\[]*).*", i)
            if sub_c:
                standard_completions.append(sub_c.groups()[0].strip())
        all_completions = list(set(standard_completions))
        prompt_completer = WordCompleter(all_completions, sentence=True)

        return prompt_completer

    def run(self):
        """

        :return:
        """
        tokens = [("class:eth", 'EthTrinity'),
                  ("class:default", ' cli. Type '),
                  ("class:command", '\'help\' '),
                  ("class:default", 'to get started')]

        print_formatted_text(FormattedText(tokens), style=self.token_style)
        print('\n')

        while self.go_on:
            session = PromptSession("trinity> ",
                                    completer=self.get_completer(),
                                    history=self.history,
                                    bottom_toolbar=self.get_bottom_toolbar,
                                    style=self.token_style,
                                    refresh_interval=3,
                                    auto_suggest=AutoSuggestFromHistory())

            try:
                result = session.prompt()
            except EOFError:
                # Control-D pressed: quit
                return self.quit()
            except KeyboardInterrupt:
                # Control-C pressed: do nothing
                continue
            # try:
            #     command, arguments = self.parse_result(result)
            #
            #     if command is not None and len(command) > 0:
            #         command = command.lower()
            #
            #         if self.locked:
            #             self.handle_locked_command(command, arguments)
            #             continue
            #
            #         else:
            #             self.handle_commands(command, arguments)
            #
            # except Exception as e:
            #
            #     print("could not execute command: %s " % e)
            #     traceback.print_stack()
            #     traceback.print_exc()
            command, arguments = self.parse_result(result)

            if command is not None and len(command) > 0:
                command = command.lower()

                if PromptInterface.locked:
                    self.handle_locked_command(command, arguments)
                    continue

                else:
                    self.handle_commands(command, arguments)
Ejemplo n.º 16
0
Archivo: main.py Proyecto: rjuju/pgcli
    def run_cli(self):
        logger = self.logger

        history_file = self.config['main']['history_file']
        if history_file == 'default':
            history_file = config_location() + 'history'
        history = FileHistory(os.path.expanduser(history_file))
        self.refresh_completions(history=history, persist_priorities='none')

        self.cli = self._build_cli(history)

        if not self.less_chatty:
            print('Version:', __version__)
            print('Chat: https://gitter.im/dbcli/pgcli')
            print('Mail: https://groups.google.com/forum/#!forum/pgcli')
            print('Home: http://pgcli.com')

        try:
            while True:
                document = self.cli.run(True)

                # The reason we check here instead of inside the pgexecute is
                # because we want to raise the Exit exception which will be
                # caught by the try/except block that wraps the pgexecute.run()
                # statement.
                if quit_command(document.text):
                    raise EOFError

                try:
                    document = self.handle_editor_command(self.cli, document)
                except RuntimeError as e:
                    logger.error("sql: %r, error: %r", document.text, e)
                    logger.error("traceback: %r", traceback.format_exc())
                    click.secho(str(e), err=True, fg='red')
                    continue

                # Initialize default metaquery in case execution fails
                query = MetaQuery(query=document.text, successful=False)

                watch_command, timing = special.get_watch_command(
                    document.text)
                if watch_command:
                    while watch_command:
                        try:
                            query = self.execute_command(watch_command, query)
                            click.echo(
                                'Waiting for {0} seconds before repeating'.
                                format(timing))
                            sleep(timing)
                        except KeyboardInterrupt:
                            watch_command = None
                else:
                    query = self.execute_command(document.text, query)

                # Allow PGCompleter to learn user's preferred keywords, etc.
                with self._completer_lock:
                    self.completer.extend_query_history(document.text)

                self.query_history.append(query)

        except EOFError:
            if not self.less_chatty:
                print('Goodbye!')
Ejemplo n.º 17
0
from __future__ import print_function

import sys
import os.path

import prompt_toolkit
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from ergonomica.lib.interface.completer import ErgonomicaCompleter
from ergonomica.lib.interface.key_bindings_manager import manager_for_environment
from prompt_toolkit.styles import style_from_dict
from prompt_toolkit.token import Token

try:
    HISTORY = FileHistory(
        os.path.join(os.path.expanduser("~"), ".ergo", ".ergo_history"))
except IOError as error:
    print(
        "[ergo: ConfigError]: No such file ~/.ergo_history. Please run ergo_setup. "
        + str(error),
        file=sys.stderr)


def get_bottom_toolbar_tokens(cli):
    return [(prompt_toolkit.Token.Toolbar, ' This is a toolbar. ')]


def get_rprompt_tokens(cli):
    return [(prompt_toolkit.Token, ' '),
            (prompt_toolkit.Token.RPrompt, '<rprompt>')]
Ejemplo n.º 18
0
 def reset_history(self):
     history_file_path = os.path.join(self.config.get_config_dir(),
                                      self.config.get_history())
     os.remove(history_file_path)
     self.history = FileHistory(history_file_path)
     self.cli.buffers[DEFAULT_BUFFER].history = self.history
Ejemplo n.º 19
0
def prompt_search(keywords, field, prompt_text):
    r"""
    Do an interactive prompt search in the Bibmanager database by
    the given keywords, with auto-complete and auto-suggest only
    offering non-None values of the given field.
    Only one keyword must be set in the prompt.
    A bottom toolbar dynamically shows additional info.

    Parameters
    ----------
    keywords: List of strings
        BibTex keywords to search by.
    field: String
        Filtering BibTex field for auto-complete and auto-suggest.
    prompt_text: String
        Text to display when launching the prompt.

    Returns
    -------
    kw_input: List of strings
        List of the parsed input (same order as keywords).
        Items are None for the keywords not defined.
    extra: List of strings
        Any further word written in the prompt.

    Examples
    --------
    >>> import bibmanager.bib_manager as bm
    >>> # Search by key or bibcode, of entries with non-None bibcode:
    >>> keywords = ['key', 'bibcode']
    >>> field = 'bibcode'
    >>> prompt_text = ("Sample search  (Press 'tab' for autocomplete):\n")
    >>> prompt_input = bm.prompt_search(keywords, field, prompt_text)
    Sample search  (Press 'tab' for autocomplete):
    key: Astropy2013aaAstroPy
    >>> # Look at the results (list corresponds to [key, bibcode]):
    >>> print(prompt_input[0])
    ['Astropy2013aaAstroPy', None]
    >>> print(f'extra = {prompt_input[1]}')
    extra = [None]

    >>> # Repeat search, now by bibcode:
    >>> prompt_input = u.prompt_search(keywords, field, prompt_text)
    Sample search  (Press 'tab' for autocomplete):
    bibcode: 2013A&A...558A..33A
    >>> print(prompt_input[0])
    [None, '2013A&A...558A..33A']
    """
    bibs = [bib for bib in load() if getattr(bib, field) is not None]
    fetch_keywords = [f'{keyword}:' for keyword in keywords]
    completer = u.KeyPathCompleter(fetch_keywords, bibs)
    suggester = u.AutoSuggestKeyCompleter()
    validator = u.AlwaysPassValidator(
        bibs, toolbar_text="(Press 'tab' for autocomplete)")

    session = prompt_toolkit.PromptSession(
        history=FileHistory(u.BM_HISTORY_PDF()))

    inputs = session.prompt(
        prompt_text,
        auto_suggest=suggester,
        completer=completer,
        complete_while_typing=False,
        validator=validator,
        validate_while_typing=True,
        bottom_toolbar=validator.bottom_toolbar,
    )

    kw_input = [
        re.search(fr'(?:^|[\s]+){kw}[\s]*(.+)', inputs)
        for kw in fetch_keywords
    ]
    # Only one of these keywords should be defined:
    output = [val is not None for val in kw_input]
    if sum(output) != 1:
        raise ValueError("Invalid syntax.")

    index = output.index(True)
    content = kw_input[index].group(1).split()
    if content == []:
        raise ValueError("Invalid syntax.")
    kw_input[index] = content[0]
    extra = content[1:] if len(content) > 1 else [None]
    return kw_input, extra
Ejemplo n.º 20
0
class AzInteractiveShell(object):
    def __init__(self,
                 cli_ctx,
                 style=None,
                 completer=None,
                 lexer=None,
                 history=None,
                 input_custom=sys.stdin,
                 output_custom=None,
                 user_feedback=False,
                 intermediate_sleep=.25,
                 final_sleep=4):

        from .color_styles import style_factory

        self.cli_ctx = cli_ctx
        self.config = Configuration(cli_ctx.config, style=style)
        self.config.set_style(style)
        self.style = style_factory(self.config.get_style())
        try:
            gathered_commands = GatherCommands(self.config)
            self.completer = completer or AzCompleter(self, gathered_commands)
            self.completer.initialize_command_table_attributes()
            self.lexer = lexer or get_az_lexer(gathered_commands)
        except IOError:  # if there is no cache
            self.completer = AzCompleter(self, None)
            self.lexer = None
        self.history = history or FileHistory(
            os.path.join(self.config.get_config_dir(),
                         self.config.get_history()))
        os.environ[ENV_ADDITIONAL_USER_AGENT] = 'AZURECLISHELL/' + VERSION

        # OH WHAT FUN TO FIGURE OUT WHAT THESE ARE!
        self._cli = None
        self.layout = None
        self.description_docs = u''
        self.param_docs = u''
        self.example_docs = u''
        self.last = None
        self.last_exit = 0
        self.user_feedback = user_feedback
        self.input = input_custom
        self.output = output_custom
        self.config_default = ""
        self.default_command = ""
        self.threads = []
        self.curr_thread = None
        self.spin_val = -1
        self.intermediate_sleep = intermediate_sleep
        self.final_sleep = final_sleep
        self.command_table_thread = None

        # try to consolidate state information here...
        # Used by key bindings and layout
        self.example_page = 1
        self.is_prompting = False
        self.is_example_repl = False
        self.is_showing_default = False
        self.is_symbols = True

    def __call__(self):

        if self.cli_ctx.data["az_interactive_active"]:
            logger.warning("You're in the interactive shell already.")
            return

        if self.config.BOOLEAN_STATES[self.config.config.get(
                'DEFAULT', 'firsttime')]:
            self.config.firsttime()

        if not self.config.has_feedback() and frequency_heuristic(self):
            print(
                "\n\nAny comments or concerns? You can use the \'feedback\' command!"
                + " We would greatly appreciate it.\n")

        self.cli_ctx.data["az_interactive_active"] = True
        self.run()
        self.cli_ctx.data["az_interactive_active"] = False

    @property
    def cli(self):
        """ Makes the interface or refreshes it """
        if self._cli is None:
            self._cli = self.create_interface()
        return self._cli

    def handle_cd(self, cmd):
        """changes dir """
        if len(cmd) != 2:
            print("Invalid syntax: cd path", file=self.output)
            return
        path = os.path.expandvars(os.path.expanduser(cmd[1]))
        try:
            os.chdir(path)
        except OSError as ex:
            print("cd: %s\n" % ex, file=self.output)

    def on_input_timeout(self, cli):
        """
        brings up the metadata for the command if there is a valid command already typed
        """
        document = cli.current_buffer.document
        text = document.text

        text = text.replace('az ', '')
        if self.default_command:
            text = self.default_command + ' ' + text

        param_info, example = self.generate_help_text()

        self.param_docs = u'{}'.format(param_info)
        self.example_docs = u'{}'.format(example)

        self._update_default_info()

        cli.buffers['description'].reset(initial_document=Document(
            self.description_docs, cursor_position=0))
        cli.buffers['parameter'].reset(
            initial_document=Document(self.param_docs))
        cli.buffers['examples'].reset(
            initial_document=Document(self.example_docs))
        cli.buffers['default_values'].reset(initial_document=Document(
            u'{}'.format(self.config_default if self.
                         config_default else 'No Default Values')))
        self._update_toolbar()
        cli.request_redraw()

    def restart_completer(self):
        command_info = GatherCommands(self.config)
        if not self.completer:
            self.completer.start(command_info)
        self.completer.initialize_command_table_attributes()
        if not self.lexer:
            self.lexer = get_az_lexer(command_info)
        self._cli = None

    def _space_examples(self, list_examples, rows, section_value):
        """ makes the example text """
        examples_with_index = []

        for i, _ in list(enumerate(list_examples)):
            if len(list_examples[i]) > 1:
                examples_with_index.append("[" + str(i + 1) + "] " +
                                           list_examples[i][0] +
                                           list_examples[i][1])

        example = "".join(exam for exam in examples_with_index)
        num_newline = example.count('\n')

        page_number = ''
        if num_newline > rows * PART_SCREEN_EXAMPLE and rows > PART_SCREEN_EXAMPLE * 10:
            len_of_excerpt = math.floor(float(rows) * PART_SCREEN_EXAMPLE)

            group = example.split('\n')
            end = int(section_value * len_of_excerpt)
            begin = int((section_value - 1) * len_of_excerpt)

            if end < num_newline:
                example = '\n'.join(group[begin:end]) + "\n"
            else:
                # default chops top off
                example = '\n'.join(group[begin:]) + "\n"
                while ((section_value - 1) * len_of_excerpt) > num_newline:
                    self.example_page -= 1
            page_number = '\n' + str(section_value) + "/" + str(
                int(math.ceil(num_newline / len_of_excerpt)))

        return example + page_number + ' CTRL+Y (^) CTRL+N (v)'

    def _update_toolbar(self):
        cli = self.cli
        _, cols = get_window_dim()
        cols = int(cols)

        empty_space = " " * cols

        delta = datetime.datetime.utcnow() - START_TIME
        if self.user_feedback and delta.seconds < DISPLAY_TIME:
            toolbar = [
                ' Try out the \'feedback\' command',
                'If refreshed disappear in: {}'.format(
                    str(DISPLAY_TIME - delta.seconds))
            ]
        elif self.command_table_thread.is_alive():
            toolbar = [' Loading...', 'Hit [enter] to refresh']
        else:
            toolbar = self._toolbar_info()

        toolbar, empty_space = space_toolbar(toolbar, empty_space)
        cli.buffers['bottom_toolbar'].reset(initial_document=Document(
            u'{}{}{}'.format(NOTIFICATIONS, toolbar, empty_space)))

    def _toolbar_info(self):
        sub_name = ""
        try:
            profile = Profile(cli_ctx=self.cli_ctx)
            sub_name = profile.get_subscription()[_SUBSCRIPTION_NAME]
        except CLIError:
            pass

        curr_cloud = "Cloud: {}".format(self.cli_ctx.cloud.name)

        tool_val = 'Subscription: {}'.format(
            sub_name) if sub_name else curr_cloud

        settings_items = [
            " [F1]Layout", "[F2]Defaults", "[F3]Keys", "[Ctrl+D]Quit", tool_val
        ]
        return settings_items

    def generate_help_text(self):
        """ generates the help text based on commands typed """
        param_descrip = example = ""
        self.description_docs = u''

        rows, _ = get_window_dim()
        rows = int(rows)

        param_args = self.completer.leftover_args
        last_word = self.completer.unfinished_word
        command = self.completer.current_command
        new_command = ' '.join([command, last_word]).strip()

        if not self.completer.complete_command and new_command in self.completer.command_description:
            command = new_command

        # get command/group help
        if self.completer and command in self.completer.command_description:
            self.description_docs = u'{}'.format(
                self.completer.command_description[command])

        # get parameter help if full command
        if self.completer and command in self.completer.command_param_info:
            param = param_args[-1] if param_args else ''
            param = last_word if last_word.startswith('-') else param

            if param in self.completer.command_param_info[
                    command] and self.completer.has_description(command + " " +
                                                                param):
                param_descrip = ''.join([
                    param, ":", '\n',
                    self.completer.param_description.get(
                        command + " " + param, '')
                ])

            if command in self.completer.command_examples:
                string_example = []
                for example in self.completer.command_examples[command]:
                    for part in example:
                        string_example.append(part)
                ''.join(string_example)
                example = self._space_examples(
                    self.completer.command_examples[command], rows,
                    self.example_page)

        return param_descrip, example

    def _update_default_info(self):
        try:
            defaults_section = self.cli_ctx.config.defaults_section_name
            options = self.cli_ctx.config.config_parser.options(
                defaults_section)
            self.config_default = ""
            for opt in options:
                self.config_default += opt + ": " + self.cli_ctx.config.get(
                    defaults_section, opt) + "  "
        except configparser.NoSectionError:
            self.config_default = ""

    def create_application(self, full_layout=True):
        """ makes the application object and the buffers """
        layout_manager = LayoutManager(self)
        if full_layout:
            layout = layout_manager.create_layout(ExampleLexer, ToolbarLexer)
        else:
            layout = layout_manager.create_tutorial_layout()

        buffers = {
            DEFAULT_BUFFER: Buffer(is_multiline=True),
            'description': Buffer(is_multiline=True, read_only=True),
            'parameter': Buffer(is_multiline=True, read_only=True),
            'examples': Buffer(is_multiline=True, read_only=True),
            'bottom_toolbar': Buffer(is_multiline=True),
            'example_line': Buffer(is_multiline=True),
            'default_values': Buffer(),
            'symbols': Buffer(),
            'progress': Buffer(is_multiline=False)
        }

        writing_buffer = Buffer(history=self.history,
                                auto_suggest=AutoSuggestFromHistory(),
                                enable_history_search=True,
                                completer=self.completer,
                                complete_while_typing=Always())

        return Application(
            mouse_support=False,
            style=self.style,
            buffer=writing_buffer,
            on_input_timeout=self.on_input_timeout,
            key_bindings_registry=InteractiveKeyBindings(self).registry,
            layout=layout,
            buffers=buffers,
        )

    def create_interface(self):
        """ instantiates the interface """
        return CommandLineInterface(application=self.create_application(),
                                    eventloop=create_eventloop())

    def set_prompt(self, prompt_command="", position=0):
        """ writes the prompt line """
        self.description_docs = u'{}'.format(prompt_command)
        self.cli.current_buffer.reset(initial_document=Document(
            self.description_docs, cursor_position=position))
        self.cli.request_redraw()

    def set_scope(self, value):
        """ narrows the scopes the commands """
        if self.default_command:
            self.default_command += ' ' + value
        else:
            self.default_command += value
        return value

    def handle_example(self, text, continue_flag):
        """ parses for the tutorial """
        cmd = text.partition(SELECT_SYMBOL['example'])[0].rstrip()
        num = text.partition(SELECT_SYMBOL['example'])[2].strip()
        example = ""
        try:
            num = int(num) - 1
        except ValueError:
            print("An Integer should follow the colon", file=self.output)
            return ""
        if cmd in self.completer.command_examples:
            if num >= 0 and num < len(self.completer.command_examples[cmd]):
                example = self.completer.command_examples[cmd][num][1]
                example = example.replace('\n', '')
            else:
                print('Invalid example number', file=self.output)
                return '', True

        example = example.replace('az', '')

        starting_index = None
        counter = 0
        example_no_fill = ""
        flag_fill = True
        for word in example.split():
            if flag_fill:
                example_no_fill += word + " "
            if word.startswith('-'):
                example_no_fill += word + " "
                if not starting_index:
                    starting_index = counter
                flag_fill = False
            counter += 1

        return self.example_repl(example_no_fill, example, starting_index,
                                 continue_flag)

    def example_repl(self, text, example, start_index, continue_flag):
        """ REPL for interactive tutorials """
        if start_index:
            start_index = start_index + 1
            cmd = ' '.join(text.split()[:start_index])
            example_cli = CommandLineInterface(
                application=self.create_application(full_layout=False),
                eventloop=create_eventloop())
            example_cli.buffers['example_line'].reset(
                initial_document=Document(u'{}\n'.format(add_new_lines(
                    example))))
            while start_index < len(text.split()):
                if self.default_command:
                    cmd = cmd.replace(self.default_command + ' ', '')
                example_cli.buffers[DEFAULT_BUFFER].reset(
                    initial_document=Document(u'{}'.format(cmd),
                                              cursor_position=len(cmd)))
                example_cli.request_redraw()
                answer = example_cli.run()
                if not answer:
                    return "", True
                answer = answer.text
                if answer.strip('\n') == cmd.strip('\n'):
                    continue
                else:
                    if len(answer.split()) > 1:
                        start_index += 1
                        cmd += " " + answer.split()[-1] + " " +\
                               u' '.join(text.split()[start_index:start_index + 1])
            example_cli.exit()
            del example_cli
        else:
            cmd = text

        return cmd, continue_flag

    # pylint: disable=too-many-statements
    def _special_cases(self, cmd, outside):
        break_flag = False
        continue_flag = False
        args = parse_quotes(cmd)
        cmd_stripped = cmd.strip()

        if not cmd_stripped and cmd:
            # add scope if there are only spaces
            cmd = self.default_command + " " + cmd
        elif cmd_stripped in ("quit", "exit"):
            break_flag = True
        elif cmd_stripped == "clear-history":
            continue_flag = True
            self.reset_history()
        elif cmd_stripped == CLEAR_WORD:
            outside = True
            cmd = CLEAR_WORD
        elif cmd_stripped[0] == SELECT_SYMBOL['outside']:
            cmd = cmd_stripped[1:]
            outside = True
            if cmd.strip() and cmd.split()[0] == 'cd':
                self.handle_cd(parse_quotes(cmd))
                continue_flag = True
            telemetry.track_outside_gesture()

        elif cmd_stripped[0] == SELECT_SYMBOL['exit_code']:
            meaning = "Success" if self.last_exit == 0 else "Failure"

            print(meaning + ": " + str(self.last_exit), file=self.output)
            continue_flag = True
            telemetry.track_exit_code_gesture()
        elif SELECT_SYMBOL[
                'query'] in cmd_stripped and self.last and self.last.result:
            continue_flag = self.handle_jmespath_query(args)
            telemetry.track_query_gesture()
        elif not args:
            continue_flag = True
        elif args[0] == '--version' or args[0] == '-v':
            try:
                continue_flag = True
                self.cli_ctx.show_version()
            except SystemExit:
                pass
        elif SELECT_SYMBOL['example'] in cmd:
            cmd, continue_flag = self.handle_example(cmd, continue_flag)
            telemetry.track_ran_tutorial()
        elif SELECT_SYMBOL['scope'] == cmd_stripped[0:2]:
            continue_flag, cmd = self.handle_scoping_input(
                continue_flag, cmd, cmd_stripped)
            telemetry.track_scope_changes()
        else:
            # not a special character; add scope and remove 'az'
            if self.default_command:
                cmd = self.default_command + " " + cmd
            elif cmd.split(' ', 1)[0].lower() == 'az':
                cmd = ' '.join(cmd.split()[1:])
            if "|" in cmd or ">" in cmd:
                # anything I don't parse, send off
                outside = True
                cmd = "az " + cmd
            telemetry.track_cli_commands_used()

        return break_flag, continue_flag, outside, cmd

    def handle_jmespath_query(self, args):
        """ handles the jmespath query for injection or printing """
        continue_flag = False
        query_symbol = SELECT_SYMBOL['query']
        symbol_len = len(query_symbol)
        try:
            if len(args) == 1:
                # if arguments start with query_symbol, just print query result
                if args[0] == query_symbol:
                    result = self.last.result
                elif args[0].startswith(query_symbol):
                    result = jmespath.search(args[0][symbol_len:],
                                             self.last.result)
                print(json.dumps(result, sort_keys=True, indent=2),
                      file=self.output)
            elif args[0].startswith(query_symbol):
                # print error message, user unsure of query shortcut usage
                print((
                    "Usage Error: " + os.linesep +
                    "1. Use {0} stand-alone to display previous result with optional filtering "
                    "(Ex: {0}[jmespath query])" + os.linesep + "OR:" +
                    os.linesep +
                    "2. Use {0} to query the previous result for argument values "
                    "(Ex: group show --name {0}[jmespath query])"
                ).format(query_symbol),
                      file=self.output)
            else:
                # query, inject into cmd
                def jmespath_query(match):
                    if match.group(0) == query_symbol:
                        return str(self.last.result)
                    query_result = jmespath.search(
                        match.group(0)[symbol_len:], self.last.result)
                    return str(query_result)

                def sub_result(arg):
                    escaped_symbol = re.escape(query_symbol)
                    # regex captures query symbol and all characters following it in the argument
                    return json.dumps(
                        re.sub(r'%s.*' % escaped_symbol, jmespath_query, arg))

                cmd_base = ' '.join(map(sub_result, args))
                self.cli_execute(cmd_base)
            continue_flag = True
        except (jmespath.exceptions.ParseError, CLIError) as e:
            print("Invalid Query Input: " + str(e), file=self.output)
            continue_flag = True
        return continue_flag

    def handle_scoping_input(self, continue_flag, cmd, text):
        """ handles what to do with a scoping gesture """
        default_split = text.partition(SELECT_SYMBOL['scope'])[2].split()
        cmd = cmd.replace(SELECT_SYMBOL['scope'], '')

        continue_flag = True

        if not default_split:
            self.default_command = ""
            print('unscoping all', file=self.output)

            return continue_flag, cmd

        while default_split:
            if not text:
                value = ''
            else:
                value = default_split[0]

            tree_path = self.default_command.split()
            tree_path.append(value)

            if self.completer.command_tree.in_tree(tree_path):
                self.set_scope(value)
                print("defaulting: " + value, file=self.output)
                cmd = cmd.replace(SELECT_SYMBOL['scope'], '')
            elif SELECT_SYMBOL['unscope'] == default_split[
                    0] and self.default_command.split():

                value = self.default_command.split()[-1]
                self.default_command = ' ' + ' '.join(
                    self.default_command.split()[:-1])

                if not self.default_command.strip():
                    self.default_command = self.default_command.strip()
                print('unscoping: ' + value, file=self.output)

            elif SELECT_SYMBOL['unscope'] not in text:
                print("Scope must be a valid command", file=self.output)

            default_split = default_split[1:]
        return continue_flag, cmd

    def reset_history(self):
        history_file_path = os.path.join(self.config.get_config_dir(),
                                         self.config.get_history())
        os.remove(history_file_path)
        self.history = FileHistory(history_file_path)
        self.cli.buffers[DEFAULT_BUFFER].history = self.history

    def cli_execute(self, cmd):
        """ sends the command to the CLI to be executed """

        try:
            args = parse_quotes(cmd)

            if args and args[0] == 'feedback':
                self.config.set_feedback('yes')
                self.user_feedback = False

            azure_folder = get_config_dir()
            if not os.path.exists(azure_folder):
                os.makedirs(azure_folder)
            ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json'))
            CONFIG.load(os.path.join(azure_folder, 'az.json'))
            SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600)

            invocation = self.cli_ctx.invocation_cls(
                cli_ctx=self.cli_ctx,
                parser_cls=self.cli_ctx.parser_cls,
                commands_loader_cls=self.cli_ctx.commands_loader_cls,
                help_cls=self.cli_ctx.help_cls)

            if '--progress' in args:
                args.remove('--progress')
                execute_args = [args]
                thread = Thread(target=invocation.execute, args=execute_args)
                thread.daemon = True
                thread.start()
                self.threads.append(thread)
                self.curr_thread = thread

                progress_args = [self]
                thread = Thread(target=progress_view, args=progress_args)
                thread.daemon = True
                thread.start()
                self.threads.append(thread)
                result = None
            else:
                result = invocation.execute(args)

            self.last_exit = 0
            if result and result.result is not None:
                if self.output:
                    self.output.write(result)
                    self.output.flush()
                else:
                    formatter = self.cli_ctx.output.get_formatter(
                        self.cli_ctx.invocation.data['output'])
                    self.cli_ctx.output.out(result,
                                            formatter=formatter,
                                            out_file=sys.stdout)
                    self.last = result

        except Exception as ex:  # pylint: disable=broad-except
            self.last_exit = handle_exception(ex)
        except SystemExit as ex:
            self.last_exit = int(ex.code)

    def progress_patch(self, _=False):
        """ forces to use the Shell Progress """
        from .progress import ShellProgressView
        self.cli_ctx.progress_controller.init_progress(ShellProgressView())
        return self.cli_ctx.progress_controller

    def run(self):
        """ starts the REPL """
        from .progress import ShellProgressView
        self.cli_ctx.get_progress_controller().init_progress(
            ShellProgressView())
        self.cli_ctx.get_progress_controller = self.progress_patch

        self.command_table_thread = LoadCommandTableThread(
            self.restart_completer, self)
        self.command_table_thread.start()

        from .configuration import SHELL_HELP
        self.cli.buffers['symbols'].reset(
            initial_document=Document(u'{}'.format(SHELL_HELP)))
        # flush telemetry for new commands and send successful interactive mode entry event
        telemetry.set_success()
        telemetry.flush()
        while True:
            try:
                document = self.cli.run(reset_current_buffer=True)
                text = document.text
                if not text:
                    # not input
                    self.set_prompt()
                    continue
                cmd = text
                outside = False

            except AttributeError:
                # when the user pressed Control D
                break
            except (KeyboardInterrupt, ValueError):
                # CTRL C
                self.set_prompt()
                continue
            else:
                self.history.append(text)
                b_flag, c_flag, outside, cmd = self._special_cases(
                    cmd, outside)

                if b_flag:
                    break
                if c_flag:
                    self.set_prompt()
                    continue

                self.set_prompt()

                if outside:
                    subprocess.Popen(cmd, shell=True).communicate()
                else:
                    telemetry.start()
                    self.cli_execute(cmd)
                    if self.last_exit and self.last_exit != 0:
                        telemetry.set_failure()
                    else:
                        telemetry.set_success()
                    telemetry.flush()
        telemetry.conclude()
Ejemplo n.º 21
0
from __future__ import unicode_literals
from prompt_toolkit import prompt
# 导入历史模块类,实现查找历史的功能
from prompt_toolkit.history import FileHistory
# 实现用户输入时候自动提示
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
# tab自动补全提示命令,旧版的WordCompleter不可用了
from prompt_toolkit.contrib.completers import SystemCompleter


SQLCompleter = SystemCompleter()


while True:
    user_input = prompt('>', history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                        completer=SQLCompleter, )
    print(user_input)
Ejemplo n.º 22
0
    def __init__(self,
                 get_globals=None, get_locals=None, history_filename=None,
                 vi_mode=False,

                 # For internal use.
                 _completer=None, _validator=None,
                 _lexer=None, _extra_buffers=None, _extra_buffer_processors=None,
                 _on_start=None,
                 _extra_layout_body=None, _extra_toolbars=None,
                 _input_buffer_height=None,
                 _accept_action=AcceptAction.RETURN_DOCUMENT,
                 _on_exit=AbortAction.RAISE_EXCEPTION):

        self.get_globals = get_globals or (lambda: {})
        self.get_locals = get_locals or self.get_globals

        self._completer = _completer or PythonCompleter(self.get_globals, self.get_locals)
        self._validator = _validator or PythonValidator(self.get_compiler_flags)
        self.history = FileHistory(history_filename) if history_filename else InMemoryHistory()
        self._lexer = _lexer or PygmentsLexer(PythonLexer)
        self._extra_buffers = _extra_buffers
        self._accept_action = _accept_action
        self._on_exit = _on_exit
        self._on_start = _on_start

        self._input_buffer_height = _input_buffer_height
        self._extra_layout_body = _extra_layout_body or []
        self._extra_toolbars = _extra_toolbars or []
        self._extra_buffer_processors = _extra_buffer_processors or []

        # Settings.
        self.show_signature = False
        self.show_docstring = False
        self.show_meta_enter_message = True
        self.completion_visualisation = CompletionVisualisation.MULTI_COLUMN
        self.completion_menu_scroll_offset = 1

        self.show_line_numbers = False
        self.show_status_bar = True
        self.wrap_lines = True
        self.complete_while_typing = True
        self.vi_mode = vi_mode
        self.paste_mode = False  # When True, don't insert whitespace after newline.
        self.confirm_exit = True  # Ask for confirmation when Control-D is pressed.
        self.accept_input_on_enter = 2  # Accept when pressing Enter 'n' times.
                                        # 'None' means that meta-enter is always required.
        self.enable_open_in_editor = True
        self.enable_system_bindings = True
        self.enable_input_validation = True
        self.enable_auto_suggest = False
        self.enable_mouse_support = False
        self.enable_history_search = False  # When True, like readline, going
                                            # back in history will filter the
                                            # history on the records starting
                                            # with the current input.

        self.highlight_matching_parenthesis = False
        self.show_sidebar = False  # Currently show the sidebar.
        self.show_sidebar_help = True # When the sidebar is visible, also show the help text.
        self.show_exit_confirmation = False  # Currently show 'Do you really want to exit?'
        self.terminal_title = None  # The title to be displayed in the terminal. (None or string.)
        self.exit_message = 'Do you really want to exit?'

        # Tokens to be shown at the prompt.
        self.prompt_style = 'classic'  # The currently active style.

        self.all_prompt_styles = {  # Styles selectable from the menu.
            'ipython': IPythonPrompt(self),
            'classic': ClassicPrompt(),
        }

        self.get_input_prompt_tokens = lambda cli: \
            self.all_prompt_styles[self.prompt_style].in_tokens(cli)

        self.get_output_prompt_tokens = lambda cli: \
            self.all_prompt_styles[self.prompt_style].out_tokens(cli)

        #: Load styles.
        self.code_styles = get_all_code_styles()
        self.ui_styles = get_all_ui_styles()
        self._current_code_style_name = 'default'
        self._current_ui_style_name = 'default'

        if is_windows():
            self._current_code_style_name = 'win32'

        self._current_style = self._generate_style()
        self.true_color = False

        # Options to be configurable from the sidebar.
        self.options = self._create_options()
        self.selected_option_index = 0

        #: Incremeting integer counting the current statement.
        self.current_statement_index = 1

        # Code signatures. (This is set asynchronously after a timeout.)
        self.signatures = []

        # Use a KeyBindingManager for loading the key bindings.
        self.key_bindings_manager = KeyBindingManager(
            enable_abort_and_exit_bindings=True,
            enable_search=True,
            enable_vi_mode=Condition(lambda cli: self.vi_mode),
            enable_open_in_editor=Condition(lambda cli: self.enable_open_in_editor),
            enable_system_bindings=Condition(lambda cli: self.enable_system_bindings),
            enable_auto_suggest_bindings=Condition(lambda cli: self.enable_auto_suggest),

            # Disable all default key bindings when the sidebar or the exit confirmation
            # are shown.
            enable_all=Condition(lambda cli: not (self.show_sidebar or self.show_exit_confirmation)))

        load_python_bindings(self.key_bindings_manager, self)
        load_sidebar_bindings(self.key_bindings_manager, self)
        load_confirm_exit_bindings(self.key_bindings_manager, self)

        # Boolean indicating whether we have a signatures thread running.
        # (Never run more than one at the same time.)
        self._get_signatures_thread_running = False
Ejemplo n.º 23
0
class AzInteractiveShell(object):

    def __init__(self, cli_ctx, style=None, completer=None,
                 lexer=None, history=None,
                 input_custom=sys.stdin, output_custom=None,
                 user_feedback=False, intermediate_sleep=.25, final_sleep=4):

        from .color_styles import style_factory

        self.cli_ctx = cli_ctx
        self.config = Configuration(cli_ctx.config, style=style)
        self.config.set_style(style)
        self.style = style_factory(self.config.get_style())
        try:
            gathered_commands = GatherCommands(self.config)
            self.completer = completer or AzCompleter(self, gathered_commands)
            self.completer.initialize_command_table_attributes()
            self.lexer = lexer or get_az_lexer(gathered_commands)
        except IOError:  # if there is no cache
            self.completer = AzCompleter(self, None)
            self.lexer = None
        self.history = history or FileHistory(os.path.join(self.config.get_config_dir(), self.config.get_history()))
        os.environ[ENV_ADDITIONAL_USER_AGENT] = 'AZURECLISHELL/' + __version__

        # OH WHAT FUN TO FIGURE OUT WHAT THESE ARE!
        self._cli = None
        self.layout = None
        self.description_docs = u''
        self.param_docs = u''
        self.example_docs = u''
        self.last = None
        self.last_exit = 0
        self.user_feedback = user_feedback
        self.input = input_custom
        self.output = output_custom
        self.config_default = ""
        self.default_command = ""
        self.threads = []
        self.curr_thread = None
        self.spin_val = -1
        self.intermediate_sleep = intermediate_sleep
        self.final_sleep = final_sleep
        self.command_table_thread = None

        # try to consolidate state information here...
        # Used by key bindings and layout
        self.example_page = 1
        self.is_prompting = False
        self.is_example_repl = False
        self.is_showing_default = False
        self.is_symbols = True

    def __call__(self):

        if self.cli_ctx.data["az_interactive_active"]:
            logger.warning("You're in the interactive shell already.")
            return

        if self.config.BOOLEAN_STATES[self.config.config.get('DEFAULT', 'firsttime')]:
            self.config.firsttime()

        if not self.config.has_feedback() and frequency_heuristic(self):
            print("\n\nAny comments or concerns? You can use the \'feedback\' command!" +
                  " We would greatly appreciate it.\n")

        self.cli_ctx.data["az_interactive_active"] = True
        self.run()
        self.cli_ctx.data["az_interactive_active"] = False

    @property
    def cli(self):
        """ Makes the interface or refreshes it """
        if self._cli is None:
            self._cli = self.create_interface()
        return self._cli

    def handle_cd(self, cmd):
        """changes dir """
        if len(cmd) != 2:
            print("Invalid syntax: cd path", file=self.output)
            return
        path = os.path.expandvars(os.path.expanduser(cmd[1]))
        try:
            os.chdir(path)
        except OSError as ex:
            print("cd: %s\n" % ex, file=self.output)

    def on_input_timeout(self, cli):
        """
        brings up the metadata for the command if there is a valid command already typed
        """
        document = cli.current_buffer.document
        text = document.text

        text = text.replace('az ', '')
        if self.default_command:
            text = self.default_command + ' ' + text

        param_info, example = self.generate_help_text()

        self.param_docs = u'{}'.format(param_info)
        self.example_docs = u'{}'.format(example)

        self._update_default_info()

        cli.buffers['description'].reset(
            initial_document=Document(self.description_docs, cursor_position=0))
        cli.buffers['parameter'].reset(
            initial_document=Document(self.param_docs))
        cli.buffers['examples'].reset(
            initial_document=Document(self.example_docs))
        cli.buffers['default_values'].reset(
            initial_document=Document(
                u'{}'.format(self.config_default if self.config_default else 'No Default Values')))
        self._update_toolbar()
        cli.request_redraw()

    def restart_completer(self):
        command_info = GatherCommands(self.config)
        if not self.completer:
            self.completer.start(command_info)
        self.completer.initialize_command_table_attributes()
        if not self.lexer:
            self.lexer = get_az_lexer(command_info)
        self._cli = None

    def _space_examples(self, list_examples, rows, section_value):
        """ makes the example text """
        examples_with_index = []

        for i, _ in list(enumerate(list_examples)):
            if len(list_examples[i]) > 1:
                examples_with_index.append("[" + str(i + 1) + "] " + list_examples[i][0] +
                                           list_examples[i][1])

        example = "".join(exam for exam in examples_with_index)
        num_newline = example.count('\n')

        page_number = ''
        if num_newline > rows * PART_SCREEN_EXAMPLE and rows > PART_SCREEN_EXAMPLE * 10:
            len_of_excerpt = math.floor(float(rows) * PART_SCREEN_EXAMPLE)

            group = example.split('\n')
            end = int(section_value * len_of_excerpt)
            begin = int((section_value - 1) * len_of_excerpt)

            if end < num_newline:
                example = '\n'.join(group[begin:end]) + "\n"
            else:
                # default chops top off
                example = '\n'.join(group[begin:]) + "\n"
                while ((section_value - 1) * len_of_excerpt) > num_newline:
                    self.example_page -= 1
            page_number = '\n' + str(section_value) + "/" + str(int(math.ceil(num_newline / len_of_excerpt)))

        return example + page_number + ' CTRL+Y (^) CTRL+N (v)'

    def _update_toolbar(self):
        cli = self.cli
        _, cols = get_window_dim()
        cols = int(cols)

        empty_space = " " * cols

        delta = datetime.datetime.utcnow() - START_TIME
        if self.user_feedback and delta.seconds < DISPLAY_TIME:
            toolbar = [
                ' Try out the \'feedback\' command',
                'If refreshed disappear in: {}'.format(str(DISPLAY_TIME - delta.seconds))]
        elif self.command_table_thread.is_alive():
            toolbar = [
                ' Loading...',
                'Hit [enter] to refresh'
            ]
        else:
            toolbar = self._toolbar_info()

        toolbar, empty_space = space_toolbar(toolbar, empty_space)
        cli.buffers['bottom_toolbar'].reset(
            initial_document=Document(u'{}{}{}'.format(NOTIFICATIONS, toolbar, empty_space)))

    def _toolbar_info(self):
        sub_name = ""
        try:
            profile = Profile(cli_ctx=self.cli_ctx)
            sub_name = profile.get_subscription()[_SUBSCRIPTION_NAME]
        except CLIError:
            pass

        curr_cloud = "Cloud: {}".format(self.cli_ctx.cloud.name)

        tool_val = 'Subscription: {}'.format(sub_name) if sub_name else curr_cloud

        settings_items = [
            " [F1]Layout",
            "[F2]Defaults",
            "[F3]Keys",
            "[Ctrl+D]Quit",
            tool_val
        ]
        return settings_items

    def generate_help_text(self):
        """ generates the help text based on commands typed """
        param_descrip = example = ""
        self.description_docs = u''

        rows, _ = get_window_dim()
        rows = int(rows)

        param_args = self.completer.leftover_args
        last_word = self.completer.unfinished_word
        command = self.completer.current_command
        new_command = ' '.join([command, last_word]).strip()

        if not self.completer.complete_command and new_command in self.completer.command_description:
            command = new_command

        # get command/group help
        if self.completer and command in self.completer.command_description:
            self.description_docs = u'{}'.format(self.completer.command_description[command])

        # get parameter help if full command
        if self.completer and command in self.completer.command_param_info:
            param = param_args[-1] if param_args else ''
            param = last_word if last_word.startswith('-') else param

            if param in self.completer.command_param_info[command] and self.completer.has_description(
                    command + " " + param):
                param_descrip = ''.join([
                    param, ":", '\n', self.completer.param_description.get(command + " " + param, '')])

            if command in self.completer.command_examples:
                string_example = []
                for example in self.completer.command_examples[command]:
                    for part in example:
                        string_example.append(part)
                ''.join(string_example)
                example = self._space_examples(
                    self.completer.command_examples[command], rows, self.example_page)

        return param_descrip, example

    def _update_default_info(self):
        try:
            options = self.cli_ctx.config.config_parser.options(DEFAULTS_SECTION)
            self.config_default = ""
            for opt in options:
                self.config_default += opt + ": " + self.cli_ctx.config.get(DEFAULTS_SECTION, opt) + "  "
        except configparser.NoSectionError:
            self.config_default = ""

    def create_application(self, full_layout=True):
        """ makes the application object and the buffers """
        layout_manager = LayoutManager(self)
        if full_layout:
            layout = layout_manager.create_layout(ExampleLexer, ToolbarLexer)
        else:
            layout = layout_manager.create_tutorial_layout()

        buffers = {
            DEFAULT_BUFFER: Buffer(is_multiline=True),
            'description': Buffer(is_multiline=True, read_only=True),
            'parameter': Buffer(is_multiline=True, read_only=True),
            'examples': Buffer(is_multiline=True, read_only=True),
            'bottom_toolbar': Buffer(is_multiline=True),
            'example_line': Buffer(is_multiline=True),
            'default_values': Buffer(),
            'symbols': Buffer(),
            'progress': Buffer(is_multiline=False)
        }

        writing_buffer = Buffer(
            history=self.history,
            auto_suggest=AutoSuggestFromHistory(),
            enable_history_search=True,
            completer=self.completer,
            complete_while_typing=Always()
        )

        return Application(
            mouse_support=False,
            style=self.style,
            buffer=writing_buffer,
            on_input_timeout=self.on_input_timeout,
            key_bindings_registry=InteractiveKeyBindings(self).registry,
            layout=layout,
            buffers=buffers,
        )

    def create_interface(self):
        """ instantiates the interface """
        from prompt_toolkit.interface import CommandLineInterface
        return CommandLineInterface(
            application=self.create_application(),
            eventloop=create_eventloop())

    def set_prompt(self, prompt_command="", position=0):
        """ writes the prompt line """
        self.description_docs = u'{}'.format(prompt_command)
        self.cli.current_buffer.reset(
            initial_document=Document(
                self.description_docs,
                cursor_position=position))
        self.cli.request_redraw()

    def set_scope(self, value):
        """ narrows the scopes the commands """
        if self.default_command:
            self.default_command += ' ' + value
        else:
            self.default_command += value
        return value

    def handle_example(self, text, continue_flag):
        """ parses for the tutorial """
        cmd = text.partition(SELECT_SYMBOL['example'])[0].rstrip()
        num = text.partition(SELECT_SYMBOL['example'])[2].strip()
        example = ""
        try:
            num = int(num) - 1
        except ValueError:
            print("An Integer should follow the colon", file=self.output)
            return ""
        if cmd in self.completer.command_examples:
            if num >= 0 and num < len(self.completer.command_examples[cmd]):
                example = self.completer.command_examples[cmd][num][1]
                example = example.replace('\n', '')
            else:
                print('Invalid example number', file=self.output)
                return '', True

        example = example.replace('az', '')

        starting_index = None
        counter = 0
        example_no_fill = ""
        flag_fill = True
        for word in example.split():
            if flag_fill:
                example_no_fill += word + " "
            if word.startswith('-'):
                example_no_fill += word + " "
                if not starting_index:
                    starting_index = counter
                flag_fill = False
            counter += 1

        return self.example_repl(example_no_fill, example, starting_index, continue_flag)

    def example_repl(self, text, example, start_index, continue_flag):
        """ REPL for interactive tutorials """
        from prompt_toolkit.interface import CommandLineInterface

        if start_index:
            start_index = start_index + 1
            cmd = ' '.join(text.split()[:start_index])
            example_cli = CommandLineInterface(
                application=self.create_application(
                    full_layout=False),
                eventloop=create_eventloop())
            example_cli.buffers['example_line'].reset(
                initial_document=Document(u'{}\n'.format(
                    add_new_lines(example)))
            )
            while start_index < len(text.split()):
                if self.default_command:
                    cmd = cmd.replace(self.default_command + ' ', '')
                example_cli.buffers[DEFAULT_BUFFER].reset(
                    initial_document=Document(
                        u'{}'.format(cmd),
                        cursor_position=len(cmd)))
                example_cli.request_redraw()
                answer = example_cli.run()
                if not answer:
                    return "", True
                answer = answer.text
                if answer.strip('\n') == cmd.strip('\n'):
                    continue
                else:
                    if len(answer.split()) > 1:
                        start_index += 1
                        cmd += " " + answer.split()[-1] + " " +\
                               u' '.join(text.split()[start_index:start_index + 1])
            example_cli.exit()
            del example_cli
        else:
            cmd = text

        return cmd, continue_flag

    # pylint: disable=too-many-statements
    def _special_cases(self, cmd, outside):
        break_flag = False
        continue_flag = False
        args = parse_quotes(cmd)
        cmd_stripped = cmd.strip()

        if not cmd_stripped and cmd:
            # add scope if there are only spaces
            cmd = self.default_command + " " + cmd
        elif cmd_stripped == "quit" or cmd_stripped == "exit":
            break_flag = True
        elif cmd_stripped == "clear-history":
            continue_flag = True
            self.reset_history()
        elif cmd_stripped == CLEAR_WORD:
            outside = True
            cmd = CLEAR_WORD
        elif cmd_stripped[0] == SELECT_SYMBOL['outside']:
            cmd = cmd_stripped[1:]
            outside = True
            if cmd.strip() and cmd.split()[0] == 'cd':
                self.handle_cd(parse_quotes(cmd))
                continue_flag = True
            telemetry.track_outside_gesture()

        elif cmd_stripped[0] == SELECT_SYMBOL['exit_code']:
            meaning = "Success" if self.last_exit == 0 else "Failure"

            print(meaning + ": " + str(self.last_exit), file=self.output)
            continue_flag = True
            telemetry.track_exit_code_gesture()
        elif SELECT_SYMBOL['query'] in cmd_stripped and self.last and self.last.result:
            continue_flag = self.handle_jmespath_query(args)
            telemetry.track_query_gesture()
        elif not args:
            continue_flag = True
        elif args[0] == '--version' or args[0] == '-v':
            try:
                continue_flag = True
                self.cli_ctx.show_version()
            except SystemExit:
                pass
        elif SELECT_SYMBOL['example'] in cmd:
            cmd, continue_flag = self.handle_example(cmd, continue_flag)
            telemetry.track_ran_tutorial()
        elif SELECT_SYMBOL['scope'] == cmd_stripped[0:2]:
            continue_flag, cmd = self.handle_scoping_input(continue_flag, cmd, cmd_stripped)
            telemetry.track_scope_changes()
        else:
            # not a special character; add scope and remove 'az'
            if self.default_command:
                cmd = self.default_command + " " + cmd
            elif cmd.split(' ', 1)[0].lower() == 'az':
                cmd = ' '.join(cmd.split()[1:])
            if "|" in cmd or ">" in cmd:
                # anything I don't parse, send off
                outside = True
                cmd = "az " + cmd
            telemetry.track_cli_commands_used()

        return break_flag, continue_flag, outside, cmd

    def handle_jmespath_query(self, args):
        """ handles the jmespath query for injection or printing """
        continue_flag = False
        query_symbol = SELECT_SYMBOL['query']
        symbol_len = len(query_symbol)
        try:
            if len(args) == 1:
                # if arguments start with query_symbol, just print query result
                if args[0] == query_symbol:
                    result = self.last.result
                elif args[0].startswith(query_symbol):
                    result = jmespath.search(args[0][symbol_len:], self.last.result)
                print(json.dumps(result, sort_keys=True, indent=2), file=self.output)
            elif args[0].startswith(query_symbol):
                # print error message, user unsure of query shortcut usage
                print(("Usage Error: " + os.linesep +
                       "1. Use {0} stand-alone to display previous result with optional filtering "
                       "(Ex: {0}[jmespath query])" +
                       os.linesep + "OR:" + os.linesep +
                       "2. Use {0} to query the previous result for argument values "
                       "(Ex: group show --name {0}[jmespath query])").format(query_symbol), file=self.output)
            else:
                # query, inject into cmd
                def jmespath_query(match):
                    if match.group(0) == query_symbol:
                        return str(self.last.result)
                    query_result = jmespath.search(match.group(0)[symbol_len:], self.last.result)
                    return str(query_result)

                def sub_result(arg):
                    escaped_symbol = re.escape(query_symbol)
                    # regex captures query symbol and all characters following it in the argument
                    return json.dumps(re.sub(r'%s.*' % escaped_symbol, jmespath_query, arg))
                cmd_base = ' '.join(map(sub_result, args))
                self.cli_execute(cmd_base)
            continue_flag = True
        except (jmespath.exceptions.ParseError, CLIError) as e:
            print("Invalid Query Input: " + str(e), file=self.output)
            continue_flag = True
        return continue_flag

    def handle_scoping_input(self, continue_flag, cmd, text):
        """ handles what to do with a scoping gesture """
        default_split = text.partition(SELECT_SYMBOL['scope'])[2].split()
        cmd = cmd.replace(SELECT_SYMBOL['scope'], '')

        continue_flag = True

        if not default_split:
            self.default_command = ""
            print('unscoping all', file=self.output)

            return continue_flag, cmd

        while default_split:
            if not text:
                value = ''
            else:
                value = default_split[0]

            tree_path = self.default_command.split()
            tree_path.append(value)

            if self.completer.command_tree.in_tree(tree_path):
                self.set_scope(value)
                print("defaulting: " + value, file=self.output)
                cmd = cmd.replace(SELECT_SYMBOL['scope'], '')
            elif SELECT_SYMBOL['unscope'] == default_split[0] and self.default_command.split():

                value = self.default_command.split()[-1]
                self.default_command = ' ' + ' '.join(self.default_command.split()[:-1])

                if not self.default_command.strip():
                    self.default_command = self.default_command.strip()
                print('unscoping: ' + value, file=self.output)

            elif SELECT_SYMBOL['unscope'] not in text:
                print("Scope must be a valid command", file=self.output)

            default_split = default_split[1:]
        return continue_flag, cmd

    def reset_history(self):
        history_file_path = os.path.join(self.config.get_config_dir(), self.config.get_history())
        os.remove(history_file_path)
        self.history = FileHistory(history_file_path)
        self.cli.buffers[DEFAULT_BUFFER].history = self.history

    def cli_execute(self, cmd):
        """ sends the command to the CLI to be executed """

        try:
            args = parse_quotes(cmd)

            if args and args[0] == 'feedback':
                self.config.set_feedback('yes')
                self.user_feedback = False

            azure_folder = get_config_dir()
            if not os.path.exists(azure_folder):
                os.makedirs(azure_folder)
            ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json'))
            CONFIG.load(os.path.join(azure_folder, 'az.json'))
            SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600)

            invocation = self.cli_ctx.invocation_cls(cli_ctx=self.cli_ctx,
                                                     parser_cls=self.cli_ctx.parser_cls,
                                                     commands_loader_cls=self.cli_ctx.commands_loader_cls,
                                                     help_cls=self.cli_ctx.help_cls)

            if '--progress' in args:
                args.remove('--progress')
                execute_args = [args]
                thread = Thread(target=invocation.execute, args=execute_args)
                thread.daemon = True
                thread.start()
                self.threads.append(thread)
                self.curr_thread = thread

                progress_args = [self]
                thread = Thread(target=progress_view, args=progress_args)
                thread.daemon = True
                thread.start()
                self.threads.append(thread)
                result = None
            else:
                result = invocation.execute(args)

            self.last_exit = 0
            if result and result.result is not None:
                from azure.cli.core._output import OutputProducer
                if self.output:
                    self.output.write(result)
                    self.output.flush()
                else:
                    formatter = OutputProducer.get_formatter(self.cli_ctx.invocation.data['output'])
                    OutputProducer(formatter=formatter).out(result)
                    self.last = result

        except Exception as ex:  # pylint: disable=broad-except
            self.last_exit = handle_exception(ex)
        except SystemExit as ex:
            self.last_exit = int(ex.code)

    def progress_patch(self, _=False):
        """ forces to use the Shell Progress """
        from .progress import ShellProgressView
        self.cli_ctx.progress_controller.init_progress(ShellProgressView())
        return self.cli_ctx.progress_controller

    def run(self):
        """ starts the REPL """
        from .progress import ShellProgressView
        self.cli_ctx.get_progress_controller().init_progress(ShellProgressView())
        self.cli_ctx.get_progress_controller = self.progress_patch

        self.command_table_thread = LoadCommandTableThread(self.restart_completer, self)
        self.command_table_thread.start()

        from .configuration import SHELL_HELP
        self.cli.buffers['symbols'].reset(
            initial_document=Document(u'{}'.format(SHELL_HELP)))
        # flush telemetry for new commands and send successful interactive mode entry event
        telemetry.set_success()
        telemetry.flush()
        while True:
            try:
                document = self.cli.run(reset_current_buffer=True)
                text = document.text
                if not text:
                    # not input
                    self.set_prompt()
                    continue
                cmd = text
                outside = False

            except AttributeError:
                # when the user pressed Control D
                break
            except (KeyboardInterrupt, ValueError):
                # CTRL C
                self.set_prompt()
                continue
            else:
                self.history.append(text)
                b_flag, c_flag, outside, cmd = self._special_cases(cmd, outside)

                if b_flag:
                    break
                if c_flag:
                    self.set_prompt()
                    continue

                self.set_prompt()

                if outside:
                    subprocess.Popen(cmd, shell=True).communicate()
                else:
                    telemetry.start()
                    self.cli_execute(cmd)
                    if self.last_exit and self.last_exit != 0:
                        telemetry.set_failure()
                    else:
                        telemetry.set_success()
                    telemetry.flush()
        telemetry.conclude()
Ejemplo n.º 24
0
def glob_search(env, search_text):
    p = _get_prefix(env)
    search_result = glob(os.path.join(p, search_text))
    if search_result:
        console.print(remove_prefix(search_result))
    else:
        console.print(f"[red]No results found for glob {search_text}[/red]")


def bottom_toolbar():
    return HTML(
        'Interactive mode is <b><style bg="ansired">experimental</style></b>!')


fh = FileHistory(".boa_tui_history")
session = PromptSession(fh)


def get_completer():
    def get_paths():
        return [build_context.config.work_dir]

    return NestedCompleter.from_nested_dict({
        "help":
        None,
        "glob": {
            "build": None,
            "host": None
        },
        "exit":