Skip to content

Commit 7e3cec8

Browse files
committed
suggest file path in backup/fileset
1 parent ca2aa53 commit 7e3cec8

6 files changed

Lines changed: 180 additions & 26 deletions

File tree

lang/en_us.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ prime_backup:
186186
done: 'Deleted file {1} in backup {0}, freed {2}'
187187
db_get_fileset_ids:
188188
name: get fileset id list
189+
db_get_backup_file_paths:
190+
name: get backup file path list
191+
db_get_fileset_file_paths:
192+
name: get fileset file path list
189193
db_inspect_backup:
190194
name: inspect backup
191195
title: 'Backup {}'

lang/zh_cn.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ prime_backup:
186186
done: '已删除备份{0}中的文件{1}, 共释放{2}'
187187
db_get_fileset_ids:
188188
name: 获取文件集ID列表
189+
db_get_backup_file_paths:
190+
name: 获取备份的文件路径列表
191+
db_get_fileset_file_paths:
192+
name: 获取文件集的文件路径列表
189193
db_inspect_backup:
190194
name: 审查备份
191195
title: '备份{}'

prime_backup/mcdr/command/commands.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from prime_backup.compressors import CompressMethod
1212
from prime_backup.config.config import Config
1313
from prime_backup.mcdr.command.nodes import DateNode, IdRangeNode, HexStringNode, JsonObjectNode, BackupIdNode, MultiBackupIdNode
14-
from prime_backup.mcdr.command.value_suggestor import BackupIdSuggestor, FilesetIdSuggestor
14+
from prime_backup.mcdr.command.value_suggestor import ValueSuggesters
1515
from prime_backup.mcdr.crontab_job import CrontabJobEvent, CrontabJobId
1616
from prime_backup.mcdr.crontab_manager import CrontabManager
1717
from prime_backup.mcdr.task.backup.create_backup_task import CreateBackupTask
@@ -62,8 +62,7 @@ def __init__(self, server: PluginServerInterface, task_manager: TaskManager, cro
6262
self.server = server
6363
self.task_manager = task_manager
6464
self.crontab_manager = crontab_manager
65-
self.backup_id_suggestor = BackupIdSuggestor(task_manager)
66-
self.fileset_id_suggestor = FilesetIdSuggestor(task_manager)
65+
self.value_suggesters = ValueSuggesters(task_manager)
6766
self.config = Config.get()
6867
self.__state = CommandManagerState.INITIAL
6968
self.__root_node = Literal(self.config.command.prefix)
@@ -94,13 +93,13 @@ def backup_id_consumer(backup_id: int):
9493

9594
def cmd_db_inspect_backup_file(self, source: CommandSource, context: CommandContext):
9695
def backup_id_consumer(backup_id: int):
97-
file_path = context['file_path']
96+
file_path = context['backup_file_path']
9897
self.task_manager.add_task(InspectBackupFileTask(source, backup_id, file_path))
9998
self.transform_backup_id(source, context['backup_id'], backup_id_consumer)
10099

101100
def cmd_db_inspect_fileset_file(self, source: CommandSource, context: CommandContext):
102101
fileset_id = context['fileset_id']
103-
file_path = context['file_path']
102+
file_path = context['fileset_file_path']
104103
self.task_manager.add_task(InspectFilesetFileTask(source, fileset_id, file_path))
105104

106105
def cmd_db_inspect_fileset(self, source: CommandSource, context: CommandContext):
@@ -113,7 +112,7 @@ def cmd_db_inspect_blob(self, source: CommandSource, context: CommandContext):
113112

114113
def cmd_db_delete_file(self, source: CommandSource, context: CommandContext):
115114
def backup_id_consumer(backup_id: int):
116-
file_path = context['file_path']
115+
file_path = context['backup_file_path']
117116
needs_confirm = context.get('confirm', 0) == 0
118117
recursive = context.get('recursive', 0) > 0
119118
self.task_manager.add_task(DeleteBackupFileTask(source, backup_id, file_path, needs_confirm=needs_confirm, recursive=recursive))
@@ -280,11 +279,17 @@ def backup_id_consumer(backup_id: int):
280279
def suggest_backup_id(self, source: CommandSource) -> List[str]:
281280
return [
282281
*BackupIdNode.get_command_suggestions(),
283-
*map(str, self.backup_id_suggestor.suggest(source)),
282+
*self.value_suggesters.suggest_backup_id(source),
284283
]
285284

286285
def suggest_fileset_id(self, source: CommandSource) -> List[str]:
287-
return [str(fileset_id) for fileset_id in self.fileset_id_suggestor.suggest(source)]
286+
return self.value_suggesters.suggest_fileset_id(source)
287+
288+
def suggest_backup_file_path(self, source: CommandSource, ctx: CommandContext) -> List[str]:
289+
return self.value_suggesters.suggest_backup_file_path(source, ctx['backup_id'])
290+
291+
def suggest_fileset_file_path(self, source: CommandSource, ctx: CommandContext) -> List[str]:
292+
return self.value_suggesters.suggest_fileset_file_path(source, ctx['fileset_id'])
288293

289294
def __transform_backup_id_impl(self, source: CommandSource, backup_id_raw: Union[str, List[str]], csm: Union[Callable[[int], Any], Callable[[List[int]], Any]]):
290295
if isinstance(backup_id_raw, str):
@@ -357,6 +362,12 @@ def create_backup_id(arg_name: str = 'backup_id', clazz: Type[ArgumentNode] = Ba
357362
def create_fileset_id(arg_name: str) -> ArgumentNode:
358363
return Integer(arg_name).suggests(self.suggest_fileset_id)
359364

365+
def create_backup_file_path(arg_name: str) -> ArgumentNode:
366+
return QuotableText(arg_name).suggests(self.suggest_backup_file_path)
367+
368+
def create_fileset_file_path(arg_name: str) -> ArgumentNode:
369+
return QuotableText(arg_name).suggests(self.suggest_fileset_file_path)
370+
360371
# --------------- simple commands ---------------
361372

362373
builder = SimpleCommandBuilder()
@@ -395,8 +406,8 @@ def create_fileset_id(arg_name: str) -> ArgumentNode:
395406
builder.command('database', lambda src: self.cmd_help(src, {'what': 'database'}))
396407
builder.command('database overview', self.cmd_db_overview)
397408
builder.command('database inspect backup <backup_id>', self.cmd_db_inspect_backup)
398-
builder.command('database inspect file <backup_id> <file_path>', self.cmd_db_inspect_backup_file)
399-
builder.command('database inspect file2 <fileset_id> <file_path>', self.cmd_db_inspect_fileset_file)
409+
builder.command('database inspect file <backup_id> <backup_file_path>', self.cmd_db_inspect_backup_file)
410+
builder.command('database inspect file2 <fileset_id> <fileset_file_path>', self.cmd_db_inspect_fileset_file)
400411
builder.command('database inspect fileset <fileset_id>', self.cmd_db_inspect_fileset)
401412
builder.command('database inspect blob <blob_hash>', self.cmd_db_inspect_blob)
402413
builder.command('database validate all', functools.partial(self.cmd_db_validate, parts=ValidatePart.all()))
@@ -408,10 +419,11 @@ def create_fileset_id(arg_name: str) -> ArgumentNode:
408419
builder.command('database prune', self.cmd_db_prune)
409420
builder.command('database migrate_compress_method <compress_method>', self.cmd_db_migrate_compress_method)
410421
builder.command('database migrate_hash_method <hash_method>', self.cmd_db_migrate_hash_method)
411-
# `database delete file <backup_id> <file_path>` is handled by `make_db_delete_file_cmd()` below
422+
# `database delete file <backup_id> <backup_file_path>` is handled by `make_db_delete_file_cmd()` below
412423

413-
builder.arg('file_path', QuotableText) # Notes: it's actually a redefine
414424
builder.arg('fileset_id', create_fileset_id) # not that necessary to provide suggestion here
425+
builder.arg('backup_file_path', create_backup_file_path) # not that necessary to provide suggestion here
426+
builder.arg('fileset_file_path', create_fileset_file_path) # not that necessary to provide suggestion here
415427
builder.arg('blob_hash', HexStringNode)
416428
builder.arg('compress_method', lambda n: Enumeration(n, CompressMethod))
417429
builder.arg('hash_method', lambda n: Enumeration(n, HashMethod))
@@ -541,7 +553,7 @@ def make_tag_cmd() -> Literal:
541553
def make_db_delete_file_cmd():
542554
__locate_node(['database']).then(Literal('delete').then(node_subcommand := Literal('file')))
543555
node_bid = create_backup_id()
544-
node_file_path = QuotableText('file_path').runs(self.cmd_db_delete_file)
556+
node_file_path = create_backup_file_path('backup_file_path').runs(self.cmd_db_delete_file)
545557
node_subcommand.then(node_bid)
546558
node_bid.then(node_file_path)
547559
for node in [node_bid, node_file_path]:

prime_backup/mcdr/command/value_suggestor.py

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,58 @@
33
from abc import abstractmethod, ABC
44
from typing import Optional, Generic, TypeVar, List
55

6-
from mcdreforged.api.all import CommandSource
6+
from mcdreforged.api.all import CommandSource, CommandContext
77
from typing_extensions import override
88

99
from prime_backup import logger
1010
from prime_backup.mcdr.task.backup.get_backup_ids_task import GetBackupIdsTask
1111
from prime_backup.mcdr.task.basic_task import LightTask
12+
from prime_backup.mcdr.task.db.get_backup_file_paths_task import GetBackupFilePathsTask
13+
from prime_backup.mcdr.task.db.get_fileset_file_paths_task import GetFilesetFilePathsTask
1214
from prime_backup.mcdr.task.db.get_fileset_ids_task import GetFilesetIdsTask
1315
from prime_backup.mcdr.task_manager import TaskManager
1416
from prime_backup.mcdr.task_queue import TaskQueue
17+
from prime_backup.utils import misc_utils
1518
from prime_backup.utils.waitable_value import WaitableValue
1619

1720
_T = TypeVar('_T')
21+
_P = TypeVar('_P')
1822

1923

20-
class ValueSuggestor(ABC, Generic[_T]):
24+
class ValueSuggestor(ABC, Generic[_T, _P]):
2125
def __init__(self, task_manager: TaskManager):
2226
self.task_manager = task_manager
2327
self.logger = logger.get()
2428
self.lock = threading.Lock()
2529
self.last_future: WaitableValue[_T] = WaitableValue()
26-
self.last_future.set(self._create_fallback())
2730
self.current_future: WaitableValue[_T] = WaitableValue()
28-
self.current_future.set(self._create_fallback())
31+
self.current_task_key: str = ''
2932
self.last_fetch_time = 0
33+
self.__reset()
3034

3135
@abstractmethod
3236
def _create_fallback(self) -> _T:
3337
...
3438

3539
@abstractmethod
36-
def _create_value_task(self, source: CommandSource) -> LightTask[_T]:
40+
def _create_value_task(self, source: CommandSource, arg: _P) -> LightTask[_T]:
41+
...
42+
43+
@abstractmethod
44+
def _compute_task_key(self, source: CommandSource, arg: _P) -> str:
3745
...
3846

39-
def request(self, source: CommandSource) -> WaitableValue[_T]:
47+
def __reset(self):
48+
self.last_future.set(self._create_fallback())
49+
self.current_future.set(self._create_fallback())
50+
51+
def request(self, source: CommandSource, arg: _P) -> WaitableValue[_T]:
4052
with self.lock:
53+
task_key = self._compute_task_key(source, arg)
54+
if task_key != self.current_task_key:
55+
self.__reset()
56+
self.current_task_key = task_key
57+
4158
if not self.current_future.is_set():
4259
return self.last_future
4360

@@ -54,7 +71,7 @@ def callback(result: Optional[_T], err: Optional[Exception]):
5471

5572
self.last_fetch_time = now
5673
wv = WaitableValue()
57-
task = self._create_value_task(source)
74+
task = self._create_value_task(source, arg)
5875
try:
5976
self.task_manager.add_task(task, callback, handle_tmo_err=False)
6077
except TaskQueue.TooManyOngoingTask:
@@ -64,28 +81,94 @@ def callback(result: Optional[_T], err: Optional[Exception]):
6481
self.current_future = wv
6582
return wv
6683

67-
def suggest(self, source: CommandSource, timeout: float = 0.2) -> _T:
68-
wv = self.request(source)
84+
def suggest(self, source: CommandSource, arg: _P, timeout: float = 0.2) -> _T:
85+
wv = self.request(source, arg)
6986
if wv.wait(timeout) == WaitableValue.EMPTY:
7087
return self._create_fallback()
7188
return wv.get()
7289

7390

74-
class BackupIdSuggestor(ValueSuggestor[List[int]]):
91+
class BackupIdSuggestor(ValueSuggestor[List[int], None]):
7592
@override
7693
def _create_fallback(self) -> List[int]:
7794
return []
7895

7996
@override
80-
def _create_value_task(self, source: CommandSource) -> LightTask[List[int]]:
97+
def _create_value_task(self, source: CommandSource, ctx: CommandContext) -> LightTask[List[int]]:
8198
return GetBackupIdsTask(source)
8299

100+
@override
101+
def _compute_task_key(self, source: CommandSource, ctx: CommandContext) -> str:
102+
return ''
103+
83104

84-
class FilesetIdSuggestor(ValueSuggestor[List[int]]):
105+
class FilesetIdSuggestor(ValueSuggestor[List[int], None]):
85106
@override
86107
def _create_fallback(self) -> List[int]:
87108
return []
88109

89110
@override
90-
def _create_value_task(self, source: CommandSource) -> LightTask[List[int]]:
111+
def _create_value_task(self, source: CommandSource, ctx: CommandContext) -> LightTask[List[int]]:
91112
return GetFilesetIdsTask(source)
113+
114+
@override
115+
def _compute_task_key(self, source: CommandSource, ctx: CommandContext) -> str:
116+
return ''
117+
118+
119+
class BackupFilePathSuggestor(ValueSuggestor[List[str], int]):
120+
@override
121+
def _create_fallback(self) -> List[str]:
122+
return []
123+
124+
@override
125+
def _create_value_task(self, source: CommandSource, backup_id_arg: str) -> LightTask[List[str]]:
126+
return GetBackupFilePathsTask(source, backup_id_arg)
127+
128+
@override
129+
def _compute_task_key(self, source: CommandSource, backup_id_arg: str) -> str:
130+
return backup_id_arg
131+
132+
@override
133+
def suggest(self, source: CommandSource, backup_id: int, timeout: float = 0.2) -> _T:
134+
return super().suggest(source, backup_id, timeout)
135+
136+
137+
class FilesetFilePathSuggestor(ValueSuggestor[List[str], int]):
138+
@override
139+
def _create_fallback(self) -> List[str]:
140+
return []
141+
142+
@override
143+
def _create_value_task(self, source: CommandSource, fileset_id: int) -> LightTask[List[str]]:
144+
return GetFilesetFilePathsTask(source, fileset_id)
145+
146+
@override
147+
def _compute_task_key(self, source: CommandSource, fileset_id: int) -> str:
148+
return str(fileset_id)
149+
150+
@override
151+
def suggest(self, source: CommandSource, fileset_id: int, timeout: float = 0.2) -> _T:
152+
return super().suggest(source, fileset_id, timeout)
153+
154+
155+
class ValueSuggesters:
156+
def __init__(self, task_manager: TaskManager):
157+
self.backup_id_suggestor = BackupIdSuggestor(task_manager)
158+
self.fileset_id_suggestor = FilesetIdSuggestor(task_manager)
159+
self.backup_file_path_suggestor = BackupFilePathSuggestor(task_manager)
160+
self.fileset_file_path_suggestor = FilesetFilePathSuggestor(task_manager)
161+
162+
def suggest_backup_id(self, source: CommandSource) -> List[str]:
163+
return [str(backup_id) for backup_id in self.backup_id_suggestor.suggest(source, None)]
164+
165+
def suggest_fileset_id(self, source: CommandSource) -> List[str]:
166+
return [str(fileset_id) for fileset_id in self.fileset_id_suggestor.suggest(source, None)]
167+
168+
def suggest_backup_file_path(self, source: CommandSource, backup_id_arg: str) -> List[str]:
169+
misc_utils.ensure_type(backup_id_arg, str)
170+
return self.backup_file_path_suggestor.suggest(source, backup_id_arg)
171+
172+
def suggest_fileset_file_path(self, source: CommandSource, fileset_id: int) -> List[str]:
173+
misc_utils.ensure_type(fileset_id, int)
174+
return self.fileset_file_path_suggestor.suggest(source, fileset_id)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import List, Union
2+
3+
from mcdreforged.api.all import CommandSource
4+
from typing_extensions import override
5+
6+
from prime_backup.action.get_file_action import GetBackupFilesAction
7+
from prime_backup.mcdr.task.backup.transform_backup_id_task import TransformBackupIdTask
8+
from prime_backup.mcdr.task.basic_task import LightTask
9+
10+
11+
class GetBackupFilePathsTask(LightTask[List[str]]):
12+
def __init__(self, source: CommandSource, backup_id: Union[int, str]):
13+
super().__init__(source)
14+
self.backup_id = backup_id
15+
16+
@property
17+
@override
18+
def id(self) -> str:
19+
return 'db_get_backup_file_paths'
20+
21+
@override
22+
def run(self) -> List[str]:
23+
if isinstance(self.backup_id, int):
24+
backup_id = self.backup_id
25+
else: # backup id raw argument
26+
backup_id = TransformBackupIdTask(self.source, [self.backup_id]).run()[0]
27+
file_dict = GetBackupFilesAction(backup_id).run()
28+
return list(file_dict.keys())
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import List
2+
3+
from mcdreforged.api.all import CommandSource
4+
from typing_extensions import override
5+
6+
from prime_backup.action.get_file_action import GetFilesetFilesAction
7+
from prime_backup.mcdr.task.basic_task import LightTask
8+
9+
10+
class GetFilesetFilePathsTask(LightTask[List[str]]):
11+
def __init__(self, source: CommandSource, fileset_id: int):
12+
super().__init__(source)
13+
self.fileset_id = fileset_id
14+
15+
@property
16+
@override
17+
def id(self) -> str:
18+
return 'db_get_fileset_file_paths'
19+
20+
@override
21+
def run(self) -> List[str]:
22+
file_dict = GetFilesetFilesAction(self.fileset_id).run()
23+
return list(file_dict.keys())

0 commit comments

Comments
 (0)