async def internal(self): return_data = [] with ShellReader("echo hi") as reader: async for result in reader: return_data.append(result) self.assertEqual(len(return_data), 1) self.assertEqual(return_data[0], "hi") # Linux-only tests if not WINDOWS: return_data = [] with ShellReader(">&2 echo oops") as reader: async for result in reader: return_data.append(result) self.assertEqual(len(return_data), 1) self.assertEqual(return_data[0], "[stderr] oops") return_data = [] with ShellReader("echo one && echo two") as reader: async for result in reader: return_data.append(result) self.assertEqual(len(return_data), 2) self.assertEqual(return_data[0], "one") self.assertEqual(return_data[1], "two") # Windows-only tests if WINDOWS: return_data = [] with ShellReader("cmd /c \"echo one && echo two\"") as reader: async for result in reader: return_data.append(result) self.assertEqual(len(return_data), 2) self.assertEqual(return_data[0].strip(), "one") self.assertEqual(return_data[1].strip(), "two") hit_exception = False try: with ShellReader("sleep 10", timeout=5) as reader: async for result in reader: pass except asyncio.TimeoutError: hit_exception = True self.assertTrue(hit_exception)
async def test_reader_basic(): return_data = [] with ShellReader("echo hi") as reader: async for result in reader: return_data.append(result) assert len(return_data) == 1 assert return_data[0] == "hi" with pytest.raises(asyncio.TimeoutError): with ShellReader("sleep 2", timeout=1) as reader: async for result in reader: pass
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}")
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)
async def update(self, ctx, *, version: str = None): """Updates the module to the latest (or provided) version.""" proc = psutil.Process() with proc.oneshot(): command = proc.name() if not command.lower().startswith("py"): return await ctx.send( f"Unable to automatically update: process name does not start with `py`," f" so unable to invoke pip.") else: run = command.lower() + " -m pip install guildmanager-v2" + ( " --upgrade" if not version else f"=={version}") paginator = PaginatorEmbedInterface( self.bot, commands.Paginator("```bash", "```", 1600)) async with ctx.channel.typing(): with ShellReader(run, 120) as reader: async for line in reader: if paginator.closed: return else: await paginator.add_line(line) await paginator.add_line( f"[status] return code {reader.close_code}") return await paginator.send_to(ctx.channel)
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)
async def neofetch(self, ctx): l = [] with ShellReader("neofetch --logo") as read: async for line in read: l.append(line) l.pop() mstr = ("\n".join(l)).rstrip() mstr = mstr.rstrip() mstrb = "\n" with ShellReader("neofetch --stdout") as read: async for line in read: mstrb += (line + "\n") mstrb += "\n" embed = discord.Embed(title="Neofetch") embed.description = f"```shell\n{mstr}\n```\n\n```shell\n{mstrb}\n```" return await ctx.send(embed=embed)
async def test_linux(): return_data = [] with ShellReader(">&2 echo oops") as reader: async for result in reader: return_data.append(result) assert len(return_data) == 1 assert return_data[0] == "[stderr] oops" return_data = [] with ShellReader("echo one && echo two") as reader: async for result in reader: return_data.append(result) assert len(return_data) == 2 assert return_data[0] == "one" assert return_data[1] == "two"
async def test_windows(): return_data = [] with ShellReader("cmd /c \"echo one && echo two\"") as reader: async for result in reader: return_data.append(result) assert len(return_data) == 2 assert return_data[0].strip() == "one" assert return_data[1].strip() == "two"
async def internal(self): return_data_1 = [] with ShellReader("echo hi") as reader: async for result in reader: return_data_1.append(result) self.assertEqual(len(return_data_1), 1) self.assertEqual(return_data_1[0], "hi") return_data_2 = [] with ShellReader(">&2 echo oops") as reader: async for result in reader: return_data_2.append(result) self.assertEqual(len(return_data_2), 1) self.assertEqual(return_data_2[0], "[stderr] oops") return_data_3 = [] with ShellReader("echo one; echo two") as reader: async for result in reader: return_data_3.append(result) self.assertEqual(len(return_data_3), 2) self.assertEqual(return_data_3[0], "one") self.assertEqual(return_data_3[1], "two") hit_exception = False try: with ShellReader("echo one; sleep 10; echo two", timeout=5) as reader: async for result in reader: pass except asyncio.TimeoutError: hit_exception = True self.assertTrue(hit_exception)
async def test_windows(): return_data = [] with ShellReader( "cmd /c \"echo one && echo two && echo three 1>&2\"") as reader: async for result in reader: return_data.append(result) assert len(return_data) == 3 return_data = [x.strip() for x in return_data] assert "one" in return_data assert "two" in return_data assert "[stderr] three" in return_data
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}")
async def _pyright(self, ctx: Context, *, codeblock: codeblock_converter) -> None: """ Evaluates Python code through the latest (installed) version of Pyright on my system. """ code = codeblock.content pyright_dump = pathlib.Path("./_pyright/") if not pyright_dump.exists(): pyright_dump.mkdir(mode=0o0755, parents=True, exist_ok=True) conf = pyright_dump / "pyrightconfig.json" conf.touch() with open(conf, "w") as f: f.write( json.dumps({ "pythonVersion": "3.9", "typeCheckingMode": "basic", "useLibraryCodeForTypes": False, "reportMissingImports": True, })) await ctx.trigger_typing() rand = os.urandom(16).hex() with_file = pyright_dump / f"{rand}_tmp_pyright.py" with_file.touch(mode=0o0777, exist_ok=True) with open(with_file, "w") as f: f.write(code) output: str = "" with ShellReader( f"cd _pyright && pyright --outputjson {with_file.name}" ) as reader: async for line in reader: if not line.startswith("[stderr] "): output += line with_file.unlink(missing_ok=True) counts = {"error": 0, "warn": 0, "info": 0} data = json.loads(output) diagnostics = [] for diagnostic in data["generalDiagnostics"]: start = diagnostic["range"]["start"] start = f"{start['line']}:{start['character']}" severity = diagnostic["severity"] if severity != "error": severity = severity[:4] counts[severity] += 1 prefix = " " if severity == "info" else "-" message = diagnostic["message"].replace("\n", f"\n{prefix} ") diagnostics.append(f"{prefix} {start} - {severity}: {message}") version = data["version"] diagnostics = "\n".join(diagnostics) totals = ", ".join(f"{count} {name}" for name, count in counts.items()) fmt = to_codeblock( f"Pyright v{version}:\n\n{diagnostics}\n\n{totals}\n", language="diff", escape_md=False) await ctx.send(fmt)