Skip to content

Commit 071d9a7

Browse files
committed
Support branches in plugin add.
1 parent 99dfcb2 commit 071d9a7

10 files changed

+99
-40
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
# v2.23.1
8+
9+
### Added
10+
11+
Branch support for `plugin add` and in registry. Typically for developers.
12+
713
# v2.23.0
814

915
### Added

bot.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
SOFTWARE.
2626
"""
2727

28-
__version__ = "2.23.0"
28+
__version__ = "2.23.1"
2929

3030
import asyncio
3131
import logging
@@ -386,6 +386,7 @@ async def on_ready(self):
386386
logger.info(info("Client ready."))
387387
logger.info(LINE)
388388
logger.info(info(f"Logged in as: {self.user}"))
389+
logger.info(info(f"Prefix: {self.prefix}"))
389390
logger.info(info(f"User ID: {self.user.id}"))
390391
logger.info(info(f"Guild ID: {self.guild.id if self.guild else 0}"))
391392
logger.info(LINE)
@@ -983,6 +984,9 @@ async def autoupdate_loop(self):
983984

984985
async def metadata_loop(self):
985986
await self.wait_until_ready()
987+
if not self.guild:
988+
return
989+
986990
owner = (await self.application_info()).owner
987991

988992
while not self.is_closed():

cogs/plugins.py

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import importlib
23
import json
34
import logging
@@ -13,13 +14,12 @@
1314
import discord
1415
from discord.ext import commands
1516
from discord.utils import async_all
16-
1717
from pkg_resources import parse_version
1818

1919
from core import checks
2020
from core.models import PermissionLevel
2121
from core.paginator import PaginatorSession
22-
from core.utils import info, error
22+
from core.utils import error, info
2323

2424
logger = logging.getLogger("Modmail")
2525

@@ -55,10 +55,20 @@ def _asubprocess_run(cmd):
5555

5656
@staticmethod
5757
def parse_plugin(name):
58-
# returns: (username, repo, plugin_name)
58+
# returns: (username, repo, plugin_name, branch)
59+
# default branch = master
5960
try:
6061
result = name.split("/")
6162
result[2] = "/".join(result[2:])
63+
if '@' in result[2]:
64+
# branch is specified
65+
# for example, fourjr/modmail-plugins/welcomer@develop is a valid name
66+
branchsplit_result = result[2].split('@')
67+
result.append(branchsplit_result[-1])
68+
result[2] = '@'.join(branchsplit_result[:-1])
69+
else:
70+
result.append('master')
71+
6272
except IndexError:
6373
return None
6474

@@ -68,18 +78,18 @@ async def download_initial_plugins(self):
6878
await self.bot._connected.wait()
6979

7080
for i in self.bot.config.plugins:
71-
parsed_plugin = self.parse_plugin(i)
81+
username, repo, name, branch = self.parse_plugin(i)
7282

7383
try:
74-
await self.download_plugin_repo(*parsed_plugin[:-1])
84+
await self.download_plugin_repo(username, repo, branch)
7585
except DownloadError as exc:
76-
msg = f"{parsed_plugin[0]}/{parsed_plugin[1]} - {exc}"
86+
msg = f"{username}/{repo}@{branch} - {exc}"
7787
logger.error(error(msg))
7888
else:
7989
try:
80-
await self.load_plugin(*parsed_plugin)
90+
await self.load_plugin(username, repo, name, branch)
8191
except DownloadError as exc:
82-
msg = f"{parsed_plugin[0]}/{parsed_plugin[1]} - {exc}"
92+
msg = f"{username}/{repo}@{branch}[{name}] - {exc}"
8393
logger.error(error(msg))
8494

8595
await async_all(
@@ -88,10 +98,11 @@ async def download_initial_plugins(self):
8898

8999
logger.debug(info("on_plugin_ready called."))
90100

91-
async def download_plugin_repo(self, username, repo):
101+
async def download_plugin_repo(self, username, repo, branch):
92102
try:
93-
cmd = f"git clone https://github.com/{username}/{repo} "
94-
cmd += f"plugins/{username}-{repo} -q"
103+
cmd = f"git clone https://github.com/{username}/{repo} "
104+
cmd += f"plugins/{username}-{repo}-{branch} "
105+
cmd += f"-b {branch} -q"
95106

96107
await self.bot.loop.run_in_executor(None, self._asubprocess_run, cmd)
97108
# -q (quiet) so there's no terminal output unless there's an error
@@ -100,11 +111,13 @@ async def download_plugin_repo(self, username, repo):
100111

101112
if not err.endswith("already exists and is not an empty directory."):
102113
# don't raise error if the plugin folder exists
103-
raise DownloadError(error) from exc
114+
msg = f'Download Error: {username}/{repo}@{branch}'
115+
logger.error(msg)
116+
raise DownloadError(err) from exc
104117

105-
async def load_plugin(self, username, repo, plugin_name):
106-
ext = f"plugins.{username}-{repo}.{plugin_name}.{plugin_name}"
107-
dirname = f"plugins/{username}-{repo}/{plugin_name}"
118+
async def load_plugin(self, username, repo, plugin_name, branch):
119+
ext = f"plugins.{username}-{repo}-{branch}.{plugin_name}.{plugin_name}"
120+
dirname = f"plugins/{username}-{repo}-{branch}/{plugin_name}"
108121

109122
if "requirements.txt" in os.listdir(dirname):
110123
# Install PIP requirements
@@ -113,7 +126,7 @@ async def load_plugin(self, username, repo, plugin_name):
113126
await self.bot.loop.run_in_executor(
114127
None,
115128
self._asubprocess_run,
116-
f"pip install -r {dirname}/requirements.txt -q -q",
129+
f"pip install -r {dirname}/requirements.txt --user -q -q",
117130
)
118131
else:
119132
await self.bot.loop.run_in_executor(
@@ -128,24 +141,26 @@ async def load_plugin(self, username, repo, plugin_name):
128141
err = exc.stderr.decode("utf8").strip()
129142

130143
if err:
144+
msg = f'Requirements Download Error: {username}/{repo}@{branch}[{plugin_name}]'
145+
logger.error(error(msg))
131146
raise DownloadError(
132-
f"Unable to download requirements: ```\n{error}\n```"
147+
f"Unable to download requirements: ```\n{err}\n```"
133148
) from exc
134149
else:
135150
if not os.path.exists(site.USER_SITE):
136151
os.makedirs(site.USER_SITE)
137152

138153
sys.path.insert(0, site.USER_SITE)
139154

155+
await asyncio.sleep(0.5)
140156
try:
141157
self.bot.load_extension(ext)
142158
except commands.ExtensionError as exc:
143-
# TODO: Add better error handling for plugin load faliure
144-
import traceback
145-
traceback.print_exc()
159+
msg = f'Plugin Load Failure: {username}/{repo}@{branch}[{plugin_name}]'
160+
logger.error(error(msg))
146161
raise DownloadError("Invalid plugin") from exc
147162
else:
148-
msg = f"Loaded plugins.{username}-{repo}.{plugin_name}"
163+
msg = f"Loaded Plugin: {username}/{repo}@{branch}[{plugin_name}]"
149164
logger.info(info(msg))
150165

151166
@commands.group(aliases=["plugins"], invoke_without_command=True)
@@ -162,7 +177,7 @@ async def plugin_add(self, ctx, *, plugin_name: str):
162177

163178
if plugin_name in self.registry:
164179
details = self.registry[plugin_name]
165-
plugin_name = details["repository"] + "/" + plugin_name
180+
plugin_name = details["repository"] + "/" + plugin_name + "@" + details["branch"]
166181
required_version = details["bot_version"]
167182

168183
if parse_version(self.bot.version) < parse_version(required_version):
@@ -194,24 +209,24 @@ async def plugin_add(self, ctx, *, plugin_name: str):
194209

195210
async with ctx.typing():
196211
if len(plugin_name.split("/")) >= 3:
197-
parsed_plugin = self.parse_plugin(plugin_name)
212+
username, repo, name, branch = self.parse_plugin(plugin_name)
198213

199214
try:
200-
await self.download_plugin_repo(*parsed_plugin[:-1])
215+
await self.download_plugin_repo(username, repo, branch)
201216
except DownloadError as exc:
202217
embed = discord.Embed(
203-
description=f"Unable to fetch this plugin from Github: {exc}.",
218+
description=f"Unable to fetch this plugin from Github: `{exc}`.",
204219
color=self.bot.main_color,
205220
)
206221
return await ctx.send(embed=embed)
207222

208223
importlib.invalidate_caches()
209224

210225
try:
211-
await self.load_plugin(*parsed_plugin)
226+
await self.load_plugin(username, repo, name, branch)
212227
except Exception as exc:
213228
embed = discord.Embed(
214-
description=f"Unable to load this plugin: {exc}.",
229+
description=f"Unable to load this plugin: `{exc}`.",
215230
color=self.bot.main_color,
216231
)
217232
return await ctx.send(embed=embed)
@@ -224,7 +239,7 @@ async def plugin_add(self, ctx, *, plugin_name: str):
224239

225240
embed = discord.Embed(
226241
description="The plugin is installed.\n"
227-
"*Please note: any plugin that you install is at your OWN RISK*",
242+
"*Please note: Any plugin that you install is at your **own risk***",
228243
color=self.bot.main_color,
229244
)
230245
await ctx.send(embed=embed)
@@ -242,13 +257,13 @@ async def plugin_remove(self, ctx, *, plugin_name: str):
242257

243258
if plugin_name in self.registry:
244259
details = self.registry[plugin_name]
245-
plugin_name = details["repository"] + "/" + plugin_name
260+
plugin_name = details["repository"] + "/" + plugin_name + "@" + details["branch"]
246261

247262
if plugin_name in self.bot.config.plugins:
248263
try:
249-
username, repo, name = self.parse_plugin(plugin_name)
264+
username, repo, name, branch = self.parse_plugin(plugin_name)
250265

251-
self.bot.unload_extension(f"plugins.{username}-{repo}.{name}.{name}")
266+
self.bot.unload_extension(f"plugins.{username}-{repo}-{branch}.{name}.{name}")
252267
except Exception:
253268
pass
254269

@@ -266,10 +281,11 @@ def onerror(func, path, exc_info): # pylint: disable=W0613
266281
os.chmod(path, stat.S_IWUSR)
267282
func(path)
268283

269-
shutil.rmtree(f"plugins/{username}-{repo}", onerror=onerror)
284+
shutil.rmtree(f"plugins/{username}-{repo}-{branch}", onerror=onerror)
270285
except Exception as exc:
271286
logger.error(str(exc))
272287
self.bot.config.plugins.append(plugin_name)
288+
logger.error(error(exc))
273289
raise exc
274290

275291
await self.bot.config.update()
@@ -292,7 +308,7 @@ async def plugin_update(self, ctx, *, plugin_name: str):
292308

293309
if plugin_name in self.registry:
294310
details = self.registry[plugin_name]
295-
plugin_name = details["repository"] + "/" + plugin_name
311+
plugin_name = details["repository"] + "/" + plugin_name + "@" + details["branch"]
296312

297313
if plugin_name not in self.bot.config.plugins:
298314
embed = discord.Embed(
@@ -301,10 +317,10 @@ async def plugin_update(self, ctx, *, plugin_name: str):
301317
return await ctx.send(embed=embed)
302318

303319
async with ctx.typing():
304-
username, repo, name = self.parse_plugin(plugin_name)
320+
username, repo, name, branch = self.parse_plugin(plugin_name)
305321

306322
try:
307-
cmd = f"cd plugins/{username}-{repo} && git reset --hard origin/master && git fetch --all && git pull"
323+
cmd = f"cd plugins/{username}-{repo}-{branch} && git reset --hard origin/master && git fetch --all && git pull"
308324
cmd = await self.bot.loop.run_in_executor(
309325
None, self._asubprocess_run, cmd
310326
)
@@ -327,11 +343,11 @@ async def plugin_update(self, ctx, *, plugin_name: str):
327343

328344
if output != "Already up to date.":
329345
# repo was updated locally, now perform the cog reload
330-
ext = f"plugins.{username}-{repo}.{name}.{name}"
346+
ext = f"plugins.{username}-{repo}-{branch}.{name}.{name}"
331347
self.bot.unload_extension(ext)
332348

333349
try:
334-
await self.load_plugin(username, repo, name)
350+
await self.load_plugin(username, repo, name, branch)
335351
except DownloadError as exc:
336352
em = discord.Embed(
337353
description=f"Unable to start the plugin: `{exc}`.",
@@ -434,7 +450,7 @@ async def plugin_registry_compact(self, ctx):
434450

435451
for name, details in registry:
436452
repo = f"https://github.com/{details['repository']}"
437-
url = f"{repo}/tree/master/{name}"
453+
url = f"{repo}/tree/{details['branch']}/{name}"
438454
desc = details["description"].replace("\n", "")
439455
fmt = f"[`{name}`]({url}) - {desc}"
440456
length = len(fmt) - len(url) - 4
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 61921e55e60ccce6a96616b3389474b2b514ca94

plugins/fourjr-modmail-plugins-master

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit b3ecfd7463671f32a32e1b798143ee0689835c92

plugins/kyb3r-modmail-plugins-master

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit cdddc083d328b21ad696cbd0362e5206fe4c57b3
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit a389b6cd1f550c20ec7ce0ad4ba6e5daa657971c
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 9be8f4f910794991b6aea0573969d48c5793cd70

0 commit comments

Comments
 (0)