Skip to content

Commit 695baa5

Browse files
committed
Add local plugins
1 parent 69a272e commit 695baa5

File tree

2 files changed

+53
-29
lines changed

2 files changed

+53
-29
lines changed

.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ node_modules/
131131

132132
# Modmail
133133
config.json
134-
plugins/
135-
!plugins/registry.json
136134
temp/
137135
test.py
138136
stack.yml

cogs/plugins.py

+53-27
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,28 @@ class InvalidPluginError(commands.BadArgument):
3131

3232

3333
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}"
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

Comments
 (0)