evm-cli 2.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evm/__init__.py +55 -0
- evm/__main__.py +9 -0
- evm/_completion.py +253 -0
- evm/_crypto.py +177 -0
- evm/_groups.py +127 -0
- evm/_history.py +141 -0
- evm/_io.py +421 -0
- evm/_json.py +52 -0
- evm/_schema.py +265 -0
- evm/_typing.py +40 -0
- evm/cli.py +961 -0
- evm/exceptions.py +150 -0
- evm/formatters.py +285 -0
- evm/manager.py +644 -0
- evm_cli-2.4.0.dist-info/METADATA +748 -0
- evm_cli-2.4.0.dist-info/RECORD +20 -0
- evm_cli-2.4.0.dist-info/WHEEL +5 -0
- evm_cli-2.4.0.dist-info/entry_points.txt +2 -0
- evm_cli-2.4.0.dist-info/licenses/LICENSE +21 -0
- evm_cli-2.4.0.dist-info/top_level.txt +1 -0
evm/cli.py
ADDED
|
@@ -0,0 +1,961 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
EVM 命令行接口
|
|
4
|
+
|
|
5
|
+
负责 argparse 解析、命令调度和输出格式化。
|
|
6
|
+
|
|
7
|
+
输出模式:
|
|
8
|
+
- 默认: 人类可读文本 (stdout)
|
|
9
|
+
- --json: 结构化 JSON (stdout=数据, stderr=日志)
|
|
10
|
+
- --quiet: 静默模式 (仅退出码)
|
|
11
|
+
|
|
12
|
+
退出码:
|
|
13
|
+
0 — 成功
|
|
14
|
+
1 — 通用错误 / 操作取消
|
|
15
|
+
2 — 变量不存在 (KeyNotFoundError)
|
|
16
|
+
3 — 存储错误 (StorageError / CorruptedStorageError / LockTimeoutError)
|
|
17
|
+
4 — 输入格式错误 (ImportFailedError / ExportError)
|
|
18
|
+
5 — 解密失败 (DecryptionError)
|
|
19
|
+
6 — 校验失败 (ValidationError / SchemaError)
|
|
20
|
+
7 — 分组错误 (GroupNotFoundError / GroupOperationError)
|
|
21
|
+
8 — 备份错误 (BackupError)
|
|
22
|
+
9 — 编辑器错误 (EditorError)
|
|
23
|
+
10 — 命令未找到 (CommandNotFoundError)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import argparse
|
|
27
|
+
import sys
|
|
28
|
+
from typing import Optional
|
|
29
|
+
|
|
30
|
+
from ._completion import SHELL_GENERATORS
|
|
31
|
+
from ._json import json_error, json_output
|
|
32
|
+
from .exceptions import (
|
|
33
|
+
BackupError,
|
|
34
|
+
CommandNotFoundError,
|
|
35
|
+
CorruptedStorageError,
|
|
36
|
+
DecryptionError,
|
|
37
|
+
EditorError,
|
|
38
|
+
EVMError,
|
|
39
|
+
ExportError,
|
|
40
|
+
GroupNotFoundError,
|
|
41
|
+
GroupOperationError,
|
|
42
|
+
ImportFailedError,
|
|
43
|
+
KeyAlreadyExistsError,
|
|
44
|
+
KeyNotFoundError,
|
|
45
|
+
LockTimeoutError,
|
|
46
|
+
OperationCancelledError,
|
|
47
|
+
SchemaError,
|
|
48
|
+
StorageError,
|
|
49
|
+
ValidationError,
|
|
50
|
+
)
|
|
51
|
+
from .formatters import (
|
|
52
|
+
print_diff,
|
|
53
|
+
print_groups,
|
|
54
|
+
print_history,
|
|
55
|
+
print_info,
|
|
56
|
+
print_load_memory_result,
|
|
57
|
+
print_schema,
|
|
58
|
+
print_search_results,
|
|
59
|
+
print_validate_all,
|
|
60
|
+
print_validate_result,
|
|
61
|
+
print_vars_by_group,
|
|
62
|
+
print_vars_table,
|
|
63
|
+
)
|
|
64
|
+
from .manager import EnvironmentManager
|
|
65
|
+
|
|
66
|
+
# 异常类型 → 退出码映射
|
|
67
|
+
EXIT_CODE_MAP = {
|
|
68
|
+
KeyNotFoundError: 2,
|
|
69
|
+
KeyAlreadyExistsError: 2,
|
|
70
|
+
StorageError: 3,
|
|
71
|
+
CorruptedStorageError: 3,
|
|
72
|
+
LockTimeoutError: 3,
|
|
73
|
+
ImportFailedError: 4,
|
|
74
|
+
ExportError: 4,
|
|
75
|
+
DecryptionError: 5,
|
|
76
|
+
ValidationError: 6,
|
|
77
|
+
SchemaError: 6,
|
|
78
|
+
GroupNotFoundError: 7,
|
|
79
|
+
GroupOperationError: 7,
|
|
80
|
+
BackupError: 8,
|
|
81
|
+
EditorError: 9,
|
|
82
|
+
CommandNotFoundError: 10,
|
|
83
|
+
OperationCancelledError: 1,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# 所有顶级命令(用于补全生成)
|
|
87
|
+
ALL_COMMANDS = [
|
|
88
|
+
'set', 'get', 'delete', 'list', 'clear',
|
|
89
|
+
'groups', 'setg', 'getg', 'deleteg', 'listg', 'delete-group', 'move-group',
|
|
90
|
+
'export', 'load',
|
|
91
|
+
'backup', 'restore',
|
|
92
|
+
'search', 'rename', 'copy',
|
|
93
|
+
'exec', 'loadmemory',
|
|
94
|
+
'edit', 'info', 'diff', 'expand',
|
|
95
|
+
'validate', 'history', 'schema', 'completion',
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _exit_code_for(exc: EVMError) -> int:
|
|
100
|
+
"""根据异常类型返回退出码"""
|
|
101
|
+
for exc_type, code in EXIT_CODE_MAP.items():
|
|
102
|
+
if isinstance(exc, exc_type):
|
|
103
|
+
return code
|
|
104
|
+
return 1
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
108
|
+
"""创建命令行参数解析器"""
|
|
109
|
+
parser = argparse.ArgumentParser(
|
|
110
|
+
prog='evm',
|
|
111
|
+
description='Environment Variable Manager - Manage environment variables easily',
|
|
112
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
113
|
+
epilog="""
|
|
114
|
+
Examples:
|
|
115
|
+
evm set API_KEY abc123 # Set a variable
|
|
116
|
+
evm set --secret DB_PASS mypass # Set an encrypted secret
|
|
117
|
+
evm get API_KEY # Get a variable
|
|
118
|
+
evm get API_KEY --json # Get as JSON: {"status":"ok","data":{"key":"API_KEY","value":"..."}}
|
|
119
|
+
evm list --json # List all as JSON
|
|
120
|
+
evm list --show-groups # List by namespace
|
|
121
|
+
evm export --format env # Export to .env
|
|
122
|
+
evm load config.json --nest # Import nested JSON
|
|
123
|
+
evm edit API_KEY # Edit in $EDITOR
|
|
124
|
+
evm info --json # Tool info as JSON
|
|
125
|
+
evm diff backup.json # Compare with backup
|
|
126
|
+
evm expand URL # Expand {{VAR}} templates
|
|
127
|
+
evm validate API_URL # Validate against schema
|
|
128
|
+
evm history --json # History as JSON
|
|
129
|
+
evm schema set API_URL --format url
|
|
130
|
+
evm completion bash # Generate shell completion
|
|
131
|
+
|
|
132
|
+
Agent-friendly usage:
|
|
133
|
+
evm get KEY --json # stdout = JSON, stderr = errors
|
|
134
|
+
evm list --json --quiet # stdout = JSON only, no decoration
|
|
135
|
+
evm --json info # All commands support --json
|
|
136
|
+
|
|
137
|
+
Group Management:
|
|
138
|
+
evm setg dev DB_URL localhost
|
|
139
|
+
evm getg dev DB_URL
|
|
140
|
+
evm listg dev
|
|
141
|
+
evm groups
|
|
142
|
+
evm delete-group dev
|
|
143
|
+
|
|
144
|
+
Options:
|
|
145
|
+
--json Output structured JSON to stdout (agent-friendly)
|
|
146
|
+
--quiet Suppress all human-readable output
|
|
147
|
+
--dry-run Preview changes (set, delete, clear, rename, copy, export,
|
|
148
|
+
load, setg, deleteg, delete-group, move-group, set --secret)
|
|
149
|
+
--force Skip confirmation for destructive operations (clear, delete-group)
|
|
150
|
+
|
|
151
|
+
Exit Codes:
|
|
152
|
+
0 Success
|
|
153
|
+
1 General error / cancelled
|
|
154
|
+
2 Variable not found
|
|
155
|
+
3 Storage error
|
|
156
|
+
4 Import/export format error
|
|
157
|
+
5 Decryption error
|
|
158
|
+
6 Validation/schema error
|
|
159
|
+
7 Group error
|
|
160
|
+
8 Backup error
|
|
161
|
+
9 Editor error
|
|
162
|
+
10 Command not found
|
|
163
|
+
""",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
parser.add_argument('--version', action='version', version='%(prog)s 2.3.0')
|
|
167
|
+
parser.add_argument('-v', '--verbose', action='store_true',
|
|
168
|
+
help='Show detailed version information')
|
|
169
|
+
parser.add_argument('--env-file',
|
|
170
|
+
help='Path to storage file (default: ~/.evm/env.json)')
|
|
171
|
+
parser.add_argument('--json', dest='json_mode', action='store_true',
|
|
172
|
+
help='Output structured JSON (agent-friendly)')
|
|
173
|
+
parser.add_argument('--quiet', '-q', action='store_true',
|
|
174
|
+
help='Suppress human-readable output')
|
|
175
|
+
parser.add_argument('--dry-run', action='store_true',
|
|
176
|
+
help='Preview changes without writing')
|
|
177
|
+
parser.add_argument('--force', action='store_true',
|
|
178
|
+
help='Skip confirmation for destructive operations')
|
|
179
|
+
|
|
180
|
+
subparsers = parser.add_subparsers(dest='command', help='Available commands')
|
|
181
|
+
|
|
182
|
+
def _sp(name, **kwargs):
|
|
183
|
+
"""Create a subparser with global args (--json/--quiet/--dry-run/--force).
|
|
184
|
+
|
|
185
|
+
Uses default=argparse.SUPPRESS so subparser defaults don't overwrite
|
|
186
|
+
values set on the parent parser (e.g. `evm --json get KEY`).
|
|
187
|
+
"""
|
|
188
|
+
p = subparsers.add_parser(name, **kwargs)
|
|
189
|
+
p.add_argument('--json', dest='json_mode', action='store_true',
|
|
190
|
+
default=argparse.SUPPRESS,
|
|
191
|
+
help='Output structured JSON (agent-friendly)')
|
|
192
|
+
p.add_argument('--quiet', '-q', action='store_true',
|
|
193
|
+
default=argparse.SUPPRESS,
|
|
194
|
+
help='Suppress human-readable output')
|
|
195
|
+
p.add_argument('--dry-run', action='store_true',
|
|
196
|
+
default=argparse.SUPPRESS,
|
|
197
|
+
help='Preview changes without writing')
|
|
198
|
+
p.add_argument('--force', action='store_true',
|
|
199
|
+
default=argparse.SUPPRESS,
|
|
200
|
+
help='Skip confirmation for destructive operations')
|
|
201
|
+
return p
|
|
202
|
+
|
|
203
|
+
# ── 基本命令 ──────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
set_p = _sp('set', help='Set a variable')
|
|
206
|
+
set_p.add_argument('key', help='Variable name')
|
|
207
|
+
set_p.add_argument('value', help='Variable value')
|
|
208
|
+
set_p.add_argument('--secret', '-s', action='store_true',
|
|
209
|
+
help='Encrypt the value')
|
|
210
|
+
|
|
211
|
+
get_p = _sp('get', help='Get a variable')
|
|
212
|
+
get_p.add_argument('key', help='Variable name')
|
|
213
|
+
get_p.add_argument('--secret', '-s', action='store_true',
|
|
214
|
+
help='Decrypt the value')
|
|
215
|
+
|
|
216
|
+
del_p = _sp('delete', help='Delete a variable')
|
|
217
|
+
del_p.add_argument('key', help='Variable name')
|
|
218
|
+
|
|
219
|
+
list_p = _sp('list', help='List all variables')
|
|
220
|
+
list_p.add_argument('pattern', nargs='?', help='Filter pattern')
|
|
221
|
+
list_p.add_argument('--group', '-g', help='Filter by group')
|
|
222
|
+
list_p.add_argument('--show-groups', action='store_true',
|
|
223
|
+
help='Group output by namespace')
|
|
224
|
+
list_p.add_argument('--no-prefix', action='store_true',
|
|
225
|
+
help='Remove group prefix from display')
|
|
226
|
+
|
|
227
|
+
_sp('clear', help='Clear all variables')
|
|
228
|
+
|
|
229
|
+
# ── 分组命令 ──────────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
_sp('groups', help='List all groups')
|
|
232
|
+
|
|
233
|
+
setg_p = _sp('setg', help='Set a grouped variable')
|
|
234
|
+
setg_p.add_argument('group')
|
|
235
|
+
setg_p.add_argument('key')
|
|
236
|
+
setg_p.add_argument('value')
|
|
237
|
+
|
|
238
|
+
getg_p = _sp('getg', help='Get a grouped variable')
|
|
239
|
+
getg_p.add_argument('group')
|
|
240
|
+
getg_p.add_argument('key')
|
|
241
|
+
|
|
242
|
+
delg_p = _sp('deleteg', help='Delete a grouped variable')
|
|
243
|
+
delg_p.add_argument('group')
|
|
244
|
+
delg_p.add_argument('key')
|
|
245
|
+
|
|
246
|
+
listg_p = _sp('listg', help='List variables in a group')
|
|
247
|
+
listg_p.add_argument('group')
|
|
248
|
+
listg_p.add_argument('--no-prefix', action='store_true')
|
|
249
|
+
|
|
250
|
+
dg_p = _sp('delete-group', help='Delete an entire group')
|
|
251
|
+
dg_p.add_argument('group')
|
|
252
|
+
|
|
253
|
+
mg_p = _sp('move-group', help='Move variable to group')
|
|
254
|
+
mg_p.add_argument('key')
|
|
255
|
+
mg_p.add_argument('group')
|
|
256
|
+
|
|
257
|
+
# ── 导入导出 ──────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
exp_p = _sp('export', help='Export variables')
|
|
260
|
+
exp_p.add_argument('--format', '-f', choices=['json', 'env', 'sh'],
|
|
261
|
+
default='json')
|
|
262
|
+
exp_p.add_argument('--output', '-o', help='Output file path')
|
|
263
|
+
exp_p.add_argument('--group', '-g', help='Export from group')
|
|
264
|
+
|
|
265
|
+
ld_p = _sp('load', help='Load from file')
|
|
266
|
+
ld_p.add_argument('file', help='Input file')
|
|
267
|
+
ld_p.add_argument('--format', '-f', choices=['json', 'env', 'backup'])
|
|
268
|
+
ld_p.add_argument('--replace', '-r', action='store_true')
|
|
269
|
+
ld_p.add_argument('--group', '-g')
|
|
270
|
+
ld_p.add_argument('--nest', '-n', action='store_true')
|
|
271
|
+
|
|
272
|
+
# ── 备份恢复 ──────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
bk_p = _sp('backup', help='Backup variables')
|
|
275
|
+
bk_p.add_argument('--file', '-f', help='Backup file path')
|
|
276
|
+
|
|
277
|
+
rs_p = _sp('restore', help='Restore from backup')
|
|
278
|
+
rs_p.add_argument('file')
|
|
279
|
+
rs_p.add_argument('--merge', '-m', action='store_true')
|
|
280
|
+
|
|
281
|
+
# ── 搜索/重命名/复制 ──────────────────────────────────
|
|
282
|
+
|
|
283
|
+
sr_p = _sp('search', help='Search variables')
|
|
284
|
+
sr_p.add_argument('pattern')
|
|
285
|
+
sr_p.add_argument('--value', '-v', action='store_true')
|
|
286
|
+
|
|
287
|
+
rn_p = _sp('rename', help='Rename a variable')
|
|
288
|
+
rn_p.add_argument('old_key')
|
|
289
|
+
rn_p.add_argument('new_key')
|
|
290
|
+
|
|
291
|
+
cp_p = _sp('copy', help='Copy a variable')
|
|
292
|
+
cp_p.add_argument('src_key')
|
|
293
|
+
cp_p.add_argument('dst_key')
|
|
294
|
+
|
|
295
|
+
# ── 执行/内存 ─────────────────────────────────────────
|
|
296
|
+
|
|
297
|
+
ex_p = _sp('exec', help='Execute with env vars')
|
|
298
|
+
ex_p.add_argument('exec_args', nargs='+')
|
|
299
|
+
|
|
300
|
+
lm_p = _sp('loadmemory', help='Load to os.environ')
|
|
301
|
+
lm_p.add_argument('--prefix', '-p')
|
|
302
|
+
lm_p.add_argument('--no-prefix', action='store_true')
|
|
303
|
+
|
|
304
|
+
# ── 编辑/信息/Diff/展开 ───────────────────────────────
|
|
305
|
+
|
|
306
|
+
ed_p = _sp('edit', help='Edit value in $EDITOR')
|
|
307
|
+
ed_p.add_argument('key')
|
|
308
|
+
|
|
309
|
+
_sp('info', help='Show tool information')
|
|
310
|
+
|
|
311
|
+
df_p = _sp('diff', help='Compare with backup')
|
|
312
|
+
df_p.add_argument('file')
|
|
313
|
+
|
|
314
|
+
xp_p = _sp('expand', help='Expand {{VAR}} templates')
|
|
315
|
+
xp_p.add_argument('key')
|
|
316
|
+
|
|
317
|
+
# ── P2 新功能 ─────────────────────────────────────────
|
|
318
|
+
|
|
319
|
+
# validate
|
|
320
|
+
vl_p = _sp('validate', help='Validate against schema')
|
|
321
|
+
vl_p.add_argument('key', nargs='?', help='Variable (omit for all)')
|
|
322
|
+
|
|
323
|
+
# history
|
|
324
|
+
hi_p = _sp('history', help='Show operation history')
|
|
325
|
+
hi_p.add_argument('--limit', '-n', type=int, default=20,
|
|
326
|
+
help='Number of entries to show')
|
|
327
|
+
hi_p.add_argument('--clear', action='store_true',
|
|
328
|
+
help='Clear all history')
|
|
329
|
+
|
|
330
|
+
# schema
|
|
331
|
+
sc_p = _sp('schema', help='Manage variable schemas')
|
|
332
|
+
sc_sub = sc_p.add_subparsers(dest='schema_command', help='Schema subcommand')
|
|
333
|
+
|
|
334
|
+
sc_set = sc_sub.add_parser('set', help='Set schema for a variable')
|
|
335
|
+
sc_set.add_argument('key')
|
|
336
|
+
sc_set.add_argument('--format', '-f',
|
|
337
|
+
choices=['url', 'email', 'port', 'integer',
|
|
338
|
+
'boolean', 'path', 'ipv4', 'ipv6'],
|
|
339
|
+
help='Built-in format')
|
|
340
|
+
sc_set.add_argument('--required', '-r', action='store_true',
|
|
341
|
+
help='Mark as required')
|
|
342
|
+
sc_set.add_argument('--pattern', '-p', help='Custom regex pattern')
|
|
343
|
+
sc_set.add_argument('--description', '-d', help='Description')
|
|
344
|
+
|
|
345
|
+
sc_get = sc_sub.add_parser('get', help='Get schema definition')
|
|
346
|
+
sc_get.add_argument('key', nargs='?', help='Variable (omit for all)')
|
|
347
|
+
|
|
348
|
+
sc_del = sc_sub.add_parser('delete', help='Remove schema definition')
|
|
349
|
+
sc_del.add_argument('key')
|
|
350
|
+
|
|
351
|
+
sc_sub.add_parser('list', help='List all schema definitions')
|
|
352
|
+
|
|
353
|
+
sc_val = sc_sub.add_parser('validate', help='Validate against schema')
|
|
354
|
+
sc_val.add_argument('key', nargs='?', help='Variable (omit for all)')
|
|
355
|
+
|
|
356
|
+
# completion
|
|
357
|
+
co_p = _sp('completion', help='Generate shell completion')
|
|
358
|
+
co_p.add_argument('shell', choices=['bash', 'zsh', 'fish'],
|
|
359
|
+
help='Shell type')
|
|
360
|
+
|
|
361
|
+
return parser
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _confirm(message: str) -> bool:
|
|
365
|
+
"""交互式确认(非交互模式或 stdin 非终端时返回 False)"""
|
|
366
|
+
if not sys.stdin.isatty():
|
|
367
|
+
return False
|
|
368
|
+
try:
|
|
369
|
+
response = input(f"{message} [y/N] ").strip().lower()
|
|
370
|
+
return response in ('y', 'yes')
|
|
371
|
+
except (EOFError, KeyboardInterrupt):
|
|
372
|
+
print()
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def main(argv: Optional[list[str]] = None) -> int:
|
|
377
|
+
"""主入口
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
退出码 (0=成功, 1-10=按异常类型细分)
|
|
381
|
+
"""
|
|
382
|
+
parser = create_parser()
|
|
383
|
+
args = parser.parse_args(argv)
|
|
384
|
+
|
|
385
|
+
json_mode = getattr(args, 'json_mode', False)
|
|
386
|
+
quiet = getattr(args, 'quiet', False)
|
|
387
|
+
|
|
388
|
+
if args.verbose:
|
|
389
|
+
mgr = EnvironmentManager(args.env_file)
|
|
390
|
+
info = mgr.info()
|
|
391
|
+
if json_mode:
|
|
392
|
+
json_output(info, quiet)
|
|
393
|
+
else:
|
|
394
|
+
print_info(info)
|
|
395
|
+
return 0
|
|
396
|
+
|
|
397
|
+
if not args.command:
|
|
398
|
+
parser.print_help()
|
|
399
|
+
return 0
|
|
400
|
+
|
|
401
|
+
dry_run = getattr(args, 'dry_run', False)
|
|
402
|
+
force = getattr(args, 'force', False)
|
|
403
|
+
|
|
404
|
+
try:
|
|
405
|
+
mgr = EnvironmentManager(args.env_file)
|
|
406
|
+
return _dispatch(mgr, args, dry_run, force, json_mode, quiet)
|
|
407
|
+
except OperationCancelledError:
|
|
408
|
+
if json_mode:
|
|
409
|
+
json_error("Operation cancelled.", 1, quiet)
|
|
410
|
+
else:
|
|
411
|
+
print("Operation cancelled.", file=sys.stderr)
|
|
412
|
+
return 1
|
|
413
|
+
except EVMError as e:
|
|
414
|
+
code = _exit_code_for(e)
|
|
415
|
+
if json_mode:
|
|
416
|
+
json_error(str(e), code, quiet)
|
|
417
|
+
else:
|
|
418
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
419
|
+
return code
|
|
420
|
+
except KeyboardInterrupt:
|
|
421
|
+
if not quiet:
|
|
422
|
+
print("\nOperation cancelled", file=sys.stderr)
|
|
423
|
+
return 1
|
|
424
|
+
except Exception as e:
|
|
425
|
+
if json_mode:
|
|
426
|
+
json_error(f"Unexpected error: {e}", 1, quiet)
|
|
427
|
+
else:
|
|
428
|
+
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
429
|
+
return 1
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
# ── 命令处理器函数 ──────────────────────────────────────────
|
|
433
|
+
|
|
434
|
+
def _cmd_set(mgr, args, dry_run, force, json_mode, quiet):
|
|
435
|
+
"""处理 set 命令"""
|
|
436
|
+
if getattr(args, 'secret', False):
|
|
437
|
+
msg = mgr.set_secret(args.key, args.value, dry_run=dry_run)
|
|
438
|
+
if json_mode:
|
|
439
|
+
json_output({
|
|
440
|
+
"key": args.key, "encrypted": True, "message": msg,
|
|
441
|
+
}, quiet)
|
|
442
|
+
elif not quiet:
|
|
443
|
+
print(msg)
|
|
444
|
+
else:
|
|
445
|
+
msg = mgr.set(args.key, args.value, dry_run=dry_run)
|
|
446
|
+
if json_mode:
|
|
447
|
+
json_output({
|
|
448
|
+
"key": args.key, "value": args.value, "message": msg,
|
|
449
|
+
}, quiet)
|
|
450
|
+
elif not quiet:
|
|
451
|
+
print(msg)
|
|
452
|
+
return 0
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _cmd_get(mgr, args, dry_run, force, json_mode, quiet):
|
|
456
|
+
"""处理 get 命令"""
|
|
457
|
+
is_secret = getattr(args, 'secret', False)
|
|
458
|
+
if is_secret:
|
|
459
|
+
value = mgr.get_secret(args.key)
|
|
460
|
+
else:
|
|
461
|
+
value = mgr.get(args.key)
|
|
462
|
+
if json_mode:
|
|
463
|
+
json_output({"key": args.key, "value": value}, quiet)
|
|
464
|
+
elif not quiet:
|
|
465
|
+
if is_secret and sys.stdout.isatty():
|
|
466
|
+
print(
|
|
467
|
+
"[WARNING] Decrypted secret displayed on terminal "
|
|
468
|
+
"(visible in scrollback).",
|
|
469
|
+
file=sys.stderr,
|
|
470
|
+
)
|
|
471
|
+
print(value)
|
|
472
|
+
return 0
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _cmd_delete(mgr, args, dry_run, force, json_mode, quiet):
|
|
476
|
+
"""处理 delete 命令"""
|
|
477
|
+
msg = mgr.delete(args.key, dry_run=dry_run)
|
|
478
|
+
if json_mode:
|
|
479
|
+
json_output({"key": args.key, "deleted": True, "message": msg}, quiet)
|
|
480
|
+
elif not quiet:
|
|
481
|
+
print(msg)
|
|
482
|
+
return 0
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def _cmd_list(mgr, args, dry_run, force, json_mode, quiet):
|
|
486
|
+
"""处理 list 命令"""
|
|
487
|
+
no_prefix = getattr(args, 'no_prefix', False)
|
|
488
|
+
if getattr(args, 'show_groups', False):
|
|
489
|
+
if args.group:
|
|
490
|
+
filtered = mgr.list_vars(group=args.group)
|
|
491
|
+
elif args.pattern:
|
|
492
|
+
filtered = mgr.list_vars(pattern=args.pattern)
|
|
493
|
+
else:
|
|
494
|
+
filtered = mgr.list_vars()
|
|
495
|
+
if json_mode:
|
|
496
|
+
json_output(filtered, quiet)
|
|
497
|
+
elif not quiet:
|
|
498
|
+
print_vars_by_group(filtered)
|
|
499
|
+
else:
|
|
500
|
+
result = mgr.list_vars(
|
|
501
|
+
pattern=args.pattern,
|
|
502
|
+
group=args.group,
|
|
503
|
+
no_prefix=no_prefix,
|
|
504
|
+
)
|
|
505
|
+
if json_mode:
|
|
506
|
+
json_output(result, quiet)
|
|
507
|
+
elif not quiet:
|
|
508
|
+
print_vars_table(result)
|
|
509
|
+
return 0
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def _cmd_clear(mgr, args, dry_run, force, json_mode, quiet):
|
|
513
|
+
"""处理 clear 命令"""
|
|
514
|
+
if not dry_run and not force:
|
|
515
|
+
count = len(mgr._env_vars)
|
|
516
|
+
if count > 0:
|
|
517
|
+
if not sys.stdin.isatty():
|
|
518
|
+
raise EVMError(
|
|
519
|
+
"Cannot confirm 'clear' in non-interactive mode. "
|
|
520
|
+
"Use --force to skip confirmation."
|
|
521
|
+
)
|
|
522
|
+
if not _confirm(f"This will clear all {count} variables. Continue?"):
|
|
523
|
+
raise OperationCancelledError("clear")
|
|
524
|
+
count = len(mgr._env_vars)
|
|
525
|
+
msg = mgr.clear(dry_run=dry_run)
|
|
526
|
+
if json_mode:
|
|
527
|
+
json_output({"cleared": count, "message": msg}, quiet)
|
|
528
|
+
elif not quiet:
|
|
529
|
+
print(msg)
|
|
530
|
+
return 0
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def _cmd_groups(mgr, args, dry_run, force, json_mode, quiet):
|
|
534
|
+
"""处理 groups 命令"""
|
|
535
|
+
groups = mgr.list_groups()
|
|
536
|
+
if json_mode:
|
|
537
|
+
json_output({"groups": groups}, quiet)
|
|
538
|
+
elif not quiet:
|
|
539
|
+
print_groups(groups)
|
|
540
|
+
return 0
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def _cmd_setg(mgr, args, dry_run, force, json_mode, quiet):
|
|
544
|
+
"""处理 setg 命令"""
|
|
545
|
+
msg = mgr.set_grouped(args.group, args.key, args.value, dry_run=dry_run)
|
|
546
|
+
if json_mode:
|
|
547
|
+
json_output({
|
|
548
|
+
"group": args.group, "key": args.key,
|
|
549
|
+
"value": args.value, "message": msg,
|
|
550
|
+
}, quiet)
|
|
551
|
+
elif not quiet:
|
|
552
|
+
print(msg)
|
|
553
|
+
return 0
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _cmd_getg(mgr, args, dry_run, force, json_mode, quiet):
|
|
557
|
+
"""处理 getg 命令"""
|
|
558
|
+
value = mgr.get_grouped(args.group, args.key)
|
|
559
|
+
if json_mode:
|
|
560
|
+
json_output({
|
|
561
|
+
"group": args.group, "key": args.key, "value": value,
|
|
562
|
+
}, quiet)
|
|
563
|
+
elif not quiet:
|
|
564
|
+
print(value)
|
|
565
|
+
return 0
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def _cmd_deleteg(mgr, args, dry_run, force, json_mode, quiet):
|
|
569
|
+
"""处理 deleteg 命令"""
|
|
570
|
+
msg = mgr.delete_grouped(args.group, args.key, dry_run=dry_run)
|
|
571
|
+
if json_mode:
|
|
572
|
+
json_output({
|
|
573
|
+
"group": args.group, "key": args.key,
|
|
574
|
+
"deleted": True, "message": msg,
|
|
575
|
+
}, quiet)
|
|
576
|
+
elif not quiet:
|
|
577
|
+
print(msg)
|
|
578
|
+
return 0
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def _cmd_listg(mgr, args, dry_run, force, json_mode, quiet):
|
|
582
|
+
"""处理 listg 命令"""
|
|
583
|
+
no_prefix = getattr(args, 'no_prefix', False)
|
|
584
|
+
result = mgr.list_vars(group=args.group, no_prefix=no_prefix)
|
|
585
|
+
if json_mode:
|
|
586
|
+
json_output(result, quiet)
|
|
587
|
+
elif not quiet:
|
|
588
|
+
print_vars_table(result)
|
|
589
|
+
return 0
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def _cmd_delete_group(mgr, args, dry_run, force, json_mode, quiet):
|
|
593
|
+
"""处理 delete-group 命令"""
|
|
594
|
+
if not dry_run and not force:
|
|
595
|
+
if not sys.stdin.isatty():
|
|
596
|
+
raise EVMError(
|
|
597
|
+
"Cannot confirm 'delete-group' in non-interactive mode. "
|
|
598
|
+
"Use --force to skip confirmation."
|
|
599
|
+
)
|
|
600
|
+
if not _confirm(
|
|
601
|
+
f"This will delete group '{args.group}' and all its variables. Continue?"
|
|
602
|
+
):
|
|
603
|
+
raise OperationCancelledError("delete-group")
|
|
604
|
+
msg = mgr.delete_group(args.group, dry_run=dry_run)
|
|
605
|
+
if json_mode:
|
|
606
|
+
json_output({
|
|
607
|
+
"group": args.group, "deleted": True, "message": msg,
|
|
608
|
+
}, quiet)
|
|
609
|
+
elif not quiet:
|
|
610
|
+
print(msg)
|
|
611
|
+
return 0
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def _cmd_move_group(mgr, args, dry_run, force, json_mode, quiet):
|
|
615
|
+
"""处理 move-group 命令"""
|
|
616
|
+
msg = mgr.move_to_group(args.key, args.group, dry_run=dry_run)
|
|
617
|
+
if json_mode:
|
|
618
|
+
json_output({
|
|
619
|
+
"key": args.key, "target_group": args.group, "message": msg,
|
|
620
|
+
}, quiet)
|
|
621
|
+
elif not quiet:
|
|
622
|
+
print(msg)
|
|
623
|
+
return 0
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def _cmd_export(mgr, args, dry_run, force, json_mode, quiet):
|
|
627
|
+
"""处理 export 命令"""
|
|
628
|
+
msg = mgr.export(
|
|
629
|
+
format_type=args.format,
|
|
630
|
+
output_file=args.output,
|
|
631
|
+
group=args.group,
|
|
632
|
+
dry_run=dry_run,
|
|
633
|
+
)
|
|
634
|
+
if json_mode:
|
|
635
|
+
json_output({"message": msg, "format": args.format}, quiet)
|
|
636
|
+
elif not quiet:
|
|
637
|
+
print(msg)
|
|
638
|
+
return 0
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def _cmd_load(mgr, args, dry_run, force, json_mode, quiet):
|
|
642
|
+
"""处理 load 命令"""
|
|
643
|
+
msg = mgr.load(
|
|
644
|
+
input_file=args.file,
|
|
645
|
+
format_type=getattr(args, 'format', None),
|
|
646
|
+
replace=getattr(args, 'replace', False),
|
|
647
|
+
group=getattr(args, 'group', None),
|
|
648
|
+
nest=getattr(args, 'nest', False),
|
|
649
|
+
dry_run=dry_run,
|
|
650
|
+
)
|
|
651
|
+
if json_mode:
|
|
652
|
+
json_output({"message": msg, "file": args.file}, quiet)
|
|
653
|
+
elif not quiet:
|
|
654
|
+
print(msg)
|
|
655
|
+
return 0
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def _cmd_backup(mgr, args, dry_run, force, json_mode, quiet):
|
|
659
|
+
"""处理 backup 命令"""
|
|
660
|
+
msg = mgr.backup(args.file)
|
|
661
|
+
if json_mode:
|
|
662
|
+
json_output({"message": msg}, quiet)
|
|
663
|
+
elif not quiet:
|
|
664
|
+
print(msg)
|
|
665
|
+
return 0
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
def _cmd_restore(mgr, args, dry_run, force, json_mode, quiet):
|
|
669
|
+
"""处理 restore 命令"""
|
|
670
|
+
msg = mgr.restore(args.file, merge=getattr(args, 'merge', False))
|
|
671
|
+
if json_mode:
|
|
672
|
+
json_output({"message": msg, "file": args.file}, quiet)
|
|
673
|
+
elif not quiet:
|
|
674
|
+
print(msg)
|
|
675
|
+
return 0
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def _cmd_search(mgr, args, dry_run, force, json_mode, quiet):
|
|
679
|
+
"""处理 search 命令"""
|
|
680
|
+
results = mgr.search(
|
|
681
|
+
args.pattern, search_value=getattr(args, 'value', False)
|
|
682
|
+
)
|
|
683
|
+
if json_mode:
|
|
684
|
+
json_output(results, quiet)
|
|
685
|
+
elif not quiet:
|
|
686
|
+
print_search_results(
|
|
687
|
+
results, args.pattern, getattr(args, 'value', False)
|
|
688
|
+
)
|
|
689
|
+
return 0
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def _cmd_rename(mgr, args, dry_run, force, json_mode, quiet):
|
|
693
|
+
"""处理 rename 命令"""
|
|
694
|
+
msg = mgr.rename(args.old_key, args.new_key, dry_run=dry_run)
|
|
695
|
+
if json_mode:
|
|
696
|
+
json_output({
|
|
697
|
+
"old_key": args.old_key, "new_key": args.new_key,
|
|
698
|
+
"message": msg,
|
|
699
|
+
}, quiet)
|
|
700
|
+
elif not quiet:
|
|
701
|
+
print(msg)
|
|
702
|
+
return 0
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
def _cmd_copy(mgr, args, dry_run, force, json_mode, quiet):
|
|
706
|
+
"""处理 copy 命令"""
|
|
707
|
+
msg = mgr.copy(args.src_key, args.dst_key, dry_run=dry_run)
|
|
708
|
+
if json_mode:
|
|
709
|
+
json_output({
|
|
710
|
+
"src_key": args.src_key, "dst_key": args.dst_key,
|
|
711
|
+
"message": msg,
|
|
712
|
+
}, quiet)
|
|
713
|
+
elif not quiet:
|
|
714
|
+
print(msg)
|
|
715
|
+
return 0
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
def _cmd_exec(mgr, args, dry_run, force, json_mode, quiet):
|
|
719
|
+
"""处理 exec 命令 - 返回子进程退出码"""
|
|
720
|
+
return mgr.execute(args.exec_args)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def _cmd_loadmemory(mgr, args, dry_run, force, json_mode, quiet):
|
|
724
|
+
"""处理 loadmemory 命令"""
|
|
725
|
+
filter_prefix = getattr(args, 'prefix', None)
|
|
726
|
+
add_evm_prefix = not getattr(args, 'no_prefix', False)
|
|
727
|
+
loaded, prefix_used, filter_used = mgr.load_to_memory(
|
|
728
|
+
filter_prefix=filter_prefix,
|
|
729
|
+
add_evm_prefix=add_evm_prefix,
|
|
730
|
+
)
|
|
731
|
+
if json_mode:
|
|
732
|
+
json_output({
|
|
733
|
+
"loaded": loaded,
|
|
734
|
+
"evm_prefix": prefix_used,
|
|
735
|
+
"filter_prefix": filter_used,
|
|
736
|
+
}, quiet)
|
|
737
|
+
elif not quiet:
|
|
738
|
+
print_load_memory_result(loaded, prefix_used, filter_used)
|
|
739
|
+
return 0
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def _cmd_edit(mgr, args, dry_run, force, json_mode, quiet):
|
|
743
|
+
"""处理 edit 命令"""
|
|
744
|
+
msg = mgr.edit(args.key)
|
|
745
|
+
changed = "Updated" in msg
|
|
746
|
+
if json_mode:
|
|
747
|
+
json_output({"key": args.key, "changed": changed, "message": msg}, quiet)
|
|
748
|
+
elif not quiet:
|
|
749
|
+
print(msg)
|
|
750
|
+
return 0
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
def _cmd_info(mgr, args, dry_run, force, json_mode, quiet):
|
|
754
|
+
"""处理 info 命令"""
|
|
755
|
+
info = mgr.info()
|
|
756
|
+
if json_mode:
|
|
757
|
+
json_output(info, quiet)
|
|
758
|
+
elif not quiet:
|
|
759
|
+
print_info(info)
|
|
760
|
+
return 0
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
def _cmd_diff(mgr, args, dry_run, force, json_mode, quiet):
|
|
764
|
+
"""处理 diff 命令"""
|
|
765
|
+
result = mgr.diff(args.file)
|
|
766
|
+
if json_mode:
|
|
767
|
+
json_output(result, quiet)
|
|
768
|
+
elif not quiet:
|
|
769
|
+
print_diff(result)
|
|
770
|
+
return 0
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
def _cmd_expand(mgr, args, dry_run, force, json_mode, quiet):
|
|
774
|
+
"""处理 expand 命令"""
|
|
775
|
+
expanded = mgr.expand(args.key)
|
|
776
|
+
if json_mode:
|
|
777
|
+
json_output({"key": args.key, "expanded": expanded}, quiet)
|
|
778
|
+
elif not quiet:
|
|
779
|
+
print(expanded)
|
|
780
|
+
return 0
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
def _cmd_validate(mgr, args, dry_run, force, json_mode, quiet):
|
|
784
|
+
"""处理 validate 命令"""
|
|
785
|
+
key = getattr(args, 'key', None)
|
|
786
|
+
if key:
|
|
787
|
+
result = mgr.validate(key)
|
|
788
|
+
if json_mode:
|
|
789
|
+
json_output({"key": key, **result}, quiet)
|
|
790
|
+
elif not quiet:
|
|
791
|
+
print_validate_result(key, result)
|
|
792
|
+
else:
|
|
793
|
+
results = mgr.validate_all()
|
|
794
|
+
if json_mode:
|
|
795
|
+
json_output(results, quiet)
|
|
796
|
+
elif not quiet:
|
|
797
|
+
print_validate_all(results)
|
|
798
|
+
return 0
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def _cmd_history(mgr, args, dry_run, force, json_mode, quiet):
|
|
802
|
+
"""处理 history 命令"""
|
|
803
|
+
if getattr(args, 'clear', False):
|
|
804
|
+
msg = mgr.clear_history()
|
|
805
|
+
if json_mode:
|
|
806
|
+
json_output({"message": msg}, quiet)
|
|
807
|
+
elif not quiet:
|
|
808
|
+
print(msg)
|
|
809
|
+
else:
|
|
810
|
+
entries = mgr.get_history(limit=args.limit)
|
|
811
|
+
if json_mode:
|
|
812
|
+
json_output(entries, quiet)
|
|
813
|
+
elif not quiet:
|
|
814
|
+
print_history(entries)
|
|
815
|
+
return 0
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def _cmd_schema(mgr, args, dry_run, force, json_mode, quiet):
|
|
819
|
+
"""处理 schema 命令"""
|
|
820
|
+
return _dispatch_schema(mgr, args, json_mode, quiet)
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
def _cmd_completion(mgr, args, dry_run, force, json_mode, quiet):
|
|
824
|
+
"""处理 completion 命令"""
|
|
825
|
+
generator = SHELL_GENERATORS.get(args.shell)
|
|
826
|
+
if generator:
|
|
827
|
+
script = generator(ALL_COMMANDS)
|
|
828
|
+
print(script, end='')
|
|
829
|
+
else:
|
|
830
|
+
raise EVMError(f"Unsupported shell: {args.shell}")
|
|
831
|
+
return 0
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
# ── 命令注册表 ──────────────────────────────────────────────
|
|
835
|
+
|
|
836
|
+
COMMAND_HANDLERS = {
|
|
837
|
+
'set': _cmd_set,
|
|
838
|
+
'get': _cmd_get,
|
|
839
|
+
'delete': _cmd_delete,
|
|
840
|
+
'list': _cmd_list,
|
|
841
|
+
'clear': _cmd_clear,
|
|
842
|
+
'groups': _cmd_groups,
|
|
843
|
+
'setg': _cmd_setg,
|
|
844
|
+
'getg': _cmd_getg,
|
|
845
|
+
'deleteg': _cmd_deleteg,
|
|
846
|
+
'listg': _cmd_listg,
|
|
847
|
+
'delete-group': _cmd_delete_group,
|
|
848
|
+
'move-group': _cmd_move_group,
|
|
849
|
+
'export': _cmd_export,
|
|
850
|
+
'load': _cmd_load,
|
|
851
|
+
'backup': _cmd_backup,
|
|
852
|
+
'restore': _cmd_restore,
|
|
853
|
+
'search': _cmd_search,
|
|
854
|
+
'rename': _cmd_rename,
|
|
855
|
+
'copy': _cmd_copy,
|
|
856
|
+
'exec': _cmd_exec,
|
|
857
|
+
'loadmemory': _cmd_loadmemory,
|
|
858
|
+
'edit': _cmd_edit,
|
|
859
|
+
'info': _cmd_info,
|
|
860
|
+
'diff': _cmd_diff,
|
|
861
|
+
'expand': _cmd_expand,
|
|
862
|
+
'validate': _cmd_validate,
|
|
863
|
+
'history': _cmd_history,
|
|
864
|
+
'schema': _cmd_schema,
|
|
865
|
+
'completion': _cmd_completion,
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def _dispatch(
|
|
870
|
+
mgr: EnvironmentManager,
|
|
871
|
+
args,
|
|
872
|
+
dry_run: bool,
|
|
873
|
+
force: bool,
|
|
874
|
+
json_mode: bool,
|
|
875
|
+
quiet: bool,
|
|
876
|
+
) -> int:
|
|
877
|
+
"""命令调度(注册表模式)
|
|
878
|
+
|
|
879
|
+
Returns:
|
|
880
|
+
退出码(通常为 0,exec 命令透传子进程退出码)
|
|
881
|
+
"""
|
|
882
|
+
cmd = args.command
|
|
883
|
+
handler = COMMAND_HANDLERS.get(cmd)
|
|
884
|
+
|
|
885
|
+
if handler is None:
|
|
886
|
+
raise EVMError(f"Unknown command: {cmd}")
|
|
887
|
+
|
|
888
|
+
return handler(mgr, args, dry_run, force, json_mode, quiet) # type: ignore[no-any-return]
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
def _dispatch_schema(
|
|
892
|
+
mgr: EnvironmentManager, args, json_mode: bool, quiet: bool
|
|
893
|
+
) -> int:
|
|
894
|
+
"""Schema 子命令调度"""
|
|
895
|
+
sc_cmd = getattr(args, 'schema_command', None)
|
|
896
|
+
|
|
897
|
+
if sc_cmd == 'set':
|
|
898
|
+
required = None
|
|
899
|
+
if getattr(args, 'required', False):
|
|
900
|
+
required = True
|
|
901
|
+
msg = mgr.set_schema(
|
|
902
|
+
args.key,
|
|
903
|
+
format=getattr(args, 'format', None),
|
|
904
|
+
required=required,
|
|
905
|
+
pattern=getattr(args, 'pattern', None),
|
|
906
|
+
description=getattr(args, 'description', None),
|
|
907
|
+
)
|
|
908
|
+
if json_mode:
|
|
909
|
+
json_output({"key": args.key, "message": msg}, quiet)
|
|
910
|
+
elif not quiet:
|
|
911
|
+
print(msg)
|
|
912
|
+
|
|
913
|
+
elif sc_cmd == 'get':
|
|
914
|
+
key = getattr(args, 'key', None)
|
|
915
|
+
schema = mgr.get_schema(key)
|
|
916
|
+
if json_mode:
|
|
917
|
+
json_output(schema, quiet)
|
|
918
|
+
elif not quiet:
|
|
919
|
+
print_schema(schema)
|
|
920
|
+
|
|
921
|
+
elif sc_cmd == 'delete':
|
|
922
|
+
msg = mgr.delete_schema(args.key)
|
|
923
|
+
if json_mode:
|
|
924
|
+
json_output({"key": args.key, "message": msg}, quiet)
|
|
925
|
+
elif not quiet:
|
|
926
|
+
print(msg)
|
|
927
|
+
|
|
928
|
+
elif sc_cmd == 'list':
|
|
929
|
+
schema = mgr.get_schema()
|
|
930
|
+
if json_mode:
|
|
931
|
+
json_output(schema, quiet)
|
|
932
|
+
elif not quiet:
|
|
933
|
+
print_schema(schema)
|
|
934
|
+
|
|
935
|
+
elif sc_cmd == 'validate':
|
|
936
|
+
key = getattr(args, 'key', None)
|
|
937
|
+
if key:
|
|
938
|
+
result = mgr.validate(key)
|
|
939
|
+
if json_mode:
|
|
940
|
+
json_output({"key": key, **result}, quiet)
|
|
941
|
+
elif not quiet:
|
|
942
|
+
print_validate_result(key, result)
|
|
943
|
+
else:
|
|
944
|
+
results = mgr.validate_all()
|
|
945
|
+
if json_mode:
|
|
946
|
+
json_output(results, quiet)
|
|
947
|
+
elif not quiet:
|
|
948
|
+
print_validate_all(results)
|
|
949
|
+
|
|
950
|
+
else:
|
|
951
|
+
# 无子命令时显示 schema 列表
|
|
952
|
+
schema = mgr.get_schema()
|
|
953
|
+
if json_mode:
|
|
954
|
+
json_output(schema, quiet)
|
|
955
|
+
elif not quiet:
|
|
956
|
+
print_schema(schema)
|
|
957
|
+
|
|
958
|
+
return 0
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
__all__ = ['create_parser', 'main', 'ALL_COMMANDS', 'EXIT_CODE_MAP', 'COMMAND_HANDLERS']
|