@@ -41,16 +41,15 @@ def __init__(self, bot):
4141 self .registry = {}
4242 self .bot .loop .create_task (self .download_initial_plugins ())
4343 self .bot .loop .create_task (self .populate_registry ())
44-
44+
4545 async def populate_registry (self ):
4646 url = 'https://raw.githubusercontent.com/kyb3r/modmail/master/plugins/registry.json'
4747 async with self .bot .session .get (url ) as resp :
4848 self .registry = json .loads (await resp .text ())
4949
5050 @staticmethod
5151 def _asubprocess_run (cmd ):
52- return subprocess .run (cmd , shell = True , check = True ,
53- capture_output = True )
52+ return subprocess .run (cmd , shell = True , check = True , capture_output = True )
5453
5554 @staticmethod
5655 def parse_plugin (name ):
@@ -60,10 +59,12 @@ def parse_plugin(name):
6059 result [2 ] = '/' .join (result [2 :])
6160 except IndexError :
6261 return None
62+
6363 return tuple (result )
6464
6565 async def download_initial_plugins (self ):
6666 await self .bot ._connected .wait ()
67+
6768 for i in self .bot .config .plugins :
6869 parsed_plugin = self .parse_plugin (i )
6970
@@ -78,29 +79,29 @@ async def download_initial_plugins(self):
7879 except DownloadError as exc :
7980 msg = f'{ parsed_plugin [0 ]} /{ parsed_plugin [1 ]} - { exc } '
8081 logger .error (error (msg ))
82+
8183 await async_all (env () for env in self .bot .extra_events .get ('on_plugin_ready' , []))
84+
8285 logger .debug (info ('on_plugin_ready called.' ))
8386
8487 async def download_plugin_repo (self , username , repo ):
8588 try :
8689 cmd = f'git clone https://github.com/{ username } /{ repo } '
8790 cmd += f'plugins/{ username } -{ repo } -q'
88- await self .bot .loop .run_in_executor (
89- None ,
90- self ._asubprocess_run ,
91- cmd
92- )
91+
92+ await self .bot .loop .run_in_executor (None , self ._asubprocess_run , cmd )
9393 # -q (quiet) so there's no terminal output unless there's an error
9494 except subprocess .CalledProcessError as exc :
9595 err = exc .stderr .decode ('utf-8' ).strip ()
96- if not err . endswith ( 'already exists and is '
97- ' not an empty directory.' ):
96+
97+ if not err . endswith ( 'already exists and is not an empty directory.' ):
9898 # don't raise error if the plugin folder exists
9999 raise DownloadError (error ) from exc
100100
101101 async def load_plugin (self , username , repo , plugin_name ):
102102 ext = f'plugins.{ username } -{ repo } .{ plugin_name } .{ plugin_name } '
103103 dirname = f'plugins/{ username } -{ repo } /{ plugin_name } '
104+
104105 if 'requirements.txt' in os .listdir (dirname ):
105106 # Install PIP requirements
106107 try :
@@ -113,6 +114,7 @@ async def load_plugin(self, username, repo, plugin_name):
113114 # so there's no terminal output unless there's an error
114115 except subprocess .CalledProcessError as exc :
115116 err = exc .stderr .decode ('utf8' ).strip ()
117+
116118 if err :
117119 raise DownloadError (
118120 f'Unable to download requirements: ```\n { error } \n ```'
@@ -135,68 +137,105 @@ async def load_plugin(self, username, repo, plugin_name):
135137 @checks .has_permissions (PermissionLevel .OWNER )
136138 async def plugin (self , ctx ):
137139 """Plugin handler. Controls the plugins in the bot."""
140+
138141 await ctx .send_help (ctx .command )
139142
140143 @plugin .command (name = 'add' , aliases = ['install' ])
141144 @checks .has_permissions (PermissionLevel .OWNER )
142145 async def plugin_add (self , ctx , * , plugin_name : str ):
143146 """Add a plugin."""
147+
144148 if plugin_name in self .registry :
145149 info = self .registry [plugin_name ]
146150 plugin_name = info ['repository' ] + '/' + plugin_name
147151 required_version = info ['bot_version' ]
152+
148153 if parse_version (self .bot .version ) < parse_version (required_version ):
149- return await ctx .send (f"Bot version too low, plugin requires version `{ required_version } `" )
154+ em = discord .Embed (
155+ description = f'Your bot\' s version is too low. This plugin requires version `{ required_version } `.' ,
156+ color = self .bot .main_color
157+ )
158+ return await ctx .send (embed = em )
159+
150160 if plugin_name in self .bot .config .plugins :
151- return await ctx .send ('Plugin already installed.' )
161+ em = discord .Embed (
162+ description = 'This plugin is already installed.' ,
163+ color = self .bot .main_color
164+ )
165+ return await ctx .send (embed = em )
166+
152167 if plugin_name in self .bot .cogs .keys ():
153168 # another class with the same name
154- return await ctx .send ('Another cog exists with the same name.' )
169+ em = discord .Embed (
170+ description = 'There\' s another cog installed with the same name.' ,
171+ color = self .bot .main_color
172+ )
173+ return await ctx .send (embed = em )
174+
175+ em = discord .Embed (
176+ description = 'Downloading this plugin...' ,
177+ color = self .bot .main_color
178+ )
179+ message = await ctx .send (embed = em )
155180
156- message = await ctx .send ('Downloading plugin...' )
157181 async with ctx .typing ():
158182 if len (plugin_name .split ('/' )) >= 3 :
159183 parsed_plugin = self .parse_plugin (plugin_name )
160184
161185 try :
162186 await self .download_plugin_repo (* parsed_plugin [:- 1 ])
163187 except DownloadError as exc :
164- return await ctx .send (
165- f'Unable to fetch plugin from Github: { exc } .'
188+ em = discord .Embed (
189+ description = f'Unable to fetch this plugin from Github: { exc } .' ,
190+ color = self .bot .main_color
166191 )
192+ return await ctx .send (embed = em )
167193
168194 importlib .invalidate_caches ()
195+
169196 try :
170197 await self .load_plugin (* parsed_plugin )
171198 except DownloadError as exc :
172- return await ctx .send (f'Unable to load plugin: `{ exc } `.' )
199+ em = discord .Embed (
200+ description = f'Unable to load this plugin: { exc } .' ,
201+ color = self .bot .main_color
202+ )
203+ return await ctx .send (embed = em )
173204
174205 # if it makes it here, it has passed all checks and should
175206 # be entered into the config
176207
177208 self .bot .config .plugins .append (plugin_name )
178209 await self .bot .config .update ()
179210
180- await message .edit (content = 'Plugin installed. Any plugin that '
181- 'you install is of your OWN RISK.' )
211+ em = discord .Embed (
212+ description = 'The plugin is installed.\n '
213+ '*Please note: any plugin that you install is of your OWN RISK*' ,
214+ color = self .bot .main_color
215+ )
216+ await message .edit (embed = em )
182217 else :
183- await message .edit (content = 'Invalid plugin name format. '
184- 'Use username/repo/plugin.' )
218+ em = discord .Embed (
219+ description = 'Invalid plugin name format: use username/repo/plugin.' ,
220+ color = self .bot .main_color
221+ )
222+ await message .edit (embed = em )
185223
186224 @plugin .command (name = 'remove' , aliases = ['del' , 'delete' , 'rm' ])
187225 @checks .has_permissions (PermissionLevel .OWNER )
188226 async def plugin_remove (self , ctx , * , plugin_name : str ):
189227 """Remove a plugin."""
228+
190229 if plugin_name in self .registry :
191230 info = self .registry [plugin_name ]
192231 plugin_name = info ['repository' ] + '/' + plugin_name
232+
193233 if plugin_name in self .bot .config .plugins :
194234 try :
195235 username , repo , name = self .parse_plugin (plugin_name )
196- self .bot .unload_extension (
197- f'plugins.{ username } -{ repo } .{ name } .{ name } '
198- )
199- except :
236+
237+ self .bot .unload_extension (f'plugins.{ username } -{ repo } .{ name } .{ name } ' )
238+ except Exception :
200239 pass
201240
202241 self .bot .config .plugins .remove (plugin_name )
@@ -211,67 +250,102 @@ def onerror(func, path, exc_info): # pylint: disable=W0613
211250 os .chmod (path , stat .S_IWUSR )
212251 func (path )
213252
214- shutil .rmtree (f'plugins/{ username } -{ repo } ' ,
215- onerror = onerror )
253+ shutil .rmtree (f'plugins/{ username } -{ repo } ' , onerror = onerror )
216254 except Exception as exc :
217255 logger .error (str (exc ))
218256 self .bot .config .plugins .append (plugin_name )
219257 raise exc
220258
221259 await self .bot .config .update ()
222- await ctx .send ('Plugin uninstalled and '
223- 'all related data is erased.' )
260+
261+ em = discord .Embed (
262+ description = 'The plugin is uninstalled and all its data is erased.' ,
263+ color = self .bot .main_color
264+ )
265+ await ctx .send (embed = em )
224266 else :
225- await ctx .send ('Plugin not installed.' )
267+ em = discord .Embed (
268+ description = 'That plugin is not installed.' ,
269+ color = self .bot .main_color
270+ )
271+ await ctx .send (embed = em )
226272
227273 @plugin .command (name = 'update' )
228274 @checks .has_permissions (PermissionLevel .OWNER )
229275 async def plugin_update (self , ctx , * , plugin_name : str ):
230276 """Update a plugin."""
277+
231278 if plugin_name in self .registry :
232279 info = self .registry [plugin_name ]
233280 plugin_name = info ['repository' ] + '/' + plugin_name
281+
234282 if plugin_name not in self .bot .config .plugins :
235- return await ctx .send ('Plugin not installed.' )
283+ em = discord .Embed (
284+ description = 'That plugin is not installed.' ,
285+ color = self .bot .main_color
286+ )
287+ return await ctx .send (embed = em )
236288
237289 async with ctx .typing ():
238290 username , repo , name = self .parse_plugin (plugin_name )
291+
239292 try :
240293 cmd = f'cd plugins/{ username } -{ repo } && git pull'
241- cmd = await self .bot .loop .run_in_executor (
242- None ,
243- self ._asubprocess_run ,
244- cmd
245- )
294+ cmd = await self .bot .loop .run_in_executor (None , self ._asubprocess_run , cmd )
246295 except subprocess .CalledProcessError as exc :
247296 err = exc .stderr .decode ('utf8' ).strip ()
248- await ctx .send (f'Error while updating: { err } .' )
297+
298+ em = discord .Embed (
299+ description = f'An error occured while updating: { err } .' ,
300+ color = self .bot .main_color
301+ )
302+ await ctx .send (embed = em )
303+
249304 else :
250305 output = cmd .stdout .decode ('utf8' ).strip ()
251- await ctx .send (f'```\n { output } \n ```' )
306+
307+ em = discord .Embed (
308+ description = f'```\n { output } \n ```' ,
309+ color = self .bot .main_color
310+ )
311+ await ctx .send (embed = em )
252312
253313 if output != 'Already up to date.' :
254314 # repo was updated locally, now perform the cog reload
255315 ext = f'plugins.{ username } -{ repo } .{ name } .{ name } '
256316 self .bot .unload_extension (ext )
317+
257318 try :
258319 await self .load_plugin (username , repo , name )
259320 except DownloadError as exc :
260- await ctx .send (f'Unable to start plugin: `{ exc } `.' )
321+ em = discord .Embed (
322+ description = f'Unable to start the plugin: `{ exc } `.' ,
323+ color = self .bot .main_color
324+ )
325+ await ctx .send (embed = em )
261326
262327 @plugin .command (name = 'enabled' , aliases = ['installed' ])
263328 @checks .has_permissions (PermissionLevel .OWNER )
264329 async def plugin_enabled (self , ctx ):
265330 """Shows a list of currently enabled plugins."""
331+
266332 if self .bot .config .plugins :
267333 msg = '```\n ' + '\n ' .join (self .bot .config .plugins ) + '\n ```'
268- await ctx .send (msg )
334+ em = discord .Embed (
335+ description = msg ,
336+ color = self .bot .main_color
337+ )
338+ await ctx .send (embed = em )
269339 else :
270- await ctx .send ('No plugins installed.' )
340+ em = discord .Embed (
341+ description = 'There are no plugins installed.' ,
342+ color = self .bot .main_color
343+ )
344+ await ctx .send (embed = em )
271345
272346 @plugin .group (invoke_without_command = True , name = 'registry' , aliases = ['list' ])
273347 @checks .has_permissions (PermissionLevel .OWNER )
274- async def plugin_registry (self , ctx , * , plugin_name :str = None ):
348+ async def plugin_registry (self , ctx , * , plugin_name : str = None ):
275349 """Shows a list of all approved plugins."""
276350
277351 await self .populate_registry ()
@@ -293,13 +367,15 @@ def find_index(name):
293367 index = find_index (plugin_name )
294368 elif plugin_name is not None :
295369 em = discord .Embed (
296- color = discord .Color .red (),
297- description = f'Could not find a plugin with name "{ plugin_name } " within the registry.'
298- )
370+ color = discord .Color .red (),
371+ description = f'Could not find a plugin with name "{ plugin_name } " within the registry.'
372+ )
299373
300374 matches = get_close_matches (plugin_name , self .registry .keys ())
375+
301376 if matches :
302377 em .add_field (name = 'Perhaps you meant' , value = '\n ' .join (f'`{ m } `' for m in matches ))
378+
303379 return await ctx .send (embed = em )
304380
305381 for name , info in registry :
@@ -312,11 +388,11 @@ def find_index(name):
312388 url = repo ,
313389 title = info ['repository' ]
314390 )
315-
391+
316392 em .add_field (
317- name = 'Installation' ,
393+ name = 'Installation' ,
318394 value = f'```{ self .bot .prefix } plugins add { name } ```' )
319-
395+
320396 em .set_author (name = info ['title' ], icon_url = info .get ('icon_url' ), url = url )
321397 if info .get ('thumbnail_url' ):
322398 em .set_thumbnail (url = info .get ('thumbnail_url' ))
@@ -351,12 +427,12 @@ async def plugin_registry_compact(self, ctx):
351427 pages .append (fmt + '\n ' )
352428 else :
353429 pages [- 1 ] += fmt + '\n '
354-
430+
355431 embeds = []
356432
357433 for page in pages :
358434 em = discord .Embed (
359- color = self .bot .main_color ,
435+ color = self .bot .main_color ,
360436 description = page ,
361437 )
362438 em .set_author (name = 'Plugin Registry' , icon_url = self .bot .user .avatar_url )
@@ -366,9 +442,5 @@ async def plugin_registry_compact(self, ctx):
366442 await paginator .run ()
367443
368444
369-
370-
371-
372-
373445def setup (bot ):
374446 bot .add_cog (Plugins (bot ))
0 commit comments