Пример #1
0
    async def jsk_curl(self, ctx: commands.Context, url: str):
        """
        Download and display a text file from the internet.

        This command is similar to jsk cat, but accepts a URL.
        """

        # remove embed maskers if present
        url = url.lstrip("<").rstrip(">")

        async with ReplResponseReactor(ctx.message):
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    data = await response.read()
                    hints = (
                        response.content_type,
                        url
                    )
                    code = response.status

            if not data:
                return await ctx.send(f"HTTP response was empty (status code {code}).")

            try:
                paginator = WrappedFilePaginator(io.BytesIO(data), language_hints=hints, max_size=1985)
            except UnicodeDecodeError:
                return await ctx.send(f"Couldn't determine the encoding of the response. (status code {code})")
            except ValueError as exc:
                return await ctx.send(f"Couldn't read response (status code {code}), {exc}")

            interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
            await interface.send_to(ctx)
Пример #2
0
    async def jsk_disassemble(self, ctx: commands.Context, *, argument: codeblock_converter):
        """
        Disassemble Python code into bytecode.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)

        async with ReplResponseReactor(ctx.message):
            text = "\n".join(disassemble(argument.content, arg_dict=arg_dict))

            # Guild's advertised limit minus 1KiB for the HTTP content
            filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024

            if len(text) < filesize_threshold:
                await ctx.send(file=discord.File(
                    filename="dis.py",
                    fp=io.BytesIO(text.encode('utf-8'))
                ))
            else:
                paginator = WrappedPaginator(prefix='```py', max_size=1985)

                paginator.add_line(text)

                interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
                await interface.send_to(ctx)
Пример #3
0
    async def git(self, ctx: commands.Context, pull_push, *, commit_msg=None):
        """
        Executes git statements in the system shell.

        This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise.
        Execution can be cancelled by closing the paginator.
        """
        if pull_push == "push":
            shellcmd = f'sudo git add .&&sudo git commit -m "{commit_msg}"&&sudo git push'
        if pull_push == "pull":
            shellcmd = 'sudo git pull'
        if pull_push not in ['pull', 'push']: 
            return await ctx.send("Invalid option given")

        async with ReplResponseReactor(ctx.message):
            paginator = WrappedPaginator(prefix="```sh", max_size=1985)
            paginator.add_line(f"$ git {pull_push}\n")

            interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
            self.bot.loop.create_task(interface.send_to(ctx))

            if commit_msg is None:
                commit_msg = "File changes"

            with ShellReader(shellcmd) as reader:
                async for line in reader:
                    if interface.closed:
                        return
                    await interface.add_line(line)
Пример #4
0
    async def jsk_python(self, ctx: commands.Context, *, argument: codeblock_converter):
        """
        Direct evaluation of Python code.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(
                        argument.content, scope, arg_dict=arg_dict
                    )
                    async for send, result in AsyncSender(executor):
                        if result is None:
                            continue

                        self.last_result = result

                        if isinstance(result, discord.File):
                            send(await ctx.send(file=result))
                        elif isinstance(result, discord.Embed):
                            send(await ctx.send(embed=result))
                        elif isinstance(result, PaginatorInterface):
                            send(await result.send_to(ctx))
                        else:
                            if not isinstance(result, str):
                                # repr all non-strings
                                result = repr(result)

                            if len(result) > 2000:
                                # inconsistency here, results get wrapped in codeblocks when they are too large
                                #  but don't if they're not. probably not that bad, but noting for later review
                                paginator = WrappedPaginator(
                                    prefix="```py", suffix="```", max_size=1985
                                )

                                paginator.add_line(result)

                                interface = PaginatorInterface(
                                    ctx.bot, paginator, owner=ctx.author
                                )
                                send(await interface.send_to(ctx))
                            else:
                                if result.strip() == "":
                                    result = "\u200b"

                                send(
                                    await ctx.send(
                                        result.replace(
                                            self.bot.http.token,
                                            "[token omitted]",
                                        )
                                    )
                                )
        finally:
            scope.clear_intersection(arg_dict)
Пример #5
0
    async def git(self, ctx, pull_push, *, message=None):
        """
        Executes git statements in the system shell.
        This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise.
        Execution can be cancelled by closing the paginator.
        """
        message = message if message is not None else "Updated files."

        if pull_push == "push":
            shellcmd = f'sudo git add .&&sudo git commit -m "{message}"&&sudo git push'
        elif pull_push == "pull":
            shellcmd = 'sudo git pull'
        else:
            return await ctx.send("Invalid option given")

        async with ReplResponseReactor(ctx.message):
            paginator = WrappedPaginator(prefix="```sh", max_size=1985)
            paginator.add_line(f"$ git {pull_push}\n")

            interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
            self.bot.loop.create_task(interface.send_to(ctx))

            with ShellReader(shellcmd) as reader:
                async for line in reader:
                    if interface.closed:
                        return
                    await interface.add_line(line)
Пример #6
0
    async def jsk_shell(self, ctx: commands.Context, *,
                        argument: codeblock_converter):
        """
        Executes statements in the system shell.

        This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise.
        Execution can be cancelled by closing the paginator.
        """

        async with ReplResponseReactor(ctx.message):
            with self.submit(ctx):
                with ShellReader(argument.content) as reader:
                    prefix = "```" + reader.highlight

                    paginator = WrappedPaginator(prefix=prefix, max_size=1975)
                    paginator.add_line(f"{reader.ps1} {argument.content}\n")

                    interface = PaginatorInterface(ctx.bot,
                                                   paginator,
                                                   owner=ctx.author)
                    self.bot.loop.create_task(interface.send_to(ctx))

                    async for line in reader:
                        if interface.closed:
                            return
                        await interface.add_line(line)

                await interface.add_line(
                    f"\n[status] Return code {reader.close_code}")
Пример #7
0
    async def jsk_python(self, ctx: commands.Context, *,
                         argument: codeblock_converter):
        """
        Direct evaluation of Python code.
        """

        arg_dict = get_var_dict_from_ctx(ctx, Flags.SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content,
                                                 scope,
                                                 arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        if result is None:
                            continue

                        self.last_result = result

                        send(await
                             self.jsk_python_result_handling(ctx, result))

        finally:
            scope.clear_intersection(arg_dict)
Пример #8
0
    async def jsk_python_inspect(self, ctx: commands.Context, *, argument: codeblock_converter):
        """
        Evaluation of Python code with inspect information.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        self.last_result = result

                        header = repr(result).replace("``", "`\u200b`").replace(self.bot.http.token, "[token omitted]")

                        if len(header) > 485:
                            header = header[0:482] + "..."

                        paginator = WrappedPaginator(prefix=f"```prolog\n=== {header} ===\n", max_size=1985)

                        for name, res in all_inspections(result):
                            paginator.add_line(f"{name:16.16} :: {res}")

                        interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
                        send(await interface.send_to(ctx))
        finally:
            scope.clear_intersection(arg_dict)
Пример #9
0
    async def jsk_python_inspect(self, ctx: commands.Context, *,
                                 argument: codeblock_converter):
        """
        Evaluation of Python code with inspect information.
        """

        arg_dict = get_var_dict_from_ctx(ctx, Flags.SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content,
                                                 scope,
                                                 arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        self.last_result = result

                        header = repr(result).replace("``",
                                                      "`\u200b`").replace(
                                                          self.bot.http.token,
                                                          "[token omitted]")

                        if len(header) > 485:
                            header = header[0:482] + "..."

                        lines = [f"=== {header} ===", ""]

                        for name, res in all_inspections(result):
                            lines.append(f"{name:16.16} :: {res}")

                        docstring = (inspect.getdoc(result) or '').strip()

                        if docstring:
                            lines.append(f"\n=== Help ===\n\n{docstring}")

                        text = "\n".join(lines)

                        if use_file_check(ctx, len(
                                text)):  # File "full content" preview limit
                            send(await ctx.send(file=discord.File(
                                filename="inspection.prolog",
                                fp=io.BytesIO(text.encode('utf-8')))))
                        else:
                            paginator = WrappedPaginator(prefix="```prolog",
                                                         max_size=1985)

                            paginator.add_line(text)

                            interface = PaginatorInterface(ctx.bot,
                                                           paginator,
                                                           owner=ctx.author)
                            send(await interface.send_to(ctx))
        finally:
            scope.clear_intersection(arg_dict)
Пример #10
0
    async def jsk_curl(self, ctx: commands.Context, url: str):
        """
        Download and display a text file from the internet.

        This command is similar to jsk cat, but accepts a URL.
        """

        # remove embed maskers if present
        url = url.lstrip("<").rstrip(">")

        async with ReplResponseReactor(ctx.message):
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as response:
                    data = await response.read()
                    hints = (response.content_type, url)
                    code = response.status

            if not data:
                return await ctx.send(
                    f"HTTP response was empty (status code {code}).")

            # Guild's advertised limit minus 1KiB for the HTTP content
            filesize_threshold = (ctx.guild.filesize_limit
                                  if ctx.guild else 8 * 1024 * 1024) - 1024

            if len(data) < filesize_threshold:
                # Shallow language detection
                language = None

                for hint in hints:
                    language = get_language(hint)

                    if language:
                        break

                await ctx.send(
                    file=discord.File(filename=f"response.{language or 'txt'}",
                                      fp=io.BytesIO(data)))
            else:
                try:
                    paginator = WrappedFilePaginator(io.BytesIO(data),
                                                     language_hints=hints,
                                                     max_size=1985)
                except UnicodeDecodeError:
                    return await ctx.send(
                        f"Couldn't determine the encoding of the response. (status code {code})"
                    )
                except ValueError as exc:
                    return await ctx.send(
                        f"Couldn't read response (status code {code}), {exc}")

                interface = PaginatorInterface(ctx.bot,
                                               paginator,
                                               owner=ctx.author)
                await interface.send_to(ctx)
Пример #11
0
    async def jsk_ast(self, ctx: commands.Context, *,
                      argument: codeblock_converter):
        """
        Disassemble Python code into AST.
        """

        async with ReplResponseReactor(ctx.message):
            text = create_tree(argument.content, use_ansi=Flags.use_ansi(ctx))

            await ctx.send(file=discord.File(
                filename="ast.ansi", fp=io.BytesIO(text.encode('utf-8'))))
Пример #12
0
    async def jsk_python(self, ctx: SubContext, *,
                         argument: codeblock_converter):
        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content,
                                                 scope,
                                                 arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        if result is None:
                            continue

                        self.last_result = result

                        if isinstance(result, discord.File):
                            send(await ctx.send(file=result))
                        elif isinstance(result, discord.Embed):
                            send(await ctx.send(embed=result))
                        elif isinstance(result, PaginatorInterface):
                            send(await result.send_to(ctx))
                        elif isinstance(result, DCMenuPages):
                            send(await result.start(ctx))
                        else:
                            if not isinstance(result, str):
                                # repr all non-strings
                                result = repr(result)

                            result = result.replace(self.bot.http.token,
                                                    "[token omitted]")
                            if result.strip() == "":
                                result = "[empty string]"

                            if len(result) > 2000:
                                paginator = PartitionPaginator(prefix="```py")

                                paginator.add_line(result)

                                source = NormalPageSource(paginator.pages)

                                menu = DCMenuPages(source)

                                send(await menu.start(ctx))

                            else:
                                send(await ctx.send(f"```py\n{result}```"))

        finally:
            scope.clear_intersection(arg_dict)
Пример #13
0
    async def jsk_disassemble(self, ctx: commands.Context, *, argument: codeblock_converter):
        """
        Disassemble Python code into bytecode.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)

        async with ReplResponseReactor(ctx.message):
            paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985)

            for line in disassemble(argument.content, arg_dict=arg_dict):
                paginator.add_line(line)

            interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
            await interface.send_to(ctx)
Пример #14
0
    async def jsk_python_inspect(self, ctx: commands.Context, *, argument: codeblock_converter):  # pylint: disable=too-many-locals
        """
        Evaluation of Python code with inspect information.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        self.last_result = result

                        header = repr(result).replace("``", "`\u200b`").replace(self.bot.http.token, "[token omitted]")

                        if len(header) > 485:
                            header = header[0:482] + "..."

                        lines = [f"=== {header} ===", ""]

                        for name, res in all_inspections(result):
                            lines.append(f"{name:16.16} :: {res}")

                        text = "\n".join(lines)

                        # Guild's advertised limit minus 1KiB for the HTTP content
                        filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024

                        if len(text) < filesize_threshold:
                            send(await ctx.send(file=discord.File(
                                filename="inspection.prolog",
                                fp=io.BytesIO(text.encode('utf-8'))
                            )))
                        else:
                            paginator = WrappedPaginator(prefix="```prolog", max_size=1985)

                            paginator.add_line(text)

                            interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
                            send(await interface.send_to(ctx))
        finally:
            scope.clear_intersection(arg_dict)
Пример #15
0
    async def jsk_debug(self, ctx: commands.Context, *, command_string: str):
        """
        Run a command timing execution and catching exceptions.
        """

        alt_ctx = await copy_context_with(ctx, content=ctx.prefix + command_string)

        if alt_ctx.command is None:
            return await ctx.send(f'Command "{alt_ctx.invoked_with}" is not found')

        start = time.perf_counter()

        async with ReplResponseReactor(ctx.message):
            with self.submit(ctx):
                await alt_ctx.command.invoke(alt_ctx)

        end = time.perf_counter()
        return await ctx.send(f"Command `{alt_ctx.command.qualified_name}` finished in {end - start:.3f}s.")
Пример #16
0
    async def speedtest(self, ctx):
        async with ReplResponseReactor(ctx.message):
            with ShellReader("speedtest-cli") as reader:
                prefix = "```" + reader.highlight

                paginator = WrappedPaginator(prefix=prefix, max_size=1975)
                paginator.add_line(f"{reader.ps1} 'speedtest-cli'\n")

                interface = PaginatorInterface(ctx.bot,
                                               paginator,
                                               owner=ctx.author)
                self.bot.loop.create_task(interface.send_to(ctx))

                async for line in reader:
                    if interface.closed:
                        return
                    await interface.add_line(line)

            await interface.add_line(
                f"\n[status] Return code {reader.close_code}")
Пример #17
0
    async def jsk_python(self, ctx: commands.Context, *, argument: CodeblockConverter):
        """
        Direct evaluation of Python code.
        """

        arg_dict = get_var_dict_from_ctx(ctx)

        scope = self.scope

        scope.clean()
        arg_dict["_"] = self.last_result

        async with ReplResponseReactor(ctx.message):
            with self.submit(ctx):
                async for result in AsyncCodeExecutor(
                    argument.content, scope, arg_dict=arg_dict
                ):
                    if result is None:
                        continue

                    self.last_result = result

                    if isinstance(result, discord.File):
                        await ctx.send(file=result)
                    elif isinstance(result, discord.Embed):
                        await ctx.send(embed=result)
                    else:
                        if not isinstance(result, str):
                            # repr all non-strings
                            result = repr(result)

                        if len(result) > 2000:
                            result = result[0:1997] + "..."
                        elif result.strip() == "":
                            result = "\u200b"

                        await ctx.send(
                            result.replace(self.bot.http.token, "[token omitted]")
                        )
Пример #18
0
    async def jsk_disassemble(self, ctx: commands.Context, *,
                              argument: codeblock_converter):
        """
        Disassemble Python code into bytecode.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)

        async with ReplResponseReactor(ctx.message):
            text = "\n".join(disassemble(argument.content, arg_dict=arg_dict))

            if len(text) < 50_000:  # File "full content" preview limit
                await ctx.send(file=discord.File(
                    filename="dis.py", fp=io.BytesIO(text.encode('utf-8'))))
            else:
                paginator = WrappedPaginator(prefix='```py', max_size=1985)

                paginator.add_line(text)

                interface = PaginatorInterface(ctx.bot,
                                               paginator,
                                               owner=ctx.author)
                await interface.send_to(ctx)
Пример #19
0
    async def _dev_python(self, ctx, *, code: codeblock_converter):
        '''
        Evaluate python code
        '''
        arg_dict = get_var_dict_from_ctx(ctx, "")
        arg_dict["_"] = self.last_result

        scope = self._scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(code.content,
                                                 scope,
                                                 arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        if result is None:
                            continue

                        self.last_result = result

                        if isinstance(result, discord.File):
                            send(await ctx.reply(file=result))
                        elif isinstance(result, discord.Embed):
                            send(await ctx.reply(embed=result))
                        elif isinstance(result, PaginatorInterface):
                            send(await result.send_to(ctx))
                        else:
                            if not isinstance(result, str):
                                result = repr(result)

                            if len(result) > 2000:
                                result = result.replace("`", "`\u200b")
                                width = 2000
                                pages = [
                                    result[i:i + width]
                                    for i in range(0, len(result), width)
                                ]

                                for page in pages:
                                    embed = discord.Embed(
                                        description=f"```py\n{page}```",
                                        colour=discord.Colour.teal())
                                    pages[pages.index(page)] = embed

                                embedpaginator = paginator(
                                    ctx, remove_reactions=True)
                                embedpaginator.add_reaction(
                                    "\U000023ea", "first")
                                embedpaginator.add_reaction(
                                    "\U000025c0", "back")
                                embedpaginator.add_reaction(
                                    "\U0001f5d1", "delete")
                                embedpaginator.add_reaction(
                                    "\U000025b6", "next")
                                embedpaginator.add_reaction(
                                    "\U000023e9", "last")
                                send(await embedpaginator.send(pages))

                            else:
                                if result.strip() == '':
                                    result = "\u200b"

                                embed = discord.Embed(
                                    description=
                                    f"```py\n{result.replace(self.bot.http.token, '[token]')}```",
                                    colour=discord.Colour.teal())

                                send(await ctx.reply(embed=embed,
                                                     mention_author=False))
        finally:
            scope.clear_intersection(arg_dict)
Пример #20
0
    async def jsk_python(self, ctx: commands.Context, *, argument: codeblock_converter):
        """
        Direct evaluation of Python code.
        """

        arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX)
        arg_dict["_"] = self.last_result

        scope = self.scope

        try:
            async with ReplResponseReactor(ctx.message):
                with self.submit(ctx):
                    executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict)
                    async for send, result in AsyncSender(executor):
                        if result is None:
                            continue

                        self.last_result = result

                        if isinstance(result, discord.File):
                            send(await ctx.send(file=result))
                        elif isinstance(result, discord.Embed):
                            send(await ctx.send(embed=result))
                        elif isinstance(result, PaginatorInterface):
                            send(await result.send_to(ctx))
                        else:
                            if not isinstance(result, str):
                                # repr all non-strings
                                result = repr(result)

                            # Guild's advertised limit minus 1KiB for the HTTP content
                            filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024

                            if len(result) <= 2000:
                                if result.strip() == '':
                                    result = "\u200b"

                                send(await ctx.send(result.replace(self.bot.http.token, "[token omitted]")))

                            elif len(result) < filesize_threshold:
                                # Discord's desktop and web client now supports an interactive file content
                                #  display for files encoded in UTF-8.
                                # Since this avoids escape issues and is more intuitive than pagination for
                                #  long results, it will now be prioritized over PaginatorInterface if the
                                #  resultant content is below the filesize threshold
                                send(await ctx.send(file=discord.File(
                                    filename="output.py",
                                    fp=io.BytesIO(result.encode('utf-8'))
                                )))

                            else:
                                # inconsistency here, results get wrapped in codeblocks when they are too large
                                #  but don't if they're not. probably not that bad, but noting for later review
                                paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985)

                                paginator.add_line(result)

                                interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
                                send(await interface.send_to(ctx))

        finally:
            scope.clear_intersection(arg_dict)