@@ -31,16 +31,28 @@ class InvalidPluginError(commands.BadArgument):
3131
3232
3333class Plugin :
34- def __init__ (self , user , repo , name , branch = None ):
35- self .user = user
36- self .repo = repo
37- self .name = name
38- self .branch = branch if branch is not None else "master"
39- self .url = f"https://github.com/{ user } /{ repo } /archive/{ self .branch } .zip"
40- self .link = f"https://github.com/{ user } /{ repo } /tree/{ self .branch } /{ name } "
34+ def __init__ (self , user , repo = None , name = None , branch = None ):
35+ if repo is None :
36+ self .user = "@local"
37+ self .repo = "@local"
38+ self .name = user
39+ self .local = True
40+ self .branch = "@local"
41+ self .url = f"@local/{ user } "
42+ self .link = f"@local/{ user } "
43+ else :
44+ self .user = user
45+ self .repo = repo
46+ self .name = name
47+ self .local = False
48+ self .branch = branch if branch is not None else "master"
49+ self .url = f"https://github.com/{ user } /{ repo } /archive/{ self .branch } .zip"
50+ self .link = f"https://github.com/{ user } /{ repo } /tree/{ self .branch } /{ name } "
4151
4252 @property
4353 def path (self ):
54+ if self .local :
55+ return PurePath ("plugins" ) / "@local" / self .name
4456 return PurePath ("plugins" ) / self .user / self .repo / f"{ self .name } -{ self .branch } "
4557
4658 @property
@@ -49,6 +61,8 @@ def abs_path(self):
4961
5062 @property
5163 def cache_path (self ):
64+ if self .local :
65+ raise ValueError ("No cache path for local plugins!" )
5266 return (
5367 Path (__file__ ).absolute ().parent .parent
5468 / "temp"
@@ -58,20 +72,27 @@ def cache_path(self):
5872
5973 @property
6074 def ext_string (self ):
75+ if self .local :
76+ return f"plugins.@local.{ self .name } .{ self .name } "
6177 return f"plugins.{ self .user } .{ self .repo } .{ self .name } -{ self .branch } .{ self .name } "
6278
6379 def __str__ (self ):
80+ if self .local :
81+ return f"@local/{ self .name } "
6482 return f"{ self .user } /{ self .repo } /{ self .name } @{ self .branch } "
6583
6684 def __lt__ (self , other ):
6785 return self .name .lower () < other .name .lower ()
6886
6987 @classmethod
7088 def from_string (cls , s , strict = False ):
71- if not strict :
72- m = match (r"^(.+?)/(.+?)/(.+?)(?:@(.+?))?$" , s )
73- else :
74- m = match (r"^(.+?)/(.+?)/(.+?)@(.+?)$" , s )
89+ m = match (r"^@?local/(.+)$" , s )
90+ if m is None :
91+ if not strict :
92+ m = match (r"^(.+?)/(.+?)/(.+?)(?:@(.+?))?$" , s )
93+ else :
94+ m = match (r"^(.+?)/(.+?)/(.+?)@(.+?)$" , s )
95+
7596 if m is not None :
7697 return Plugin (* m .groups ())
7798 raise InvalidPluginError ("Cannot decipher %s." , s ) # pylint: disable=raising-format-tuple
@@ -152,9 +173,12 @@ async def initial_load_plugins(self):
152173 await self .bot .config .update ()
153174
154175 async def download_plugin (self , plugin , force = False ):
155- if plugin .abs_path .exists () and not force :
176+ if plugin .abs_path .exists () and ( not force or plugin . local ) :
156177 return
157178
179+ if plugin .local :
180+ raise InvalidPluginError (f"Local plugin { plugin } not found!" )
181+
158182 plugin .abs_path .mkdir (parents = True , exist_ok = True )
159183
160184 if plugin .cache_path .exists () and not force :
@@ -178,14 +202,14 @@ async def download_plugin(self, plugin, force=False):
178202 if raw == "Not Found" :
179203 raise InvalidPluginError ("Plugin not found" )
180204 else :
181- raise InvalidPluginError ("Invalid download recieved , non-bytes object" )
205+ raise InvalidPluginError ("Invalid download received , non-bytes object" )
182206
183- plugin_io = io .BytesIO (raw )
184- if not plugin .cache_path .parent .exists ():
185- plugin .cache_path .parent .mkdir (parents = True )
207+ plugin_io = io .BytesIO (raw )
208+ if not plugin .cache_path .parent .exists ():
209+ plugin .cache_path .parent .mkdir (parents = True )
186210
187- with plugin .cache_path .open ("wb" ) as f :
188- f .write (raw )
211+ with plugin .cache_path .open ("wb" ) as f :
212+ f .write (raw )
189213
190214 with zipfile .ZipFile (plugin_io ) as zipf :
191215 for info in zipf .infolist ():
@@ -253,7 +277,7 @@ async def parse_user_input(self, ctx, plugin_name, check_version=False):
253277 description = "Plugins are disabled, enable them by setting `ENABLE_PLUGINS=true`" ,
254278 color = self .bot .main_color ,
255279 )
256- await ctx .send (embed = em )
280+ await ctx .send (embed = embed )
257281 return
258282
259283 if not self ._ready_event .is_set ():
@@ -290,7 +314,7 @@ async def parse_user_input(self, ctx, plugin_name, check_version=False):
290314 embed = discord .Embed (
291315 description = "Invalid plugin name, double check the plugin name "
292316 "or use one of the following formats: "
293- "username/repo/plugin, username/repo/plugin@branch." ,
317+ "username/repo/plugin-name , username/repo/plugin-name @branch, local/plugin-name ." ,
294318 color = self .bot .error_color ,
295319 )
296320 await ctx .send (embed = embed )
@@ -314,7 +338,8 @@ async def plugins_add(self, ctx, *, plugin_name: str):
314338 Install a new plugin for the bot.
315339
316340 `plugin_name` can be the name of the plugin found in `{prefix}plugin registry`,
317- or a direct reference to a GitHub hosted plugin (in the format `user/repo/name[@branch]`).
341+ or a direct reference to a GitHub hosted plugin (in the format `user/repo/name[@branch]`)
342+ or `local/name` for local plugins.
318343 """
319344
320345 plugin = await self .parse_user_input (ctx , plugin_name , check_version = True )
@@ -335,10 +360,16 @@ async def plugins_add(self, ctx, *, plugin_name: str):
335360 )
336361 return await ctx .send (embed = embed )
337362
338- embed = discord .Embed (
339- description = f"Starting to download plugin from { plugin .link } ..." ,
340- color = self .bot .main_color ,
341- )
363+ if plugin .local :
364+ embed = discord .Embed (
365+ description = f"Starting to load local plugin from { plugin .link } ..." ,
366+ color = self .bot .main_color ,
367+ )
368+ else :
369+ embed = discord .Embed (
370+ description = f"Starting to download plugin from { plugin .link } ..." ,
371+ color = self .bot .main_color ,
372+ )
342373 msg = await ctx .send (embed = embed )
343374
344375 try :
@@ -395,7 +426,7 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
395426 Remove an installed plugin of the bot.
396427
397428 `plugin_name` can be the name of the plugin found in `{prefix}plugin registry`, or a direct reference
398- to a GitHub hosted plugin (in the format `user/repo/name[@branch]`).
429+ to a GitHub hosted plugin (in the format `user/repo/name[@branch]`) or `local/name` for local plugins .
399430 """
400431 plugin = await self .parse_user_input (ctx , plugin_name )
401432 if plugin is None :
@@ -416,17 +447,18 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
416447
417448 self .bot .config ["plugins" ].remove (str (plugin ))
418449 await self .bot .config .update ()
419- shutil .rmtree (
420- plugin .abs_path ,
421- onerror = lambda * args : logger .warning (
422- "Failed to remove plugin files %s: %s" , plugin , str (args [2 ])
423- ),
424- )
425- try :
426- plugin .abs_path .parent .rmdir ()
427- plugin .abs_path .parent .parent .rmdir ()
428- except OSError :
429- pass # dir not empty
450+ if not plugin .local :
451+ shutil .rmtree (
452+ plugin .abs_path ,
453+ onerror = lambda * args : logger .warning (
454+ "Failed to remove plugin files %s: %s" , plugin , str (args [2 ])
455+ ),
456+ )
457+ try :
458+ plugin .abs_path .parent .rmdir ()
459+ plugin .abs_path .parent .parent .rmdir ()
460+ except OSError :
461+ pass # dir not empty
430462
431463 embed = discord .Embed (
432464 description = "The plugin is successfully uninstalled." , color = self .bot .main_color
@@ -477,7 +509,7 @@ async def plugins_update(self, ctx, *, plugin_name: str = None):
477509 Update a plugin for the bot.
478510
479511 `plugin_name` can be the name of the plugin found in `{prefix}plugin registry`, or a direct reference
480- to a GitHub hosted plugin (in the format `user/repo/name[@branch]`).
512+ to a GitHub hosted plugin (in the format `user/repo/name[@branch]`) or `local/name` for local plugins .
481513
482514 To update all plugins, do `{prefix}plugins update`.
483515 """
@@ -514,7 +546,7 @@ async def plugins_reset(self, ctx):
514546 shutil .rmtree (cache_path )
515547
516548 for entry in os .scandir (Path (__file__ ).absolute ().parent .parent / "plugins" ):
517- if entry .is_dir ():
549+ if entry .is_dir () and entry . name != "@local" :
518550 shutil .rmtree (entry .path )
519551 logger .warning ("Removing %s." , entry .name )
520552
0 commit comments