[i18n] Pass over bank, cleanup, customcom, dataconverter, downloader

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
This commit is contained in:
Toby Harradine 2018-08-16 23:51:45 +10:00
parent 3a20c11331
commit 0c3d8af8f4
9 changed files with 123 additions and 131 deletions

View File

@ -1,11 +1,10 @@
import logging
from typing import Tuple from typing import Tuple
import discord import discord
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.i18n import Translator, cog_i18n
import logging
from redbot.core.utils.chat_formatting import box from redbot.core.utils.chat_formatting import box
from .announcer import Announcer from .announcer import Announcer
from .converters import MemberDefaultAuthor, SelfRole from .converters import MemberDefaultAuthor, SelfRole

View File

@ -67,7 +67,7 @@ class Bank(commands.Cog):
@checks.guildowner_or_permissions(administrator=True) @checks.guildowner_or_permissions(administrator=True)
@commands.group(autohelp=True) @commands.group(autohelp=True)
async def bankset(self, ctx: commands.Context): async def bankset(self, ctx: commands.Context):
"""Base command for bank settings""" """Base command for bank settings."""
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
if await bank.is_global(): if await bank.is_global():
bank_name = await bank._conf.bank_name() bank_name = await bank._conf.bank_name()
@ -91,9 +91,11 @@ class Bank(commands.Cog):
@bankset.command(name="toggleglobal") @bankset.command(name="toggleglobal")
@checks.is_owner() @checks.is_owner()
async def bankset_toggleglobal(self, ctx: commands.Context, confirm: bool = False): async def bankset_toggleglobal(self, ctx: commands.Context, confirm: bool = False):
"""Toggles whether the bank is global or not """Toggle whether the bank is global or not.
If the bank is global, it will become per-server
If the bank is per-server, it will become global""" If the bank is global, it will become per-server.
If the bank is per-server, it will become global.
"""
cur_setting = await bank.is_global() cur_setting = await bank.is_global()
word = _("per-server") if cur_setting else _("global") word = _("per-server") if cur_setting else _("global")
@ -111,14 +113,14 @@ class Bank(commands.Cog):
@bankset.command(name="bankname") @bankset.command(name="bankname")
@check_global_setting_guildowner() @check_global_setting_guildowner()
async def bankset_bankname(self, ctx: commands.Context, *, name: str): async def bankset_bankname(self, ctx: commands.Context, *, name: str):
"""Set the bank's name""" """Set the bank's name."""
await bank.set_bank_name(name, ctx.guild) await bank.set_bank_name(name, ctx.guild)
await ctx.send(_("Bank name has been set to: {name}").format(name=name)) await ctx.send(_("Bank name has been set to: {name}").format(name=name))
@bankset.command(name="creditsname") @bankset.command(name="creditsname")
@check_global_setting_guildowner() @check_global_setting_guildowner()
async def bankset_creditsname(self, ctx: commands.Context, *, name: str): async def bankset_creditsname(self, ctx: commands.Context, *, name: str):
"""Set the name for the bank's currency""" """Set the name for the bank's currency."""
await bank.set_currency_name(name, ctx.guild) await bank.set_currency_name(name, ctx.guild)
await ctx.send(_("Currency name has been set to: {name}").format(name=name)) await ctx.send(_("Currency name has been set to: {name}").format(name=name))

View File

@ -16,7 +16,7 @@ _ = Translator("Cleanup", __file__)
@cog_i18n(_) @cog_i18n(_)
class Cleanup(commands.Cog): class Cleanup(commands.Cog):
"""Commands for cleaning messages""" """Commands for cleaning messages."""
def __init__(self, bot: Red): def __init__(self, bot: Red):
super().__init__() super().__init__()
@ -104,7 +104,7 @@ class Cleanup(commands.Cog):
@commands.group() @commands.group()
@checks.mod_or_permissions(manage_messages=True) @checks.mod_or_permissions(manage_messages=True)
async def cleanup(self, ctx: commands.Context): async def cleanup(self, ctx: commands.Context):
"""Deletes messages.""" """Delete messages."""
pass pass
@cleanup.command() @cleanup.command()
@ -112,16 +112,17 @@ class Cleanup(commands.Cog):
async def text( async def text(
self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False
): ):
"""Deletes last X messages matching the specified text. """Delete the last X messages matching the specified text.
Example: Example:
cleanup text \"test\" 5 `[p]cleanup text "test" 5`
Remember to use double quotes.""" Remember to use double quotes.
"""
channel = ctx.channel channel = ctx.channel
if not channel.permissions_for(ctx.guild.me).manage_messages: if not channel.permissions_for(ctx.guild.me).manage_messages:
await ctx.send("I need the Manage Messages permission to do this.") await ctx.send(_("I need the Manage Messages permission to do this."))
return return
author = ctx.author author = ctx.author
@ -159,14 +160,15 @@ class Cleanup(commands.Cog):
async def user( async def user(
self, ctx: commands.Context, user: str, number: int, delete_pinned: bool = False self, ctx: commands.Context, user: str, number: int, delete_pinned: bool = False
): ):
"""Deletes last X messages from specified user. """Delete the last X messages from a specified user.
Examples: Examples:
cleanup user @\u200bTwentysix 2 `[p]cleanup user @\u200bTwentysix 2`
cleanup user Red 6""" `[p]cleanup user Red 6`
"""
channel = ctx.channel channel = ctx.channel
if not channel.permissions_for(ctx.guild.me).manage_messages: if not channel.permissions_for(ctx.guild.me).manage_messages:
await ctx.send("I need the Manage Messages permission to do this.") await ctx.send(_("I need the Manage Messages permission to do this."))
return return
member = None member = None
@ -214,7 +216,7 @@ class Cleanup(commands.Cog):
@cleanup.command() @cleanup.command()
@commands.guild_only() @commands.guild_only()
async def after(self, ctx: commands.Context, message_id: int, delete_pinned: bool = False): async def after(self, ctx: commands.Context, message_id: int, delete_pinned: bool = False):
"""Deletes all messages after specified message. """Delete all messages after a specified message.
To get a message id, enable developer mode in Discord's To get a message id, enable developer mode in Discord's
settings, 'appearance' tab. Then right click a message settings, 'appearance' tab. Then right click a message
@ -223,7 +225,7 @@ class Cleanup(commands.Cog):
channel = ctx.channel channel = ctx.channel
if not channel.permissions_for(ctx.guild.me).manage_messages: if not channel.permissions_for(ctx.guild.me).manage_messages:
await ctx.send("I need the Manage Messages permission to do this.") await ctx.send(_("I need the Manage Messages permission to do this."))
return return
author = ctx.author author = ctx.author
@ -280,14 +282,15 @@ class Cleanup(commands.Cog):
@cleanup.command() @cleanup.command()
@commands.guild_only() @commands.guild_only()
async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False): async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False):
"""Deletes last X messages. """Delete the last X messages.
Example: Example:
cleanup messages 26""" `[p]cleanup messages 26`
"""
channel = ctx.channel channel = ctx.channel
if not channel.permissions_for(ctx.guild.me).manage_messages: if not channel.permissions_for(ctx.guild.me).manage_messages:
await ctx.send("I need the Manage Messages permission to do this.") await ctx.send(_("I need the Manage Messages permission to do this."))
return return
author = ctx.author author = ctx.author
@ -311,11 +314,11 @@ class Cleanup(commands.Cog):
@cleanup.command(name="bot") @cleanup.command(name="bot")
@commands.guild_only() @commands.guild_only()
async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False): async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False):
"""Cleans up command messages and messages from the bot.""" """Clean up command messages and messages from the bot."""
channel = ctx.channel channel = ctx.channel
if not channel.permissions_for(ctx.guild.me).manage_messages: if not channel.permissions_for(ctx.guild.me).manage_messages:
await ctx.send("I need the Manage Messages permission to do this.") await ctx.send(_("I need the Manage Messages permission to do this."))
return return
author = ctx.message.author author = ctx.message.author
@ -369,7 +372,7 @@ class Cleanup(commands.Cog):
match_pattern: str = None, match_pattern: str = None,
delete_pinned: bool = False, delete_pinned: bool = False,
): ):
"""Cleans up messages owned by the bot. """Clean up messages owned by the bot.
By default, all messages are cleaned. If a third argument is specified, By default, all messages are cleaned. If a third argument is specified,
it is used for pattern matching: If it begins with r( and ends with ), it is used for pattern matching: If it begins with r( and ends with ),

View File

@ -54,7 +54,7 @@ class CommandObj:
intro = _( intro = _(
"Welcome to the interactive random {cc} maker!\n" "Welcome to the interactive random {cc} maker!\n"
"Every message you send will be added as one of the random " "Every message you send will be added as one of the random "
"responses to choose from once this {} is " "responses to choose from once this {cc} is "
"triggered. To exit this interactive menu, type `{quit}`" "triggered. To exit this interactive menu, type `{quit}`"
).format(cc="customcommand", quit="exit()") ).format(cc="customcommand", quit="exit()")
await ctx.send(intro) await ctx.send(intro)
@ -196,30 +196,26 @@ class CustomCommands(commands.Cog):
@commands.group(aliases=["cc"]) @commands.group(aliases=["cc"])
@commands.guild_only() @commands.guild_only()
async def customcom(self, ctx: commands.Context): async def customcom(self, ctx: commands.Context):
"""Custom commands management""" """Custom commands management."""
pass pass
@customcom.group(name="add") @customcom.group(name="create", aliases=["add"])
@checks.mod_or_permissions(administrator=True) @checks.mod_or_permissions(administrator=True)
async def cc_add(self, ctx: commands.Context): async def cc_create(self, ctx: commands.Context):
""" """Create custom commands.
Adds a new custom command
CCs can be enhanced with arguments: CCs can be enhanced with arguments, see the guide
https://red-discordbot.readthedocs.io/en/v3-develop/cog_customcom.html [here](https://red-discordbot.readthedocs.io/en/v3-develop/cog_customcom.html).
""" """
pass pass
@cc_add.command(name="random") @cc_create.command(name="random")
@checks.mod_or_permissions(administrator=True) @checks.mod_or_permissions(administrator=True)
async def cc_add_random(self, ctx: commands.Context, command: str.lower): async def cc_create_random(self, ctx: commands.Context, command: str.lower):
""" """Create a CC where it will randomly choose a response!
Create a CC where it will randomly choose a response!
Note: This is interactive Note: This command is interactive.
""" """
responses = []
responses = await self.commandobj.get_responses(ctx=ctx) responses = await self.commandobj.get_responses(ctx=ctx)
try: try:
await self.commandobj.create(ctx=ctx, command=command, response=responses) await self.commandobj.create(ctx=ctx, command=command, response=responses)
@ -233,16 +229,16 @@ class CustomCommands(commands.Cog):
# await ctx.send(str(responses)) # await ctx.send(str(responses))
@cc_add.command(name="simple") @cc_create.command(name="simple")
@checks.mod_or_permissions(administrator=True) @checks.mod_or_permissions(administrator=True)
async def cc_add_simple(self, ctx, command: str.lower, *, text: str): async def cc_create_simple(self, ctx, command: str.lower, *, text: str):
"""Adds a simple custom command """Add a simple custom command.
Example: Example:
[p]customcom add simple yourcommand Text you want - `[p]customcom create simple yourcommand Text you want`
""" """
if command in self.bot.all_commands: if command in self.bot.all_commands:
await ctx.send(_("That command is already a standard command.")) await ctx.send(_("There already exists a bot command with the same name."))
return return
try: try:
await self.commandobj.create(ctx=ctx, command=command, response=text) await self.commandobj.create(ctx=ctx, command=command, response=text)
@ -261,13 +257,14 @@ class CustomCommands(commands.Cog):
async def cc_cooldown( async def cc_cooldown(
self, ctx, command: str.lower, cooldown: int = None, *, per: str.lower = "member" self, ctx, command: str.lower, cooldown: int = None, *, per: str.lower = "member"
): ):
""" """Set, edit, or view the cooldown for a custom command.
Sets, edits, or views cooldowns for a custom command
You may set cooldowns per member, channel, or guild. Multiple
cooldowns may be set. All cooldowns must be cooled to call the
custom command.
You may set cooldowns per member, channel, or guild.
Multiple cooldowns may be set. All cooldowns must be cooled to call the custom command.
Example: Example:
[p]customcom cooldown yourcommand 30 - `[p]customcom cooldown yourcommand 30`
""" """
if cooldown is None: if cooldown is None:
try: try:
@ -294,17 +291,18 @@ class CustomCommands(commands.Cog):
except NotFound: except NotFound:
await ctx.send( await ctx.send(
_("That command doesn't exist. Use `{command}` to add it.").format( _("That command doesn't exist. Use `{command}` to add it.").format(
command="{}customcom add".format(ctx.prefix) command="{}customcom create".format(ctx.prefix)
) )
) )
@customcom.command(name="delete") @customcom.command(name="delete")
@checks.mod_or_permissions(administrator=True) @checks.mod_or_permissions(administrator=True)
async def cc_delete(self, ctx, command: str.lower): async def cc_delete(self, ctx, command: str.lower):
"""Deletes a custom command """Delete a custom command
.
Example: Example:
[p]customcom delete yourcommand""" - `[p]customcom delete yourcommand`
"""
try: try:
await self.commandobj.delete(ctx=ctx, command=command) await self.commandobj.delete(ctx=ctx, command=command)
await ctx.send(_("Custom command successfully deleted.")) await ctx.send(_("Custom command successfully deleted."))
@ -314,18 +312,20 @@ class CustomCommands(commands.Cog):
@customcom.command(name="edit") @customcom.command(name="edit")
@checks.mod_or_permissions(administrator=True) @checks.mod_or_permissions(administrator=True)
async def cc_edit(self, ctx, command: str.lower, *, text: str = None): async def cc_edit(self, ctx, command: str.lower, *, text: str = None):
"""Edits a custom command's response """Edit a custom command.
Example: Example:
[p]customcom edit yourcommand Text you want - `[p]customcom edit yourcommand Text you want`
""" """
command = command.lower()
try: try:
await self.commandobj.edit(ctx=ctx, command=command, response=text) await self.commandobj.edit(ctx=ctx, command=command, response=text)
await ctx.send(_("Custom command successfully edited.")) await ctx.send(_("Custom command successfully edited."))
except NotFound: except NotFound:
await ctx.send( await ctx.send(
_("That command doesn't exist. Use `{}` to add it.").format( _("That command doesn't exist. Use `{command}` to add it.").format(
"{}customcom add".format(ctx.prefix) command="{}customcom create".format(ctx.prefix)
) )
) )
except ArgParseError as e: except ArgParseError as e:
@ -333,7 +333,7 @@ class CustomCommands(commands.Cog):
@customcom.command(name="list") @customcom.command(name="list")
async def cc_list(self, ctx): async def cc_list(self, ctx):
"""Shows custom commands list""" """List all available custom commands."""
response = await CommandObj.get_commands(self.config.guild(ctx.guild)) response = await CommandObj.get_commands(self.config.guild(ctx.guild))
@ -342,7 +342,7 @@ class CustomCommands(commands.Cog):
_( _(
"There are no custom commands in this server." "There are no custom commands in this server."
" Use `{command}` to start adding some." " Use `{command}` to start adding some."
).format(command="{}customcom add".format(ctx.prefix)) ).format(command="{}customcom create".format(ctx.prefix))
) )
return return

View File

@ -13,9 +13,7 @@ _ = Translator("DataConverter", __file__)
@cog_i18n(_) @cog_i18n(_)
class DataConverter(commands.Cog): class DataConverter(commands.Cog):
""" """Import Red V2 data to your V3 instance."""
Cog for importing Red v2 Data
"""
def __init__(self, bot: Red): def __init__(self, bot: Red):
super().__init__() super().__init__()
@ -24,13 +22,10 @@ class DataConverter(commands.Cog):
@checks.is_owner() @checks.is_owner()
@commands.command(name="convertdata") @commands.command(name="convertdata")
async def dataconversioncommand(self, ctx: commands.Context, v2path: str): async def dataconversioncommand(self, ctx: commands.Context, v2path: str):
""" """Interactive prompt for importing data from Red V2.
Interactive prompt for importing data from Red v2
Takes the path where the v2 install is Takes the path where the V2 install is, and overwrites
values which have entries in both V2 and v3; use with caution.
Overwrites values which have entries in both v2 and v3,
use with caution.
""" """
resolver = SpecResolver(Path(v2path.strip())) resolver = SpecResolver(Path(v2path.strip()))
@ -54,7 +49,7 @@ class DataConverter(commands.Cog):
"message", check=MessagePredicate.same_context(ctx), timeout=60 "message", check=MessagePredicate.same_context(ctx), timeout=60
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:
return await ctx.send(_("Try this again when you are more ready")) return await ctx.send(_("Try this again when you are ready."))
else: else:
if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]: if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]:
return await ctx.tick() return await ctx.tick()
@ -72,7 +67,7 @@ class DataConverter(commands.Cog):
else: else:
return await ctx.send( return await ctx.send(
_( _(
"There isn't anything else I know how to convert here." "There isn't anything else I know how to convert here.\n"
"\nThere might be more things I can convert in the future." "There might be more things I can convert in the future."
) )
) )

View File

@ -1,11 +1,15 @@
import asyncio import asyncio
from redbot.core import commands from redbot.core import commands
from redbot.core.i18n import Translator
from redbot.core.utils.predicates import MessagePredicate from redbot.core.utils.predicates import MessagePredicate
__all__ = ["do_install_agreement"] __all__ = ["do_install_agreement"]
REPO_INSTALL_MSG = ( T_ = Translator("DownloaderChecks", __file__)
_ = lambda s: s
REPO_INSTALL_MSG = _(
"You're about to add a 3rd party repository. The creator of Red" "You're about to add a 3rd party repository. The creator of Red"
" and its community have no responsibility for any potential " " and its community have no responsibility for any potential "
"damage that the content of 3rd party repositories might cause." "damage that the content of 3rd party repositories might cause."
@ -14,6 +18,7 @@ REPO_INSTALL_MSG = (
"shown again until the next reboot.\n\nYou have **30** seconds" "shown again until the next reboot.\n\nYou have **30** seconds"
" to reply to this message." " to reply to this message."
) )
_ = T_
async def do_install_agreement(ctx: commands.Context): async def do_install_agreement(ctx: commands.Context):
@ -21,14 +26,14 @@ async def do_install_agreement(ctx: commands.Context):
if downloader is None or downloader.already_agreed: if downloader is None or downloader.already_agreed:
return True return True
await ctx.send(REPO_INSTALL_MSG) await ctx.send(T_(REPO_INSTALL_MSG))
try: try:
await ctx.bot.wait_for( await ctx.bot.wait_for(
"message", check=MessagePredicate.lower_equal_to("i agree", ctx), timeout=30 "message", check=MessagePredicate.lower_equal_to("i agree", ctx), timeout=30
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:
await ctx.send("Your response has timed out, please try again.") await ctx.send(_("Your response has timed out, please try again."))
return False return False
downloader.already_agreed = True downloader.already_agreed = True

View File

@ -8,10 +8,10 @@ class InstalledCog(Installable):
async def convert(cls, ctx: commands.Context, arg: str) -> Installable: async def convert(cls, ctx: commands.Context, arg: str) -> Installable:
downloader = ctx.bot.get_cog("Downloader") downloader = ctx.bot.get_cog("Downloader")
if downloader is None: if downloader is None:
raise commands.CommandError("Downloader not loaded.") raise commands.CommandError(_("No Downloader cog found."))
cog = discord.utils.get(await downloader.installed_cogs(), name=arg) cog = discord.utils.get(await downloader.installed_cogs(), name=arg)
if cog is None: if cog is None:
raise commands.BadArgument("That cog is not installed") raise commands.BadArgument(_("That cog is not installed"))
return cog return cog

View File

@ -8,7 +8,7 @@ from sys import path as syspath
from typing import Tuple, Union, Iterable from typing import Tuple, Union, Iterable
import discord import discord
from redbot.core import checks, commands, Config from redbot.core import checks, commands, Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path from redbot.core.data_manager import cog_data_path
from redbot.core.i18n import Translator, cog_i18n from redbot.core.i18n import Translator, cog_i18n
@ -193,9 +193,7 @@ class Downloader(commands.Cog):
@commands.command() @commands.command()
@checks.is_owner() @checks.is_owner()
async def pipinstall(self, ctx, *deps: str): async def pipinstall(self, ctx, *deps: str):
""" """Install a group of dependencies using pip."""
Installs a group of dependencies using pip.
"""
repo = Repo("", "", "", Path.cwd(), loop=ctx.bot.loop) repo = Repo("", "", "", Path.cwd(), loop=ctx.bot.loop)
success = await repo.install_raw_requirements(deps, self.LIB_PATH) success = await repo.install_raw_requirements(deps, self.LIB_PATH)
@ -212,18 +210,15 @@ class Downloader(commands.Cog):
@commands.group() @commands.group()
@checks.is_owner() @checks.is_owner()
async def repo(self, ctx): async def repo(self, ctx):
""" """Repo management commands."""
Command group for managing Downloader repos.
"""
pass pass
@repo.command(name="add") @repo.command(name="add")
async def _repo_add(self, ctx, name: str, repo_url: str, branch: str = None): async def _repo_add(self, ctx, name: str, repo_url: str, branch: str = None):
""" """Add a new repo.
Add a new repo to Downloader.
Name can only contain characters A-z, numbers and underscore The name can only contain characters A-z, numbers and underscores.
Branch will default to master if not specified The branch will default to master if not specified.
""" """
agreed = await do_install_agreement(ctx) agreed = await do_install_agreement(ctx)
if not agreed: if not agreed:
@ -246,11 +241,9 @@ class Downloader(commands.Cog):
if repo.install_msg is not None: if repo.install_msg is not None:
await ctx.send(repo.install_msg.replace("[p]", ctx.prefix)) await ctx.send(repo.install_msg.replace("[p]", ctx.prefix))
@repo.command(name="delete") @repo.command(name="delete", aliases=["remove"])
async def _repo_del(self, ctx, repo_name: Repo): async def _repo_del(self, ctx, repo_name: Repo):
""" """Remove a repo and its files."""
Removes a repo from Downloader and its' files.
"""
await self._repo_manager.delete_repo(repo_name.name) await self._repo_manager.delete_repo(repo_name.name)
await ctx.send( await ctx.send(
@ -259,9 +252,7 @@ class Downloader(commands.Cog):
@repo.command(name="list") @repo.command(name="list")
async def _repo_list(self, ctx): async def _repo_list(self, ctx):
""" """List all installed repos."""
Lists all installed repos.
"""
repos = self._repo_manager.get_all_repo_names() repos = self._repo_manager.get_all_repo_names()
repos = sorted(repos, key=str.lower) repos = sorted(repos, key=str.lower)
joined = _("Installed Repos:\n\n") joined = _("Installed Repos:\n\n")
@ -274,11 +265,9 @@ class Downloader(commands.Cog):
@repo.command(name="info") @repo.command(name="info")
async def _repo_info(self, ctx, repo_name: Repo): async def _repo_info(self, ctx, repo_name: Repo):
""" """Show information about a repo."""
Lists information about a single repo
"""
if repo_name is None: if repo_name is None:
await ctx.send(_("There is no repo `{repo_name}`").format(repo_name=repo_name.name)) await ctx.send(_("Repo `{repo_name}` not found.").format(repo_name=repo_name.name))
return return
msg = _("Information on {repo_name}:\n{description}").format( msg = _("Information on {repo_name}:\n{description}").format(
@ -289,28 +278,24 @@ class Downloader(commands.Cog):
@commands.group() @commands.group()
@checks.is_owner() @checks.is_owner()
async def cog(self, ctx): async def cog(self, ctx):
""" """Cog installation management commands."""
Command group for managing installable Cogs.
"""
pass pass
@cog.command(name="install") @cog.command(name="install")
async def _cog_install(self, ctx, repo_name: Repo, cog_name: str): async def _cog_install(self, ctx, repo_name: Repo, cog_name: str):
""" """Install a cog from the given repo."""
Installs a cog from the given repo. cog: Installable = discord.utils.get(repo_name.available_cogs, name=cog_name)
"""
cog = discord.utils.get(repo_name.available_cogs, name=cog_name) # type: Installable
if cog is None: if cog is None:
await ctx.send( await ctx.send(
_( _(
"Error, there is no cog by the name of `{cog_name}` in the `{repo_name}` repo." "Error: there is no cog by the name of `{cog_name}` in the `{repo_name}` repo."
).format(cog_name=cog_name, repo_name=repo_name.name) ).format(cog_name=cog_name, repo_name=repo_name.name)
) )
return return
elif cog.min_python_version > sys.version_info: elif cog.min_python_version > sys.version_info:
await ctx.send( await ctx.send(
_("This cog requires at least python version {}, aborting install.").format( _("This cog requires at least python version {version}, aborting install.").format(
".".join([str(n) for n in cog.min_python_version]) version=".".join([str(n) for n in cog.min_python_version])
) )
) )
return return
@ -329,15 +314,16 @@ class Downloader(commands.Cog):
await repo_name.install_libraries(self.SHAREDLIB_PATH) await repo_name.install_libraries(self.SHAREDLIB_PATH)
await ctx.send(_("`{cog_name}` cog successfully installed.").format(cog_name=cog_name)) await ctx.send(_("Cog `{cog_name}` successfully installed.").format(cog_name=cog_name))
if cog.install_msg is not None: if cog.install_msg is not None:
await ctx.send(cog.install_msg.replace("[p]", ctx.prefix)) await ctx.send(cog.install_msg.replace("[p]", ctx.prefix))
@cog.command(name="uninstall") @cog.command(name="uninstall")
async def _cog_uninstall(self, ctx, cog_name: InstalledCog): async def _cog_uninstall(self, ctx, cog_name: InstalledCog):
""" """Uninstall a cog.
Allows you to uninstall cogs that were previously installed
through Downloader. You may only uninstall cogs which were previously installed
by Downloader.
""" """
# noinspection PyUnresolvedReferences,PyProtectedMember # noinspection PyUnresolvedReferences,PyProtectedMember
real_name = cog_name.name real_name = cog_name.name
@ -348,7 +334,7 @@ class Downloader(commands.Cog):
# noinspection PyTypeChecker # noinspection PyTypeChecker
await self._remove_from_installed(cog_name) await self._remove_from_installed(cog_name)
await ctx.send( await ctx.send(
_("`{real_name}` was successfully removed.").format(real_name=real_name) _("Cog `{cog_name}` was successfully uninstalled.").format(cog_name=real_name)
) )
else: else:
await ctx.send( await ctx.send(
@ -356,14 +342,14 @@ class Downloader(commands.Cog):
"That cog was installed but can no longer" "That cog was installed but can no longer"
" be located. You may need to remove it's" " be located. You may need to remove it's"
" files manually if it is still usable." " files manually if it is still usable."
) " Also make sure you've unloaded the cog"
" with `{prefix}unload {cog_name}`."
).format(cog_name=real_name)
) )
@cog.command(name="update") @cog.command(name="update")
async def _cog_update(self, ctx, cog_name: InstalledCog = None): async def _cog_update(self, ctx, cog_name: InstalledCog = None):
""" """Update all cogs, or one of your choosing."""
Updates all cogs or one of your choosing.
"""
installed_cogs = set(await self.installed_cogs()) installed_cogs = set(await self.installed_cogs())
async with ctx.typing(): async with ctx.typing():
@ -426,9 +412,7 @@ class Downloader(commands.Cog):
@cog.command(name="list") @cog.command(name="list")
async def _cog_list(self, ctx, repo_name: Repo): async def _cog_list(self, ctx, repo_name: Repo):
""" """List all available cogs from a single repo."""
Lists all available cogs from a single repo.
"""
installed = await self.installed_cogs() installed = await self.installed_cogs()
installed_str = "" installed_str = ""
if installed: if installed:
@ -453,9 +437,7 @@ class Downloader(commands.Cog):
@cog.command(name="info") @cog.command(name="info")
async def _cog_info(self, ctx, repo_name: Repo, cog_name: str): async def _cog_info(self, ctx, repo_name: Repo, cog_name: str):
""" """List information about a single cog."""
Lists information about a single cog.
"""
cog = discord.utils.get(repo_name.available_cogs, name=cog_name) cog = discord.utils.get(repo_name.available_cogs, name=cog_name)
if cog is None: if cog is None:
await ctx.send( await ctx.send(
@ -549,9 +531,9 @@ class Downloader(commands.Cog):
@commands.command() @commands.command()
async def findcog(self, ctx: commands.Context, command_name: str): async def findcog(self, ctx: commands.Context, command_name: str):
""" """Find which cog a command comes from.
Figures out which cog a command comes from. Only works with loaded
cogs. This will only work with loaded cogs.
""" """
command = ctx.bot.all_commands.get(command_name) command = ctx.bot.all_commands.get(command_name)

View File

@ -12,11 +12,15 @@ from typing import Tuple, MutableMapping, Union, Optional
from redbot.core import data_manager, commands from redbot.core import data_manager, commands
from redbot.core.utils import safe_delete from redbot.core.utils import safe_delete
from redbot.core.i18n import Translator
from . import errors from . import errors
from .installable import Installable, InstallableType from .installable import Installable, InstallableType
from .json_mixins import RepoJSONMixin from .json_mixins import RepoJSONMixin
from .log import log from .log import log
_ = Translator("RepoManager", __file__)
class Repo(RepoJSONMixin): class Repo(RepoJSONMixin):
GIT_CLONE = "git clone --recurse-submodules -b {branch} {url} {folder}" GIT_CLONE = "git clone --recurse-submodules -b {branch} {url} {folder}"
@ -64,13 +68,15 @@ class Repo(RepoJSONMixin):
async def convert(cls, ctx: commands.Context, argument: str): async def convert(cls, ctx: commands.Context, argument: str):
downloader_cog = ctx.bot.get_cog("Downloader") downloader_cog = ctx.bot.get_cog("Downloader")
if downloader_cog is None: if downloader_cog is None:
raise commands.CommandError("No Downloader cog found.") raise commands.CommandError(_("No Downloader cog found."))
# noinspection PyProtectedMember # noinspection PyProtectedMember
repo_manager = downloader_cog._repo_manager repo_manager = downloader_cog._repo_manager
poss_repo = repo_manager.get_repo(argument) poss_repo = repo_manager.get_repo(argument)
if poss_repo is None: if poss_repo is None:
raise commands.BadArgument("Repo by the name {} does not exist.".format(argument)) raise commands.BadArgument(
_('Repo by the name "{repo_name}" does not exist.').format(repo_name=argument)
)
return poss_repo return poss_repo
def _existing_git_repo(self) -> (bool, Path): def _existing_git_repo(self) -> (bool, Path):