fix(installer): make uninstall atomic for plugins and pass rollback test
This commit is contained in:
@@ -245,25 +245,64 @@ run_uninstall() {
|
||||
|
||||
python3 - <<'PY'
|
||||
import json, os, subprocess, sys
|
||||
|
||||
rec=json.load(open(os.environ['REC_FILE'],encoding='utf-8'))
|
||||
paths=rec.get('paths',{})
|
||||
|
||||
for path, info in paths.items():
|
||||
exists=bool(info.get('exists'))
|
||||
if exists:
|
||||
PLUGINS_LOAD='plugins.load.paths'
|
||||
PLUGINS_ENTRY='plugins.entries.whispergate'
|
||||
PROVIDER_PATHS=[k for k in paths.keys() if k.startswith('models.providers[')]
|
||||
|
||||
# 1) restore plugins atomically to avoid transient schema failures
|
||||
pcur=subprocess.run(['openclaw','config','get','plugins','--json'],capture_output=True,text=True)
|
||||
plugins={}
|
||||
if pcur.returncode==0:
|
||||
plugins=json.loads(pcur.stdout)
|
||||
if not isinstance(plugins,dict):
|
||||
plugins={}
|
||||
|
||||
load=plugins.get('load') if isinstance(plugins.get('load'),dict) else {}
|
||||
entries=plugins.get('entries') if isinstance(plugins.get('entries'),dict) else {}
|
||||
|
||||
# restore plugins.load.paths from record
|
||||
info=paths.get(PLUGINS_LOAD,{'exists':False})
|
||||
if info.get('exists'):
|
||||
load['paths']=info.get('value')
|
||||
else:
|
||||
load.pop('paths',None)
|
||||
|
||||
# restore plugins.entries.whispergate from record
|
||||
info=paths.get(PLUGINS_ENTRY,{'exists':False})
|
||||
if info.get('exists'):
|
||||
entries['whispergate']=info.get('value')
|
||||
else:
|
||||
entries.pop('whispergate',None)
|
||||
|
||||
plugins['load']=load
|
||||
plugins['entries']=entries
|
||||
|
||||
pset=subprocess.run(['openclaw','config','set','plugins',json.dumps(plugins,ensure_ascii=False),'--json'],capture_output=True,text=True)
|
||||
if pset.returncode!=0:
|
||||
sys.stderr.write(pset.stderr or pset.stdout)
|
||||
raise SystemExit(1)
|
||||
|
||||
# 2) restore provider paths (usually custom no-reply provider)
|
||||
for path in PROVIDER_PATHS:
|
||||
info=paths.get(path,{'exists':False})
|
||||
if info.get('exists'):
|
||||
val=json.dumps(info.get('value'),ensure_ascii=False)
|
||||
p=subprocess.run(['openclaw','config','set',path,val,'--json'],capture_output=True,text=True)
|
||||
if p.returncode!=0:
|
||||
sys.stderr.write(p.stderr)
|
||||
sys.stderr.write(p.stderr or p.stdout)
|
||||
raise SystemExit(1)
|
||||
else:
|
||||
p=subprocess.run(['openclaw','config','unset',path],capture_output=True,text=True)
|
||||
if p.returncode!=0:
|
||||
# path may already be absent; tolerate common "not found" style failures
|
||||
txt=(p.stderr or p.stdout or '').lower()
|
||||
if 'not found' not in txt and 'missing' not in txt and 'does not exist' not in txt:
|
||||
sys.stderr.write(p.stderr)
|
||||
sys.stderr.write(p.stderr or p.stdout)
|
||||
raise SystemExit(1)
|
||||
|
||||
print('ok')
|
||||
PY
|
||||
|
||||
|
||||
Reference in New Issue
Block a user