@@ -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
@@ -155,6 +176,9 @@ async def download_plugin(self, plugin, force=False):
155176 if plugin .abs_path .exists () and not force :
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 :
@@ -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, username/repo/plugin@branch, @local/plugin ." ,
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 )
@@ -395,7 +420,7 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
395420 Remove an installed plugin of the bot.
396421
397422 `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]`).
423+ to a GitHub hosted plugin (in the format `user/repo/name[@branch]`) or `@local/name` for local plugins .
399424 """
400425 plugin = await self .parse_user_input (ctx , plugin_name )
401426 if plugin is None :
@@ -416,17 +441,18 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
416441
417442 self .bot .config ["plugins" ].remove (str (plugin ))
418443 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
444+ if not plugin .local :
445+ shutil .rmtree (
446+ plugin .abs_path ,
447+ onerror = lambda * args : logger .warning (
448+ "Failed to remove plugin files %s: %s" , plugin , str (args [2 ])
449+ ),
450+ )
451+ try :
452+ plugin .abs_path .parent .rmdir ()
453+ plugin .abs_path .parent .parent .rmdir ()
454+ except OSError :
455+ pass # dir not empty
430456
431457 embed = discord .Embed (
432458 description = "The plugin is successfully uninstalled." , color = self .bot .main_color
@@ -477,7 +503,7 @@ async def plugins_update(self, ctx, *, plugin_name: str = None):
477503 Update a plugin for the bot.
478504
479505 `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]`).
506+ to a GitHub hosted plugin (in the format `user/repo/name[@branch]`) or `@local/name` for local plugins .
481507
482508 To update all plugins, do `{prefix}plugins update`.
483509 """
@@ -514,7 +540,7 @@ async def plugins_reset(self, ctx):
514540 shutil .rmtree (cache_path )
515541
516542 for entry in os .scandir (Path (__file__ ).absolute ().parent .parent / "plugins" ):
517- if entry .is_dir ():
543+ if entry .is_dir () and entry . name != "@local" :
518544 shutil .rmtree (entry .path )
519545 logger .warning ("Removing %s." , entry .name )
520546
0 commit comments