fix(update): preserve unmanaged client settings

This commit is contained in:
Julian lechner committed 2026-09-30 09:22:55 +02:00
1 parent 097cec41c2
commit 3973ed48f3
3 files changed
+103 -64

No files matched your search

+87 -4
View File
@@ -60,16 +60,99 @@ def filter_flashbang(path):
return filter_options(path, flashbang_enabled=False)
def merge_json(current, managed):
if not isinstance(current, dict) or not isinstance(managed, dict):
return managed
result = dict(current)
if 'statusLine' not in managed:
result.pop('statusLine', None)
for key, value in managed.items():
if key == 'hooks' and isinstance(value, dict) and isinstance(result.get(key), dict):
hooks = dict(result[key])
for event in set(value) | {'Stop'}:
groups = value.get(event, [])
old_groups = hooks.get(event, [])
if isinstance(groups, list) and isinstance(old_groups, list):
retained = [group for group in old_groups if not any(
re.search(r'(?:flashbang|statusline|record-compact|session-state-pointer)\.(?:ps1|sh)',
str(hook.get('command', '')) + str(hook.get('command_windows', '')), re.I)
for hook in group.get('hooks', []) if isinstance(hook, dict)
)]
merged = groups + [group for group in retained if group not in groups]
if merged:
hooks[event] = merged
else:
hooks.pop(event, None)
else:
hooks[event] = value
result[key] = hooks
elif isinstance(value, dict) and isinstance(result.get(key), dict):
result[key] = merge_json(result[key], value)
else:
result[key] = value
return result
def merge_toml(current_text, managed_text):
tomllib.loads(current_text)
tomllib.loads(managed_text)
managed_root_keys = set(tomllib.loads(managed_text))
lines = current_text.splitlines(keepends=True)
root = []
blocks = []
active = root
for line in lines:
header = re.match(r'^\s*(\[\[?.+?\]\]?)\s*(?:#.*)?$', line.rstrip('\r\n'))
if header:
active = []
blocks.append((header.group(1), active))
if active is root:
assignment = re.match(r'^\s*([A-Za-z0-9_-]+)\s*=', line)
if assignment and assignment.group(1) in managed_root_keys:
continue
active.append(line)
managed_headers = set(re.findall(r'(?m)^\s*(\[\[?.+?\]\]?)\s*(?:#.*)?$', managed_text))
extras = []
for header, block in blocks:
plugin_table = re.match(r'^\[(?:plugins|marketplaces)(?:\.|\])', header)
array_table = header.startswith('[[')
owned_hook = any(re.search(r'(?:flashbang|statusline|record-compact|session-state-pointer)\.(?:ps1|sh)', line, re.I) for line in block)
if plugin_table and header in managed_headers:
raise ValueError('Cannot merge conflicting managed plugin tables.')
if header not in managed_headers or (array_table and not owned_hook):
extras.extend(block)
result = managed_text
if root and ''.join(root).strip():
managed_lines = managed_text.splitlines(keepends=True)
split = next((i for i, line in enumerate(managed_lines) if re.match(r'^\s*\[', line)), len(managed_lines))
result = ''.join(managed_lines[:split]).rstrip() + '\n' + ''.join(root).strip() + '\n' + ''.join(managed_lines[split:])
if extras:
result = result.rstrip() + '\n\n' + ''.join(extras).lstrip()
tomllib.loads(result)
return result
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('action', choices=('filter',))
parser.add_argument('--path', type=Path, required=True)
parser.add_argument('--flashbang', choices=('true', 'false'), required=True)
parser.add_argument('action', choices=('filter', 'merge-json', 'merge-toml'))
parser.add_argument('--path', type=Path)
parser.add_argument('--current', type=Path)
parser.add_argument('--flashbang', choices=('true', 'false'))
parser.add_argument('--statusline', choices=('true', 'false'), default='true')
args = parser.parse_args()
try:
sys.stdout.reconfigure(encoding='utf-8')
print(filter_options(args.path, args.flashbang == 'true', args.statusline == 'true'), end='')
if args.action == 'filter':
print(filter_options(args.path, args.flashbang == 'true', args.statusline == 'true'), end='')
else:
if args.action == 'merge-json':
current = json.loads(args.current.read_text(encoding='utf-8-sig'))
managed = json.load(sys.stdin)
print(json.dumps(merge_json(current, managed), indent=2, ensure_ascii=False) + '\n', end='')
else:
print(merge_toml(args.current.read_text(encoding='utf-8-sig'), sys.stdin.read()), end='')
except (OSError, ValueError, KeyError) as error:
print(f'Install options: {error}', file=sys.stderr)
sys.exit(1)