11from __future__ import annotations
22
3- import asyncio
4- import importlib
5- import os
6- import re
7- import subprocess # nosec # We already know this is dangerous, but it's needed
8- import sys
93from typing import TYPE_CHECKING , Literal , Optional
104
115import discord
126from discord .ext import commands
137from discord .ext .commands import Greedy
148
159if TYPE_CHECKING :
16- from libs . utils import RoboContext
10+ from utils . context import RoboContext
1711
1812 from bot .rodhaj import Rodhaj
1913
20- GIT_PULL_REGEX = re .compile (r"\s+(?P<filename>.*)\b\s+\|\s+[\d]" )
21-
2214
2315class Admin (commands .Cog , command_attrs = dict (hidden = True )):
2416 """Administrative commands for Rodhaj"""
@@ -33,78 +25,6 @@ def display_emoji(self) -> discord.PartialEmoji:
3325 async def cog_check (self , ctx : RoboContext ) -> bool :
3426 return await self .bot .is_owner (ctx .author )
3527
36- async def reload_or_load_extension (self , module : str ) -> None :
37- try :
38- await self .bot .reload_extension (module )
39- except commands .ExtensionNotLoaded :
40- await self .bot .load_extension (module )
41-
42- def find_modules_from_git (self , output : str ) -> list [tuple [int , str ]]:
43- files = GIT_PULL_REGEX .findall (output )
44- ret : list [tuple [int , str ]] = []
45- for file in files :
46- root , ext = os .path .splitext (file )
47- if ext != ".py" or root .endswith ("__init__" ):
48- continue
49-
50- true_root = "." .join (root .split ("/" )[1 :])
51-
52- if true_root .startswith ("cogs" ) or true_root .startswith ("libs" ):
53- # A subdirectory within these are a part of the codebase
54-
55- ret .append ((true_root .count ("." ) + 1 , true_root ))
56-
57- # For reload order, the submodules should be reloaded first
58- ret .sort (reverse = True )
59- return ret
60-
61- async def run_process (self , command : str ) -> list [str ]:
62- process = await asyncio .create_subprocess_shell (
63- command , stdout = subprocess .PIPE , stderr = subprocess .PIPE
64- )
65- result = await process .communicate ()
66-
67- return [output .decode () for output in result ]
68-
69- def tick (self , opt : Optional [bool ], label : Optional [str ] = None ) -> str :
70- lookup = {
71- True : "\U00002705 " ,
72- False : "\U0000274c " ,
73- None : "\U000023e9 " ,
74- }
75- emoji = lookup .get (opt , "\U0000274c " )
76- if label is not None :
77- return f"{ emoji } : { label } "
78- return emoji
79-
80- def format_results (self , statuses : list ) -> str :
81- desc = "\U00002705 - Successful reload | \U0000274c - Failed reload | \U000023e9 - Skipped\n \n "
82- status = "\n " .join (f"- { status } : `{ module } `" for status , module in statuses )
83- desc += status
84- return desc
85-
86- async def reload_exts (self , module : str ) -> list [tuple [str , str ]]:
87- statuses = []
88- try :
89- await self .reload_or_load_extension (module )
90- statuses .append ((self .tick (True ), module ))
91- except commands .ExtensionError :
92- statuses .append ((self .tick (False ), module ))
93-
94- return statuses
95-
96- def reload_lib_modules (self , module : str ) -> list [tuple [str , str ]]:
97- statuses = []
98- try :
99- actual_module = sys .modules [module ]
100- importlib .reload (actual_module )
101- statuses .append ((self .tick (True ), module ))
102- except KeyError :
103- statuses .append ((self .tick (None ), module ))
104- except Exception :
105- statuses .append ((self .tick (False ), module ))
106- return statuses
107-
10828 # Umbra's sync command
10929 # To learn more about it, see the link below (and ?tag ass on the dpy server):
11030 # https://about.abstractumbra.dev/discord.py/2023/01/29/sync-command-example.html
@@ -147,43 +67,6 @@ async def sync(
14767
14868 await ctx .send (f"Synced the tree to { ret } /{ len (guilds )} ." )
14969
150- @commands .command (name = "reload-all" , hidden = True )
151- async def reload (self , ctx : RoboContext ) -> None :
152- """Reloads all cogs and utils"""
153- async with ctx .typing ():
154- stdout , _ = await self .run_process ("git pull" )
155-
156- # progress and stuff is redirected to stderr in git pull
157- # however, things like "fast forward" and files
158- # along with the text "already up-to-date" are in stdout
159-
160- if stdout .startswith ("Already up-to-date." ):
161- await ctx .send (stdout )
162- return
163-
164- modules = self .find_modules_from_git (stdout )
165-
166- mods_text = "\n " .join (
167- f"{ index } . `{ module } `" for index , (_ , module ) in enumerate (modules , start = 1 )
168- )
169- prompt_text = (
170- f"This will update the following modules, are you sure?\n { mods_text } "
171- )
172-
173- confirm = await ctx .prompt (prompt_text )
174- if not confirm :
175- await ctx .send ("Aborting...." )
176- return
177-
178- statuses = []
179- for is_submodule , module in modules :
180- if is_submodule :
181- statuses = self .reload_lib_modules (module )
182- else :
183- statuses = await self .reload_exts (module )
184-
185- await ctx .send (self .format_results (statuses ))
186-
18770
18871async def setup (bot : Rodhaj ) -> None :
18972 await bot .add_cog (Admin (bot ))
0 commit comments