feat: refresh model and voice test catalog with favicon
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ import sys
|
||||
|
||||
ROOT = Path("/adamwen-work-space/xas-test-library")
|
||||
NAME = "adamwen-script-console"
|
||||
IMAGE = "adamwen/script-console:20261014-1"
|
||||
IMAGE = "adamwen/script-console:20261020-1"
|
||||
UNIT = "adamwen-script-worker.service"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
"""Refresh reviewed sources atomically without resetting saved options or history."""
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
from console import catalog, native_plans
|
||||
from console.settings import Settings
|
||||
from console.store import Store
|
||||
|
||||
|
||||
def refresh(store, backup, apply=False):
|
||||
original = {s['id']: s for s in store.scripts()}
|
||||
class Draft:
|
||||
settings = store.settings
|
||||
items = copy.deepcopy(original)
|
||||
def scripts(self): return list(self.items.values())
|
||||
def save_script(self, item): self.items[item['id']] = item
|
||||
draft = Draft()
|
||||
scan = catalog.discover(draft)
|
||||
for item in draft.items.values():
|
||||
profile = native_plans.profile_for(store.settings, item)
|
||||
if not profile:
|
||||
continue
|
||||
if item['id'] not in original:
|
||||
item['config'] = native_plans.validate_config(store.settings, item,
|
||||
{'native_options': {}, 'timeout_seconds': profile.get('timeout_seconds', 3600)})
|
||||
item['enabled'] = profile.get('available', True)
|
||||
if not profile.get('available', True):
|
||||
item.update(enabled=False, blocked=True, reason=profile.get('unavailable_reason', '原环境待配置'))
|
||||
if item['enabled']:
|
||||
item.update(status='ready', reason='')
|
||||
elif item['status'] != 'missing':
|
||||
item['status'] = 'needs_configuration'
|
||||
changes = []
|
||||
for identity, value in draft.items.items():
|
||||
before = original.get(identity)
|
||||
if before and {k:v for k,v in before.items() if k != 'updated_at'} == {k:v for k,v in value.items() if k != 'updated_at'}:
|
||||
continue
|
||||
changes.append((identity, before, value))
|
||||
if not apply:
|
||||
return {'scan': scan, 'changed': len(changes), 'applied': False}
|
||||
with store.connect(write=True) as db:
|
||||
if db.execute("SELECT 1 FROM runs WHERE state IN ('queued','running')").fetchone():
|
||||
raise ValueError('请先等待排队和运行任务结束')
|
||||
records = []
|
||||
for identity, before, after in changes:
|
||||
row = db.execute('SELECT data FROM scripts WHERE id=?', (identity,)).fetchone()
|
||||
if (json.loads(row[0]) if row else None) != before:
|
||||
raise ValueError('配置有并发修改,本次刷新未写入')
|
||||
records.append({'id': identity, 'before': row[0] if row else None, 'after': json.dumps(after)})
|
||||
if not records:
|
||||
return {'scan': scan, 'changed': 0, 'applied': True}
|
||||
backup.parent.mkdir(parents=True, exist_ok=True)
|
||||
with backup.open('x', encoding='utf-8') as handle:
|
||||
json.dump({'scripts': records}, handle, ensure_ascii=False, indent=2)
|
||||
backup.chmod(0o600)
|
||||
for record in records:
|
||||
db.execute('INSERT OR REPLACE INTO scripts VALUES(?,?)', (record['id'], record['after']))
|
||||
return {'scan': scan, 'changed': len(changes), 'applied': True}
|
||||
|
||||
|
||||
def restore(store, backup):
|
||||
records = json.loads(backup.read_text(encoding='utf-8'))['scripts']
|
||||
with store.connect(write=True) as db:
|
||||
if db.execute("SELECT 1 FROM runs WHERE state IN ('queued','running')").fetchone():
|
||||
raise ValueError('请先等待排队和运行任务结束')
|
||||
for record in records:
|
||||
row = db.execute('SELECT data FROM scripts WHERE id=?', (record['id'],)).fetchone()
|
||||
current = row[0] if row else None
|
||||
if current not in (record['before'], record['after']):
|
||||
raise ValueError('刷新后配置已修改,请人工核对,禁止覆盖')
|
||||
if record['before'] is None and db.execute('SELECT 1 FROM runs WHERE script_id=?', (record['id'],)).fetchone():
|
||||
raise ValueError('新增项目已有运行历史,不能删除登记,请人工恢复')
|
||||
for record in records:
|
||||
if record['before'] is None:
|
||||
db.execute('DELETE FROM scripts WHERE id=?', (record['id'],))
|
||||
else:
|
||||
db.execute('UPDATE scripts SET data=? WHERE id=?', (record['before'], record['id']))
|
||||
return {'restored': len(records), 'history_preserved': True}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--apply', action='store_true')
|
||||
parser.add_argument('--restore', action='store_true')
|
||||
parser.add_argument('--backup', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
if args.apply and args.restore: parser.error('选择刷新或恢复之一')
|
||||
store = Store(Settings.from_env())
|
||||
print(json.dumps(restore(store, args.backup) if args.restore else refresh(store, args.backup, args.apply)))
|
||||
Reference in New Issue
Block a user