Exemple #1
0
def _print_error(err: AnyErr):
    if is_int(err):
        if err != 0:  # 0 is success
            print(errno_str(err))
    elif is_str(err):
        print(err)
    else:
        log.w(f"err expected of type int or str, found {type(err)}")
        log.w(stacktrace(color=ansi.FG_YELLOW))
Exemple #2
0
def set_char_p(lib: CDLL, name: str, value: Union[bytes, str]):
    try:
        if is_str(value):
            value = c_stob(value)
        elif not is_bytes(value):
            raise TypeError(f"Exception bytes or str, found {type(value)}")

        c_char_p.in_dll(lib, name).value = value
    except Exception as e:
        log.w(f"set_char_p failed: {e}")
        raise CException(e)
Exemple #3
0
    def parse(self, args: Union[str, List[str]]) -> Optional[Args]:
        if is_str(args):
            args = self.split_args(args)

        if not is_list(args):
            raise TypeError(f"args must be a list, found {type(args)}")

        return Args.parse(
            args=args,
            positionals_spec=self.positionals_spec(),
            options_spec=self.options_spec(),
            continue_parsing_hook=self.continue_parsing_hook(),
        )
Exemple #4
0
def create_error_of_response(err: Union[int, str],
                             *subjects) -> Optional[ResponseError]:
    if is_int(err):
        # Consider err as an error number
        if not subjects:
            return {"errno": err}
        return {"errno": err, "subjects": [str(s) for s in subjects]}

    if is_str(err):
        # Consider err as a reason of a SPECIFIED_ERROR
        return {"errno": ServerErrors.GENERAL_ERROR, "subjects": err}

    return None
Exemple #5
0
 def quote_string(s: str) -> str:
     return "\"" + s + "\"" if is_str(s) else str(s)
Exemple #6
0
 def conv(o: Any):
     val = key(o) if key else o
     if is_str(val):
         val = val.lower()
     return val
Exemple #7
0
def is_request(req: Request) -> bool:
    """ Returns whether 'req' is a valid request """
    return \
        req and \
        is_dict(req) and \
        is_str(req.get("api", None))
Exemple #8
0
    def _next_suggestion(self, token: str, count: int):
        """
        Called by GNU readline when new suggestions have to be provided.
        Provide the next suggestion, or None if there is nothing more to suggest.
        """
        def escape(s: str):
            return s.replace(" ", "\\ ")

        def unescape(s: str):
            return s.replace("\\ ", " ")

        try:
            log.d(f"next_suggestion, token='{token}' | count={count}")

            # Never insert trailing quote, we will do it manually
            # (this is needed because for directory completion we should not
            # insert the trailing quote)
            rl_set_completion_suppress_quote(1)
            is_quoting = rl_get_completion_quote_character() == ord('"')

            if count == 0:

                self._current_line = readline.get_line_buffer()

                # Take out the trailing white spaces, and in case a ;
                # is found, ignore everything before it (was another command inline)
                line = rightof(self._current_line, ";", from_end=True).lstrip()

                # Unescape since the token might contain \ we inserted in next_suggestion
                # for allow spaces in the line
                token = unescape(token)
                line = unescape(line)

                # Detect the command (first token of the line) by resolving aliases
                # and figure out if the command is unique for the given prefix
                log.d(f"line: '{line}'")
                resolved_line = self._resolve_alias(line, as_string=True)
                resolved_command = self._command_for(resolved_line,
                                                     resolve_alias=False)
                log.d(f"resolved_line: '{resolved_line}'")
                log.d(f"resolved_command: '{resolved_command}'")

                no_suggestions = True  # keep track, in order to propose local
                # files if shell passthrough is True
                self._suggestions_intent = SuggestionsIntent([])

                for comm_name, comm_info in self._available_commands.items():
                    comm_resolved_name = comm_info.name(
                    ) if comm_info else None

                    log.d(f" > iterating, comm_name='{comm_name}'")
                    if resolved_command == comm_name and re.match(
                            Shell.COMM_SPACE_RE, line):
                        # Typing a COMPLETE command
                        # e.g. 'ls \t'
                        log.d(
                            f"Fetching suggestions for COMMAND INTENT '{comm_resolved_name}'"
                        )

                        if comm_info:
                            comms_sugg = comm_info.suggestions(
                                line, token, self._client)
                            if comms_sugg:
                                # don't let it to be None
                                self._suggestions_intent = comms_sugg

                                log.d(
                                    f"Fetched ({len(self._suggestions_intent.suggestions)}) "
                                    f"suggestions INTENT for command '{comm_name}'"
                                )
                        else:
                            log.w(
                                "Null comm info, maybe refers to a multi-command?"
                                "Not providing suggestions for it")

                        no_suggestions = False
                        break  # nothing more to complete, the command has been found

                    if comm_name.startswith(line):
                        # Typing an INCOMPLETE command
                        # e.g. 'clos\t'

                        # Case 1: complete command
                        log.d(
                            f"Adding suggestion for COMMAND COMPLETION of '{comm_resolved_name}'"
                        )
                        self._suggestions_intent.suggestions.append(
                            StyledString(comm_name))
                        no_suggestions = False

                # Translate the finding into the real name if the token
                # is exactly a finding
                if len(self._suggestions_intent.suggestions) == 1:
                    log.d(
                        "Just a suggestion, checking whether it is a finding pattern"
                    )

                    the_suggestion = self._suggestions_intent.suggestions[0]
                    findings = None

                    if re.match(Shell.LOCAL_FINDINGS_RE,
                                the_suggestion.string):
                        findings = self._client.get_local_findings(token)
                    elif re.match(Shell.REMOTE_FINDINGS_RE,
                                  the_suggestion.string):
                        findings = self._client.get_remote_findings(token)

                    if findings and len(findings) == 1:
                        finding_info = findings[0]
                        log.d(
                            f"Found single finding for token: {finding_info}")
                        self._suggestions_intent.suggestions.clear()
                        self._suggestions_intent.suggestions.append(
                            StyledString(
                                str(
                                    Path(findings.path) /
                                    finding_info.get("name"))))
                        no_suggestions = False

                # If there are no suggestions and we are doing shell passthrough
                # show the local files (probably the user command acts on those)
                if no_suggestions and get_setting(Settings.SHELL_PASSTHROUGH):
                    log.d("Showing local files as suggestions as fallback, "
                          "since shell passthrough is enabled")
                    self._suggestions_intent = Ls.suggestions(line, token, self._client) \
                                               or self._suggestions_intent

                if not self._suggestions_intent.completion:
                    # TODO: find a way for not show the the suggestion inline
                    #  probably see https://tiswww.case.edu/php/chet/readline/readline.html#SEC45
                    #  for now we add a dummy suggestion that we won't print in our
                    #  custom renderer
                    self._suggestions_intent.suggestions.append(
                        StyledString(""))

                self._suggestions_intent.suggestions = sorted(
                    self._suggestions_intent.suggestions,
                    key=lambda s: s.string.lower())

            if count < len(self._suggestions_intent.suggestions):
                sug = self._suggestions_intent.suggestions[count].string

                # Eventually escape it
                if not is_quoting:
                    sug = escape(sug)

                log.d(f"Returning suggestion {count}: {sug}")
                log.d(
                    f"Completion is enabled = {self._suggestions_intent.completion}"
                )

                # If there is only a suggestion that begins with
                # this name, complete the suggestion (and eventually insert a space)
                if self._suggestions_intent.completion and \
                        self._suggestions_intent.insert_after_completion and \
                        len(self._suggestions_intent.suggestions) == 1:

                    if is_str(
                            self._suggestions_intent.insert_after_completion):
                        insert_after = self._suggestions_intent.insert_after_completion
                    else:  # is a hook
                        insert_after = self._suggestions_intent.insert_after_completion(
                            sug)

                    if insert_after:
                        log.d(
                            "Last command with autocomplete -> adding required string"
                        )
                        if insert_after == " " and is_quoting:
                            # Insert the quote before the space
                            sug += '"'

                        sug += insert_after

                return sug

            log.d("END OF suggestions")
            return None
        except:
            log.w(
                f"Exception occurred while retrieving suggestions\n{traceback.format_exc()}"
            )
            return None
Exemple #9
0
    def _execute_single_real(self, cmd: str) -> AnyErrs:
        if not is_str(cmd):
            log.e("Invalid command")
            return ClientErrors.INVALID_COMMAND_SYNTAX

        cmd = cmd.strip()

        if len(cmd) == 0:
            log.w("Empty command, nothing to do here")
            return ClientErrors.SUCCESS  # no problem...

        log.d(f"Will try to execute '{cmd}'")
        if cmd.startswith("#"):
            log.d("Ignoring, it's a comment")
            return ClientErrors.SUCCESS

        log.d(f"Before alias resolution: {cmd}")
        # resolved_cmd_prefix, resolved_cmd_suffix = self._resolve_alias(cmd, as_string=False)
        resolved_cmd = self._resolve_alias(cmd, as_string=True)
        # log.d(f"resolved_cmd: {resolved_cmd}")
        # Resolved cmd can contain multiple command after alias resolution
        resolved_cmd_prefix, resolved_cmd_suffix = \
            Shell._split_command_prefix_suffix(resolved_cmd, keep_space=True)
        log.d(f"resolved_cmd_prefix: {resolved_cmd_prefix}")
        log.d(f"resolved_cmd_suffix: {resolved_cmd_suffix}")
        # 'command_prefix' might be partial (unique prefix of a valid command)
        commands = self._commands_for(resolved_cmd_prefix, resolve_alias=False)
        log.d(f"Commands found: {commands}")

        # No command
        if len(commands) == 0:
            if get_setting(Settings.SHELL_PASSTHROUGH):
                log.d(
                    "Passing unknown command to underlying shell due to passthrough"
                )
                return self._client.execute_command(Commands.LOCAL_SHELL, cmd)

            return ClientErrors.COMMAND_NOT_RECOGNIZED

        # More than a command for this prefix
        if len(commands) > 1 and resolved_cmd_prefix not in commands:
            print("Available commands: ")
            for comm in isorted(commands):
                print(
                    red(resolved_cmd_prefix) + comm[len(resolved_cmd_prefix):])
            return ClientErrors.SUCCESS

        if len(commands) == 1:
            # Just 1 command found
            command = commands[0]
        else:
            # More than a command, but one matches exactly
            command = resolved_cmd_prefix

        # Exactly a known command, execute it
        try:
            outcome = ClientErrors.COMMAND_NOT_RECOGNIZED

            if self.has_command(command):
                outcome = self._execute_shell_command(command,
                                                      resolved_cmd_suffix)
            elif self._client.has_command(command):
                outcome = self._client.execute_command(command,
                                                       resolved_cmd_suffix)

            log.d(f"Command outcome: {outcome}")

            return outcome
        except ConnectionError:
            log.eexception("Connection error occurred")
            print_errors(ClientErrors.CONNECTION_ERROR)
            self._client.destroy_connection()
        except EOFError:
            log.i("\nCTRL+D: exiting")
            self._client.destroy_connection()
            # for consistency with CTRL+D typed while reading command, exit
            exit(0)
        except KeyboardInterrupt:
            log.d("\nCTRL+C")