Beispiel #1
0
    def complete(self, text, state):  # pylint: disable=unused-argument
        '''
        Tab complete for the current step.
        '''

        if state == 0:
            parser = StatementParser(self.features)
            begidx = readline.get_begidx()
            endidx = readline.get_endidx()
            line = readline.get_line_buffer()
            prefix = line[begidx:endidx] if line else ''

            line = line[:endidx]
            if self.complete_single_token:
                # treat the entire line as a single token
                args = [line]
            else:
                # tokenize the line
                tokens = parser.tokenize(line)
                tokens = parser.condense(tokens)
                args = [t.text for t in tokens if isinstance(t, StringToken)]
            self.completions = self.active_step.complete(self, args, prefix)

        if state < len(self.completions):
            return self.completions[state]
        return None
Beispiel #2
0
    def __init__(self, shell_name='pypsi', width=80, exit_rc=-1024, ctx=None):
        '''
        :param str shell_name: the name of the shell; used in error messages
        :param int exit_rc: the exit return code that is returned from a command
            when the shell needs to end execution
        :param pypsi.namespace.Namespace ctx: the base context
        '''
        self.real_stdout = sys.stdout
        self.real_stdin = sys.stdin
        self.real_stderr = sys.stderr
        self.width = width
        self.shell_name = shell_name
        self.exit_rc = exit_rc
        self.errno = 0
        self.commands = {}
        self.preprocessors = []
        self.postprocessors = []
        self.plugins = []
        self.prompt = "{name} )> ".format(name=shell_name)
        self.ctx = ctx or Namespace()

        self.parser = StatementParser()
        self.default_cmd = None
        self.register_base_plugins()
        self.fallback_cmd = None

        self.on_shell_ready()
Beispiel #3
0
    def preprocess_single(self, raw, origin):
        tokens = self.on_tokenize([StringToken(0, raw, quote='"')], origin)

        if tokens:
            parser = StatementParser(self.features)
            parser.clean_escapes(tokens)
            ret = ''
            for token in tokens:
                ret += token.text
            return ret
        return ''
Beispiel #4
0
 def __init__(self, name, description, steps=None):
     '''
     :param str name: the prompt wizard name to display to the user
     :param str description: a short description of what the wizard does
     :param list steps: a list of :class:`WizardStep` objects
     '''
     self.name = name
     self.description = description
     self.steps = steps
     self.values = Namespace()
     self.parser = StatementParser()
Beispiel #5
0
    def __init__(self, shell_name='pypsi', width=79, exit_rc=-1024, ctx=None):
        '''
        Subclasses need to call the Shell constructor to properly initialize
        it.

        :param str shell_name: the name of the shell; used in error messages
        :param int exit_rc: the exit return code that is returned from a
            command when the shell needs to end execution
        :param pypsi.namespace.Namespace ctx: the base context
        '''
        self.backup_stdout = None
        self.backup_stdin = None
        self.backup_stderr = None
        self.backup_print = None

        self.width = width
        self.shell_name = shell_name
        self.exit_rc = exit_rc
        self.errno = 0
        self.commands = {}
        self.preprocessors = []
        self.postprocessors = []
        self.plugins = []
        self.prompt = "{name} )> ".format(name=shell_name)
        self.ctx = ctx or Namespace()

        self.parser = StatementParser()
        self.default_cmd = None
        self.register_base_plugins()
        self.fallback_cmd = None

        self.eof_is_sigint = False
        self._backup_completer = readline.get_completer()

        self.bootstrap()

        self.on_shell_ready()
Beispiel #6
0
    def get_completions(self, line, prefix):
        '''
        Get the list of completions given a line buffer and a prefix.

        :param str line: line buffer content up to cursor
        :param str prefix: readline prefix token
        :returns list[str]: list of completions
        '''
        try:
            parser = StatementParser(TabCompletionFeatures(self.features))
            tokens = parser.tokenize(line)
            parser.clean_escapes(tokens)

            cmd_name = ""
            loc = None
            args = []
            next_arg = True
            ret = []
            in_quote = None
            for token in tokens:
                if isinstance(token, StringToken):
                    in_quote = token.quote if token.open_quote else None
                    if not cmd_name:
                        cmd_name = token.text
                        loc = 'name'
                    elif loc == 'name':
                        cmd_name += token.text
                    else:
                        if next_arg:
                            args.append(token.text)
                            next_arg = False
                        else:
                            args[-1] += token.text
                elif isinstance(token, OperatorToken):
                    in_quote = None
                    if token.operator in ('|', ';', '&&', '||'):
                        cmd_name = None
                        args = []
                        next_arg = True
                    elif token.operator in ('>', '<', '>>'):
                        loc = 'path'
                        args = []
                elif isinstance(token, WhitespaceToken):
                    in_quote = None
                    if loc == 'name':
                        loc = None
                    next_arg = True

            if loc == 'path':
                ret = path_completer(''.join(args), prefix)
            elif not cmd_name or loc == 'name':
                if is_path_prefix(cmd_name):
                    ret = path_completer(cmd_name, prefix)
                else:
                    ret = self.get_command_name_completions(cmd_name)
            else:
                if cmd_name not in self.commands:
                    ret = []
                else:
                    if next_arg:
                        args.append('')

                    cmd = self.commands[cmd_name]
                    ret = cmd.complete(self, args, prefix)

            ret = self._clean_completions(ret, in_quote)
        except:
            ret = []

        return ret
Beispiel #7
0
    def execute(self, raw):
        '''
        Parse and execute a statement.

        :param str raw: the raw command line to parse.
        :param function input: a function that returns a string,
                                overrides default input function (stdin).
        :returns int: the return code of the statement.
        '''

        parser = StatementParser(self.features)
        input_complete = False
        while not input_complete:
            text = self.preprocess(raw, 'input')
            if text is None:
                return None

            try:
                tokens = parser.tokenize(text)
            except (UnclosedQuotationError, TrailingEscapeError):
                input_complete = False
            else:
                # Parsing succeeded, break out of the input loop
                input_complete = True

            if not input_complete:
                # This is a multiline input
                try:
                    # hide prompt if reading from a file
                    raw = input("> " if sys.stdin.isatty() else '')
                except (EOFError, KeyboardInterrupt) as e:
                    self.on_input_canceled()
                    raise e

        tokens = self.on_tokenize(tokens, 'input')
        statement = None

        if not tokens:
            return None

        try:
            statement = parser.build(tokens)
        except StatementSyntaxError as e:
            self.error(str(e))
            return 1

        rc = None

        if not statement:
            # The line was empty, a comment, or just contained whitespace.
            return rc

        # Setup the invocations
        for invoke in statement:
            try:
                # Open any and all I/O redirections and resolve the pypsi
                # command.
                invoke.setup(self)
            except Exception as e:
                for sub in statement:
                    sub.close_streams()

                if isinstance(e, (IORedirectionError, CommandNotFoundError)):
                    # pypsi can handle I/O redirection and command not found
                    # errors, these are not fatal.
                    self.error(str(e))
                    return -1
                # Unhandled fatal exception, re-raise it
                raise

        # Current pipe being built
        pipe = []

        # Process the statement
        for invoke in statement:
            if invoke.chain_pipe():
                # We are in a pipe
                pipe.append(invoke)
            else:
                # We are not in a pipe

                if pipe:
                    # We have a pipe built that needs to be executed.
                    # Create the invocation threads for the pipe.
                    threads, stdin = self.create_pipe_threads(pipe)
                    # Reset the building pipe
                    pipe = []
                    # Set the current invocation's stdin to the last
                    # invocation's stdout.
                    invoke.stdin = stdin
                else:
                    # We were not in a pipe
                    threads = []

                # Start all the pipe threads, if we are processing a pipe
                for t in threads:
                    t.start()

                # Execute the invocation in the current thread.
                try:
                    rc = invoke(self)
                except Exception as e:
                    # Unhandled exception, stop all threads if any are running.
                    for t in threads:
                        t.stop()

                    # Wait for threads to terminate.
                    try:
                        for t in threads:
                            t.join()
                    except:
                        # Something went wrong or a KeyboardInterrupt was
                        # issued. Stop waiting for threads to terminate.
                        pass

                    # Print thread-specific unhandled exceptions.
                    for t in threads:
                        if t.exc_info:
                            if t.exc_info[0] == OSError:
                                msg = t.exc_info[1].strerror
                            else:
                                msg = str(t.exc_info[1])

                            print(AnsiCodes.red,
                                  t.invoke.name,
                                  ": ",
                                  msg,
                                  AnsiCodes.reset,
                                  sep='')

                    if isinstance(e, KeyboardInterrupt):
                        # Ctrl+c was entered
                        print()
                        rc = -1
                    elif isinstance(e, SystemExit):
                        # The command is requesting to exit the shell.
                        rc = e.code  # pylint: disable=no-member
                        print("exiting....")
                        self.running = False
                    elif isinstance(e, RuntimeError):
                        # The command was aborted by a generic exception.
                        self.error("command aborted: " + str(e))
                        rc = -1
                    else:
                        # Unhandled fatal exception, re-raise it
                        raise

                self.errno = rc

                # Check if the statement's next invocation be executed.
                if not invoke.should_continue(rc):
                    break

        return rc
Beispiel #8
0
 def __init__(self, name, description, steps=None):
     self.name = name
     self.description = description
     self.steps = steps
     self.values = Namespace()
     self.parser = StatementParser()