123ba0d0fa
- auth/jwt/header 认证流程更新,会话与令牌处理增强 - 通信(ChatWindow/ConversationList/Network)更新 - tauri backend.rs/remote.rs、tauri.conf.json 更新 - pineagents app 路由(agent_gate/opc)与配置更新
234 lines
7.7 KiB
Python
Executable File
234 lines
7.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
版本号同步脚本:从根目录 VERSION 文件读取版本号,同步到各端配置文件。
|
|
|
|
单一数据源:agent-desktop/VERSION
|
|
同步目标:
|
|
- console/src-tauri/tauri.conf.json (version 字段)
|
|
- console/src-tauri/Cargo.toml (version 字段)
|
|
- src/pineagents/branding.py (version 字段)
|
|
- src/pineagents/config/config.py (app_version 默认值)
|
|
|
|
用法:
|
|
uv run scripts/sync_version.py # 同步版本号
|
|
uv run scripts/sync_version.py --check # 仅检查是否一致,不修改
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
VERSION_FILE = ROOT / "VERSION"
|
|
|
|
|
|
def read_version() -> str:
|
|
"""从 VERSION 文件读取版本号。"""
|
|
if not VERSION_FILE.is_file():
|
|
print(f"错误:VERSION 文件不存在: {VERSION_FILE}", file=sys.stderr)
|
|
sys.exit(1)
|
|
version = VERSION_FILE.read_text(encoding="utf-8").strip()
|
|
if not version:
|
|
print("错误:VERSION 文件为空", file=sys.stderr)
|
|
sys.exit(1)
|
|
return version
|
|
|
|
|
|
def pep440_to_semver(version: str) -> str:
|
|
"""将 PEP 440 版本号转换为 semver 格式(Tauri 要求)。
|
|
|
|
转换规则:
|
|
0.0.1b3 -> 0.0.1-beta.3
|
|
0.0.1a1 -> 0.0.1-alpha.1
|
|
0.0.1rc1 -> 0.0.1-rc.1
|
|
0.0.1 -> 0.0.1
|
|
0.0.1.post1 -> 0.0.1-post.1
|
|
0.0.1.dev1 -> 0.0.1-dev.1
|
|
"""
|
|
# 已经是 semver 格式(包含 -),直接返回
|
|
if "-" in version:
|
|
return version
|
|
|
|
# 匹配预发布标签:a/b/rc + 数字
|
|
match = re.match(r"^(\d+\.\d+\.\d+)(a|b|rc|alpha|beta)(\d+)$", version, re.IGNORECASE)
|
|
if match:
|
|
base, label, num = match.groups()
|
|
label = label.lower()
|
|
if label == "a":
|
|
label = "alpha"
|
|
elif label == "b":
|
|
label = "beta"
|
|
return f"{base}-{label}.{num}"
|
|
|
|
# 匹配 .postN / .devN
|
|
match = re.match(r"^(\d+\.\d+\.\d+)\.(post|dev)(\d+)$", version, re.IGNORECASE)
|
|
if match:
|
|
base, label, num = match.groups()
|
|
return f"{base}-{label.lower()}.{num}"
|
|
|
|
# 纯版本号,直接返回
|
|
return version
|
|
|
|
|
|
def sync_tauri_conf(version: str, check_only: bool = False) -> bool:
|
|
"""同步版本号到 tauri.conf.json。
|
|
|
|
注意:Tauri 要求 version 字段必须是 semver 格式,
|
|
因此这里将 PEP 440 格式转换为 semver 格式后再写入。
|
|
例如:0.0.1b3 -> 0.0.1-beta.3
|
|
"""
|
|
path = ROOT / "console" / "src-tauri" / "tauri.conf.json"
|
|
if not path.is_file():
|
|
print(f"跳过:文件不存在 {path}")
|
|
return True
|
|
|
|
semver_version = pep440_to_semver(version)
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
|
|
old_version = data.get("version", "")
|
|
if old_version == semver_version:
|
|
print(f" ✓ tauri.conf.json 已是 {semver_version} (semver)")
|
|
return True
|
|
|
|
if check_only:
|
|
print(f" ✗ tauri.conf.json 不一致: {old_version} → {semver_version} (semver)")
|
|
return False
|
|
|
|
data["version"] = semver_version
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
print(f" ✓ tauri.conf.json 已更新: {old_version} → {semver_version} (semver)")
|
|
return True
|
|
|
|
|
|
def sync_cargo_toml(version: str, check_only: bool = False) -> bool:
|
|
"""同步版本号到 Cargo.toml。
|
|
|
|
注意:Cargo 要求 version 字段必须是 semver 格式,
|
|
因此这里将 PEP 440 格式转换为 semver 格式后再写入。
|
|
例如:0.0.1b3 -> 0.0.1-beta.3
|
|
"""
|
|
path = ROOT / "console" / "src-tauri" / "Cargo.toml"
|
|
if not path.is_file():
|
|
print(f"跳过:文件不存在 {path}")
|
|
return True
|
|
|
|
semver_version = pep440_to_semver(version)
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
# 匹配 [package] 下的 version = "x.x.x"
|
|
pattern = re.compile(r'^(\s*version\s*=\s*)"[^"]*"', re.MULTILINE)
|
|
match = pattern.search(content)
|
|
if not match:
|
|
print(f" ✗ Cargo.toml 未找到 version 字段")
|
|
return False
|
|
|
|
old_version = match.group(0).split('"')[1]
|
|
if old_version == semver_version:
|
|
print(f" ✓ Cargo.toml 已是 {semver_version} (semver)")
|
|
return True
|
|
|
|
if check_only:
|
|
print(f" ✗ Cargo.toml 不一致: {old_version} → {semver_version} (semver)")
|
|
return False
|
|
|
|
new_content = pattern.sub(f'{match.group(1)}"{semver_version}"', content, count=1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" ✓ Cargo.toml 已更新: {old_version} → {semver_version} (semver)")
|
|
return True
|
|
|
|
|
|
def sync_branding_py(version: str, check_only: bool = False) -> bool:
|
|
"""同步版本号到 branding.py。"""
|
|
path = ROOT / "src" / "pineagents" / "branding.py"
|
|
if not path.is_file():
|
|
print(f"跳过:文件不存在 {path}")
|
|
return True
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
pattern = re.compile(r'(\s*version\s*:\s*str\s*=\s*)"[^"]*"')
|
|
match = pattern.search(content)
|
|
if not match:
|
|
print(f" ✗ branding.py 未找到 version 字段")
|
|
return False
|
|
|
|
old_version = match.group(0).split('"')[1]
|
|
if old_version == version:
|
|
print(f" ✓ branding.py 已是 {version}")
|
|
return True
|
|
|
|
if check_only:
|
|
print(f" ✗ branding.py 不一致: {old_version} → {version}")
|
|
return False
|
|
|
|
new_content = pattern.sub(f'{match.group(1)}"{version}"', content, count=1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" ✓ branding.py 已更新: {old_version} → {version}")
|
|
return True
|
|
|
|
|
|
def sync_config_py(version: str, check_only: bool = False) -> bool:
|
|
"""同步版本号到 config.py 的 app_version 默认值。"""
|
|
path = ROOT / "src" / "pineagents" / "config" / "config.py"
|
|
if not path.is_file():
|
|
print(f"跳过:文件不存在 {path}")
|
|
return True
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
# 匹配 app_version: str = Field( default="x.x.x",
|
|
pattern = re.compile(r'(app_version\s*:\s*str\s*=\s*Field\(\s*default\s*=\s*)"[^"]*"')
|
|
match = pattern.search(content)
|
|
if not match:
|
|
print(f" ✗ config.py 未找到 app_version 字段")
|
|
return False
|
|
|
|
old_version = match.group(0).split('"')[1]
|
|
if old_version == version:
|
|
print(f" ✓ config.py 已是 {version}")
|
|
return True
|
|
|
|
if check_only:
|
|
print(f" ✗ config.py 不一致: {old_version} → {version}")
|
|
return False
|
|
|
|
new_content = pattern.sub(f'{match.group(1)}"{version}"', content, count=1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" ✓ config.py 已更新: {old_version} → {version}")
|
|
return True
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="同步版本号到各端配置文件")
|
|
parser.add_argument("--check", action="store_true", help="仅检查是否一致,不修改")
|
|
args = parser.parse_args()
|
|
|
|
version = read_version()
|
|
print(f"{'检查' if args.check else '同步'}版本号: {version}")
|
|
print(f"数据源: {VERSION_FILE}")
|
|
print()
|
|
|
|
results = []
|
|
results.append(sync_tauri_conf(version, args.check))
|
|
results.append(sync_cargo_toml(version, args.check))
|
|
results.append(sync_branding_py(version, args.check))
|
|
results.append(sync_config_py(version, args.check))
|
|
|
|
print()
|
|
if all(results):
|
|
print("✓ 所有配置文件版本号一致")
|
|
sys.exit(0)
|
|
else:
|
|
print("✗ 部分配置文件版本号不一致" + ("(请运行 uv run scripts/sync_version.py 同步)" if args.check else ""))
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|