Skip to content

Commit

Permalink
more helps for those flag arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Fallen-Breath committed Dec 8, 2023
1 parent 22fe35a commit fd76652
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 33 deletions.
37 changes: 30 additions & 7 deletions lang/en_us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,13 @@ prime_backup:
§7{prefix}§r: Display the current welcome page
§7{prefix} help §e[<what>]§r: Display help message of all / given command
§7{prefix} make §e[<comment>]§r: Make a backup. §e<comment>§r is an optional comment message
§7{prefix} back §6[<backup_id>]§r: Restore the world to the given backup. Default: latest backup
§7{prefix} back §6[<backup_id>]§r: Restore to the given backup. See §7{prefix} help back§r for detailed help
§7{prefix} list [...]§r: List backups with given filters. See §7{prefix} help list§r for detailed help
§7{prefix} show §6<backup_id>§r: Show detailed information of the given backup
§7{prefix} rename §6<backup_id>§r §e<comment>§r: Modify the comment of the given backup
§7{prefix} delete §6<backup_id>§r: Delete the given backup
§7{prefix} delete §6<backup_id> [<backup_id>...]§r: Delete the given backup. You can enter multiple backup IDs
§7{prefix} delete_range §6<backup_id_range>§r: Delete backups inside the given ID range
§7{prefix} export §6<backup_id> §3[<export_format>]§r: Export the given backup to the §3export§r folder
§7{prefix} export §6<backup_id> §7[...]§r: Export the given backup. See §7{prefix} help export§r for detailed help
§7{prefix} prune §6<backup_id>§r: Manually trigger a backup prune
§7{prefix} crontab §5<job_id> §7[...]§r: Crontab job operations. See §7{prefix} help crontab§r for help
§7{prefix} tag §6<backup_id> §7[...]§r: Tag operation on the given backup
Expand All @@ -199,15 +199,24 @@ prime_backup:
arguments:
title: '[Arguments]'
content: |-
§6<backup_id>§r: A positive integer, the unique identifier for a backup, e.g.: §612§r
§6<backup_id>§r: A positive integer, the unique ID for a backup, e.g.: §612§r
§6<backup_id_range>§r: An integer closed interval, e.g.: §63-12§r, §64~9§r, §64~§r, §64~§r, §6*§r
§3<export_format>§r: Available options: {export_formats}
other:
title: '[Others]'
nodes_with_help: 'Subcommands with detailed help: {}'
docs: 'Documentation: {}'
docs.hover: Click to open the url
node_help:
back: |-
§d[back Command Usage]§r
Restore the world to the given backup
§7{prefix} back §6[<backup_id>] §7[--flags]§r
§d[Arguments]§r
§3<backup_id>§r: The ID of the backup to restore. If not specified, the latest not pre-restore backup will be used
§d[Optional flags]§r
§7--confirm§r: Skip the confirm step and start the restore directly
§7--fail-soft§r: Skip files with export failure in the backup, so a single failure will not abort the export
§7--no-verify§r: Do not verify the exported file contents
crontab: |-
§d[crontab Command Usage]§r
Operate crontab jobs
Expand All @@ -233,6 +242,20 @@ prime_backup:
- §aall§r: Validate all of the above
database.scheduled_compact.on: 'Notes: With the current config, {name} will automatically prune the database every {interval}'
database.scheduled_compact.off: 'Notes: With the current config, scheduled database prune is disabled'
export: |-
§d[export Command Usage]§r
Export the given backup to the §3export§r folder
§7{prefix} export §6<backup_id> §3[<export_format>] §7[--flags]§r
§d[Arguments]§r
§3<export_format>§r: Available options: {export_formats}. Use §3tar§r format if not specified
§d[Optional flags]§r
§7--overwrite§r: Overwrites existing exported backup. By default, no export will be made if the output file exists
§7--fail-soft§r: Skip files with export failure in the backup, so a single failure will not abort the export
§7--no-verify§r: Do not verify the exported file contents
§d[Examples]§r
§7{prefix} export 12§r: Use the default §3tar§r format to export backup §612§r
§7{prefix} export 12 tar_gz§r: Use the §tar_gz§r format to export backup §612§r
§7{prefix} export 12 tar --fail-soft --no-verify§r: Export backup §612§r with best effort
list: |-
§d[list Command Usage]§r
List backups with given filters
Expand All @@ -242,11 +265,11 @@ prime_backup:
§7--author §e<author>§r: Show backup created by the given author only
§7--start §b<start_date>§r: Show backup after the given date only
§7--end §b<end_date>§r: Show backup before the given date only
§7--all§r: Show all backups. By default, hidden backups and pre-restore backups will not be shown
§7--size§r: Show backup sizes
§7--flags§r: Show backup flags, based on the tags of the backup
§7--all§r: Show all backups. By default, hidden backups and pre-restore backups will not be shown
§d[Examples]§r
§7{prefix} list --all§r
§7{prefix} list --all --flags§r
§7{prefix} list --start 20231130 --size§r
§7{prefix} list 3 --per-page 20§r
tag: |-
Expand Down
39 changes: 31 additions & 8 deletions lang/zh_cn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,13 @@ prime_backup:
§7{prefix}§r: 展示当前这个欢迎界面
§7{prefix} help §e[<指令>]§r: 展示全部指令/给定指令的详细帮助
§7{prefix} make §e[<注释>]§r: 创建一个备份。§e<注释>§r为可选注释
§7{prefix} back §6[<备份ID>]§r: 回档至给定备份。若未指定备份ID, 则使用最新的备份
§7{prefix} back §6[<备份ID>]§r: 回档至给定备份。详见§7{prefix} help back§r
§7{prefix} list [...]§r: 列出备份, 展示备份列表。详见§7{prefix} help list§r
§7{prefix} show §6<备份ID>§r: 展示给定备份的详细信息
§7{prefix} rename §6<备份ID>§r §e<新注释>§r: 修改给定备份的注释
§7{prefix} delete §6<备份ID>§r: 删除给定备份
§7{prefix} delete_range §6<备份ID范围>§r: 删除给定ID范围的备份。参数例子: §62-7§r、§69-§r、§6*§r
§7{prefix} export §6<备份ID> §3[<导出格式>]§r: 以给定格式导出给定备份到§3export§r文件夹
§7{prefix} delete §6<备份ID> [<备份ID>...]§r: 删除给定备份。可输入多个备份ID
§7{prefix} delete_range §6<备份ID范围>§r: 删除给定ID范围的备份
§7{prefix} export §6<备份ID> §7[...]§r: 给导出给定备份到文件。详见§7{prefix} help export§r
§7{prefix} prune §6<备份ID>§r: 手动触发一次备份裁剪
§7{prefix} crontab §5<任务ID> §7[...]§r: 操作定时任务。详见§7{prefix} help crontab§r
§7{prefix} tag §6<备份ID> §7[...]§r: 操作给定备份的标签。详见§7{prefix} help tag§r
Expand All @@ -199,15 +199,24 @@ prime_backup:
arguments:
title: 【参数帮助】
content: |-
§6<备份ID>§r: 一个正整数, 备份的唯一标识符, 如: §612§r
§6<备份ID>§r: 一个正整数, 备份的唯一ID, 如: §612§r
§6<备份ID范围>§r: 一个整数闭区间, 如: §63-12§r, §64~9§r, §64~§r, §64~§r, §6*§r
§3<导出格式>§r: 可用选项: {export_formats}
other:
title: 【其它】
nodes_with_help: '含详细帮助页的子命令: {}'
docs: '文档: {}'
docs.hover: 点击以打开链接
node_help:
back: |-
§d【back指令帮助】§r
§7{prefix} back §6[<备份ID>] §7[--可选参数]§r
回档至给定备份
§d【参数帮助】§r
§6<备份ID>§r: 备份的ID。若未给出,则使用非回档前自动备份的最新的备份
§d【可选参数】§r
§7--confirm§r: 跳过确认步骤,直接开始回档
§7--fail-soft§r: 在导出过程中跳过导出失败的文件,因此单个文件的失败不会导致整个导出的失败
§7--no-verify§r: 不校验导出文件的内容
crontab: |-
§d【crontab指令帮助】§r
操作定时任务
Expand All @@ -233,6 +242,20 @@ prime_backup:
- §aall§r: 验证上述全部
database.scheduled_compact.on: '注意: 在当前配置下,{name}每{interval}会自动执行一次数据库精简操作'
database.scheduled_compact.off: '注意: 在当前配置下,定时数据库精简操作已被禁用'
export: |-
§d【export指令帮助】§r
§7{prefix} export §6<备份ID> §3[<导出格式>] §7[--可选参数]§r
以给定格式导出给定备份到§3export§r文件夹
§d【参数帮助】§r
§3<导出格式>§r: 可用选项: {export_formats}。若未指定,则使用§3tar§r格式
§d【可选参数】§r
§7--overwrite§r: 覆盖已存在的备份导出文件。默认情况下,若输出文件已存在则不导出
§7--fail-soft§r: 在导出过程中跳过导出失败的文件,因此单个文件的失败不会导致整个导出的失败
§7--no-verify§r: 不校验导出文件的内容
§d【例子】§r
§7{prefix} export 12§r: 使用默认的§3tar§r格式导出备份§612§r
§7{prefix} export 12 tar_gz§r: 使用§3tar_gz§r格式导出备份§612§r
§7{prefix} export 12 tar --fail-soft --no-verify§r: 使用§3tar§r格式尽力而为地导出备份§612§r
list: |-
§d【list指令帮助】§r
列出备份, 展示备份列表
Expand All @@ -242,11 +265,11 @@ prime_backup:
§7--author §e<作者>§r: 仅列出给定作者的备份
§7--start §b<起始日期>§r: 仅列出给定日期之后的备份
§7--end §b<结束日期>§r: 仅列出给定日期之前的备份
§7--all§r: 展示所有的备份。默认情况下, 隐藏备份、回档前备份不会被展示
§7--size§r: 展示备份原始大小。这将增加任务耗时
§7--flags§r: 展示备份标志位, 这些标志位是基于备份的标签生成的
§7--all§r: 展示所有的备份。默认情况下, 隐藏备份、回档前备份不会被展示
§d【例子】§r
§7{prefix} list --all§r
§7{prefix} list --all --flags§r
§7{prefix} list --start 20231130 --size§r
§7{prefix} list 3 --per-page 20§r
tag: |-
Expand Down
13 changes: 9 additions & 4 deletions prime_backup/action/export_backup_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ def _i_am_root():
class ExportBackupToDirectoryAction(_ExportBackupActionBase):
def __init__(
self, backup_id: int, output_path: Path, *,
fail_soft: bool = False, delete_existing: bool = True,
fail_soft: bool = False, verify_blob: bool = True,
delete_existing: bool = True,
child_to_export: Optional[Path] = None, recursively_export_child: bool = False,
):
super().__init__(backup_id, output_path, fail_soft=fail_soft)
super().__init__(backup_id, output_path, fail_soft=fail_soft, verify_blob=verify_blob)
self.delete_existing = delete_existing
self.child_to_export = child_to_export
self.recursively_export_child = recursively_export_child
Expand Down Expand Up @@ -192,8 +193,11 @@ def _export_backup(self, session, backup: schema.Backup) -> ExportFailures:


class ExportBackupToTarAction(_ExportBackupActionBase):
def __init__(self, backup_id: int, output_path: Path, tar_format: TarFormat, *, fail_soft: bool = False):
super().__init__(backup_id, output_path, fail_soft=fail_soft)
def __init__(
self, backup_id: int, output_path: Path, tar_format: TarFormat, *,
fail_soft: bool = False, verify_blob: bool = True,
):
super().__init__(backup_id, output_path, fail_soft=fail_soft, verify_blob=verify_blob)
self.tar_format = tar_format

@contextlib.contextmanager
Expand Down Expand Up @@ -228,6 +232,7 @@ def __export_file(self, tar: tarfile.TarFile, file: schema.File):
reader = None
tar.addfile(tarinfo=info, fileobj=stream)
if reader is not None:
# notes: the read len is always <= info.size
self._verify_exported_blob(file, reader.get_read_len(), reader.get_hash())

elif stat.S_ISDIR(file.mode):
Expand Down
7 changes: 5 additions & 2 deletions prime_backup/cli/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ def cmd_export(self):

backup = GetBackupAction(self.args.backup_id).run()
logger.info('Exporting backup #{} to {}, format {}'.format(backup.id, str(output_path.as_posix()), fmt.name))
kwargs = dict(fail_soft=self.args.fail_soft, verify_blob=not self.args.no_verify)
if isinstance(fmt.value, TarFormat):
act = ExportBackupToTarAction(backup.id, output_path, fmt.value)
act = ExportBackupToTarAction(backup.id, output_path, fmt.value, **kwargs)
else:
act = ExportBackupToZipAction(backup.id, output_path)
act = ExportBackupToZipAction(backup.id, output_path, **kwargs)

failures = act.run()
if len(failures) > 0:
Expand Down Expand Up @@ -204,6 +205,8 @@ def entrypoint(cls):
parser_export.add_argument('backup_id', type=int, help='The ID of the backup to export')
parser_export.add_argument('output', help='The output file name of the exported backup. Example: my_backup.tar')
parser_export.add_argument('-f', '--format', help='The format of the output file. If not given, attempt to infer from the output file name. Options: {}'.format(enum_options(StandaloneBackupFormat)))
parser_export.add_argument('--fail-soft', action='store_true', help='Skip files with export failure in the backup, so a single failure will not abort the export')
parser_export.add_argument('--no-verify', action='store_true', help='Do not verify the exported file contents')

desc = 'Extract a single file from a backup'
parser_extract = subparsers.add_parser('extract', help=desc, description=desc)
Expand Down
13 changes: 11 additions & 2 deletions prime_backup/mcdr/command/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ def callback(_, err):
def cmd_back(self, source: CommandSource, context: CommandContext):
needs_confirm = context.get('confirm', 0) == 0
fail_soft = context.get('fail_soft', 0) > 0
verify_blob = context.get('no_verify', 0) == 0
backup_id = context.get('backup_id')
self.task_manager.add_task(RestoreBackupTask(source, backup_id, needs_confirm=needs_confirm, fail_soft=fail_soft))
self.task_manager.add_task(RestoreBackupTask(source, backup_id, needs_confirm=needs_confirm, fail_soft=fail_soft, verify_blob=verify_blob))

def cmd_list(self, source: CommandSource, context: CommandContext):
page = context.get('page', 1)
Expand Down Expand Up @@ -129,7 +130,9 @@ def cmd_export(self, source: CommandSource, context: CommandContext):
backup_id = context['backup_id']
export_format = context.get('export_format', StandaloneBackupFormat.tar)
fail_soft = context.get('fail_soft', 0) > 0
self.task_manager.add_task(ExportBackupTask(source, backup_id, export_format, fail_soft=fail_soft))
verify_blob = context.get('no_verify', 0) == 0
overwrite_existing = context.get('overwrite', 0) > 0
self.task_manager.add_task(ExportBackupTask(source, backup_id, export_format, fail_soft=fail_soft, verify_blob=verify_blob, overwrite_existing=overwrite_existing))

def cmd_crontab_show(self, source: CommandSource, context: CommandContext):
job_id = context.get('job_id')
Expand Down Expand Up @@ -255,13 +258,17 @@ def set_confirm_able(node: AbstractNode):
def set_fail_soft_able(node: AbstractNode):
node.then(CountingLiteral('--fail-soft', 'fail_soft').redirects(node))

def set_no_verify_able(node: AbstractNode):
node.then(CountingLiteral('--no-verify', 'no_verify').redirects(node))

def make_back_cmd() -> Literal:
node_sc = create_subcommand('back')
node_bid = create_backup_id()
node_sc.then(node_bid)
for node in [node_sc, node_bid]:
set_confirm_able(node)
set_fail_soft_able(node)
set_no_verify_able(node)
node.runs(self.cmd_back)
return node_sc

Expand All @@ -281,6 +288,8 @@ def make_export_cmd() -> Literal:

for node in [node_bid, node_ef]:
set_fail_soft_able(node)
set_no_verify_able(node)
node.then(CountingLiteral('--overwrite', 'overwrite').redirects(node))
node.runs(self.cmd_export)

return node_sc
Expand Down
11 changes: 8 additions & 3 deletions prime_backup/mcdr/task/backup/export_backup_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ def _sanitize_file_name(s: str, max_length: int = 64):


class ExportBackupTask(OperationTask[None]):
def __init__(self, source: CommandSource, backup_id: int, export_format: StandaloneBackupFormat, fail_soft: bool):
def __init__(
self, source: CommandSource, backup_id: int, export_format: StandaloneBackupFormat, *,
fail_soft: bool, verify_blob: bool, overwrite_existing: bool,
):
super().__init__(source)
self.backup_id = backup_id
self.export_format = export_format
self.fail_soft = fail_soft
self.verify_blob = verify_blob
self.overwrite_existing = overwrite_existing

@property
def id(self) -> str:
Expand All @@ -41,7 +46,7 @@ def make_output(extension: str) -> Path:
return self.config.storage_path / 'export' / name

efv = self.export_format.value
kwargs = dict(fail_soft=self.fail_soft)
kwargs = dict(fail_soft=self.fail_soft, verify_blob=self.verify_blob)
if isinstance(efv, TarFormat):
path = make_output(efv.value.extension)
action = ExportBackupToTarAction(self.backup_id, path, efv, **kwargs)
Expand All @@ -51,7 +56,7 @@ def make_output(extension: str) -> Path:
else:
raise TypeError(efv)

if path.exists():
if path.exists() and not self.overwrite_existing:
self.reply(self.tr('already_exists', TextComponents.file_path(path)))
return

Expand Down
7 changes: 4 additions & 3 deletions prime_backup/mcdr/task/backup/restore_backup_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@


class RestoreBackupTask(OperationTask[None]):
def __init__(self, source: CommandSource, backup_id: Optional[int] = None, needs_confirm: bool = True, fail_soft: bool = False):
def __init__(self, source: CommandSource, backup_id: Optional[int] = None, needs_confirm: bool = True, fail_soft: bool = False, verify_blob: bool = True):
super().__init__(source)
self.backup_id = backup_id
self.needs_confirm = needs_confirm
self.fail_soft = fail_soft
self.verify_blob = verify_blob

@property
def id(self) -> str:
Expand Down Expand Up @@ -83,8 +84,8 @@ def run(self):
).run()
cost_backup = timer.get_and_restart()

self.logger.info('Restoring backup (fail-soft={})'.format(self.fail_soft))
ExportBackupToDirectoryAction(backup.id, self.config.source_path, delete_existing=True, fail_soft=self.fail_soft).run()
self.logger.info('Restoring backup (fail_soft={}, verify_blob={})'.format(self.fail_soft, self.no_verify))
ExportBackupToDirectoryAction(backup.id, self.config.source_path, delete_existing=True, fail_soft=self.fail_soft, verify_blob=self.verify_blob).run()
cost_restore = timer.get_and_restart()

self.logger.info('Restore done, cost {}s (backup {}s, restore {}s), starting the server'.format(
Expand Down
10 changes: 6 additions & 4 deletions prime_backup/mcdr/task/general/show_help_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

class ShowHelpTask(ImmediateTask[None]):
COMMANDS_WITH_DETAILED_HELP = [
'back',
'crontab',
'database',
'export',
'list',
'tag',
]
Expand Down Expand Up @@ -45,13 +47,10 @@ def __has_permission(self, literal: str) -> bool:
def run(self) -> None:
with self.source.preferred_language_context():
if self.what is None:
from prime_backup.types.standalone_backup_format import StandaloneBackupFormat
t_export_formats = ', '.join([f'§3{ebf.name}§r' for ebf in StandaloneBackupFormat])

self.reply(self.tr('commands.title').set_color(TextColors.help_title))
self.__reply_help(self.tr('commands.content', prefix=self.__cmd_prefix), True)
self.reply(self.tr('arguments.title').set_color(TextColors.help_title))
self.__reply_help(self.tr('arguments.content', export_formats=t_export_formats))
self.__reply_help(self.tr('arguments.content'))

self.reply(self.tr('other.title').set_color(TextColors.help_title))
self.reply(self.tr(
Expand Down Expand Up @@ -94,6 +93,9 @@ def run(self) -> None:
)
else:
kwargs['scheduled_compact_notes'] = self.tr(f'node_help.{self.what}.scheduled_compact.off')
elif self.what == 'export':
from prime_backup.types.standalone_backup_format import StandaloneBackupFormat
kwargs['export_formats'] = ', '.join([f'§3{ebf.name}§r' for ebf in StandaloneBackupFormat])

self.__reply_help(self.tr(f'node_help.{self.what}', **kwargs))

Expand Down

0 comments on commit fd76652

Please sign in to comment.