@@ -31,16 +31,28 @@ class InvalidPluginError(commands.BadArgument):
31
31
32
32
33
33
class 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 } "
41
51
42
52
@property
43
53
def path (self ):
54
+ if self .local :
55
+ return PurePath ("plugins" ) / "@local" / self .name
44
56
return PurePath ("plugins" ) / self .user / self .repo / f"{ self .name } -{ self .branch } "
45
57
46
58
@property
@@ -49,6 +61,8 @@ def abs_path(self):
49
61
50
62
@property
51
63
def cache_path (self ):
64
+ if self .local :
65
+ raise ValueError ("No cache path for local plugins!" )
52
66
return (
53
67
Path (__file__ ).absolute ().parent .parent
54
68
/ "temp"
@@ -58,20 +72,27 @@ def cache_path(self):
58
72
59
73
@property
60
74
def ext_string (self ):
75
+ if self .local :
76
+ return f"plugins.@local.{ self .name } .{ self .name } "
61
77
return f"plugins.{ self .user } .{ self .repo } .{ self .name } -{ self .branch } .{ self .name } "
62
78
63
79
def __str__ (self ):
80
+ if self .local :
81
+ return f"@local/{ self .name } "
64
82
return f"{ self .user } /{ self .repo } /{ self .name } @{ self .branch } "
65
83
66
84
def __lt__ (self , other ):
67
85
return self .name .lower () < other .name .lower ()
68
86
69
87
@classmethod
70
88
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
+
75
96
if m is not None :
76
97
return Plugin (* m .groups ())
77
98
raise InvalidPluginError ("Cannot decipher %s." , s ) # pylint: disable=raising-format-tuple
@@ -152,9 +173,12 @@ async def initial_load_plugins(self):
152
173
await self .bot .config .update ()
153
174
154
175
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 ) :
156
177
return
157
178
179
+ if plugin .local :
180
+ raise InvalidPluginError (f"Local plugin { plugin } not found!" )
181
+
158
182
plugin .abs_path .mkdir (parents = True , exist_ok = True )
159
183
160
184
if plugin .cache_path .exists () and not force :
@@ -178,14 +202,14 @@ async def download_plugin(self, plugin, force=False):
178
202
if raw == "Not Found" :
179
203
raise InvalidPluginError ("Plugin not found" )
180
204
else :
181
- raise InvalidPluginError ("Invalid download recieved , non-bytes object" )
205
+ raise InvalidPluginError ("Invalid download received , non-bytes object" )
182
206
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 )
186
210
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 )
189
213
190
214
with zipfile .ZipFile (plugin_io ) as zipf :
191
215
for info in zipf .infolist ():
@@ -253,7 +277,7 @@ async def parse_user_input(self, ctx, plugin_name, check_version=False):
253
277
description = "Plugins are disabled, enable them by setting `ENABLE_PLUGINS=true`" ,
254
278
color = self .bot .main_color ,
255
279
)
256
- await ctx .send (embed = em )
280
+ await ctx .send (embed = embed )
257
281
return
258
282
259
283
if not self ._ready_event .is_set ():
@@ -290,7 +314,7 @@ async def parse_user_input(self, ctx, plugin_name, check_version=False):
290
314
embed = discord .Embed (
291
315
description = "Invalid plugin name, double check the plugin name "
292
316
"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 ." ,
294
318
color = self .bot .error_color ,
295
319
)
296
320
await ctx .send (embed = embed )
@@ -314,7 +338,8 @@ async def plugins_add(self, ctx, *, plugin_name: str):
314
338
Install a new plugin for the bot.
315
339
316
340
`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.
318
343
"""
319
344
320
345
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):
335
360
)
336
361
return await ctx .send (embed = embed )
337
362
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
+ )
342
373
msg = await ctx .send (embed = embed )
343
374
344
375
try :
@@ -395,7 +426,7 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
395
426
Remove an installed plugin of the bot.
396
427
397
428
`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 .
399
430
"""
400
431
plugin = await self .parse_user_input (ctx , plugin_name )
401
432
if plugin is None :
@@ -416,17 +447,18 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
416
447
417
448
self .bot .config ["plugins" ].remove (str (plugin ))
418
449
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
430
462
431
463
embed = discord .Embed (
432
464
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):
477
509
Update a plugin for the bot.
478
510
479
511
`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 .
481
513
482
514
To update all plugins, do `{prefix}plugins update`.
483
515
"""
@@ -514,7 +546,7 @@ async def plugins_reset(self, ctx):
514
546
shutil .rmtree (cache_path )
515
547
516
548
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" :
518
550
shutil .rmtree (entry .path )
519
551
logger .warning ("Removing %s." , entry .name )
520
552
0 commit comments