做安装包版本

This commit is contained in:
2026-04-07 23:21:58 +08:00
parent d583e711f0
commit 920d142d9c
11 changed files with 669 additions and 42 deletions
Binary file not shown.
+113 -36
View File
@@ -4,6 +4,8 @@ import shutil
# 数据库放到 Windows 常见的 APPDATA 目录(避免写在项目目录)
APP_NAME = "CleanDesktopOrganizer"
_SCHEMA_VERSION_KEY = "schema_version"
LATEST_SCHEMA_VERSION = 1
_PROJECT_DB_PATH = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "data.db"
@@ -37,52 +39,127 @@ def get_conn():
_ensure_db_dir()
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
try:
conn.execute("PRAGMA foreign_keys=ON")
except Exception:
pass
return conn
def _get_schema_version(conn: sqlite3.Connection) -> int:
try:
row = conn.execute(
"SELECT value FROM settings WHERE key=?",
(_SCHEMA_VERSION_KEY,),
).fetchone()
if not row:
return 0
return int(str(row[0]).strip() or "0")
except Exception:
return 0
def _set_schema_version(conn: sqlite3.Connection, v: int):
conn.execute(
"INSERT INTO settings (key, value) VALUES (?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
(_SCHEMA_VERSION_KEY, str(int(v))),
)
def _table_has_column(conn: sqlite3.Connection, table: str, col: str) -> bool:
try:
rows = conn.execute(f"PRAGMA table_info({table})").fetchall()
return any((r[1] if isinstance(r, (tuple, list)) else r["name"]) == col for r in rows)
except Exception:
return False
def _apply_migrations(conn: sqlite3.Connection):
"""
版本化迁移(schema migration):
- 允许从任意旧版本升级到最新
- 每一步尽量幂等,并在事务中执行
"""
def m1():
# 基础表
conn.execute(
"""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
"""
)
conn.execute(
"""
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
position INTEGER DEFAULT 0,
folder_path TEXT DEFAULT ''
)
"""
)
conn.execute(
"""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL,
icon_path TEXT,
position INTEGER DEFAULT 0,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
)
"""
)
# 兼容更老的库:补字段
if not _table_has_column(conn, "groups", "folder_path"):
conn.execute("ALTER TABLE groups ADD COLUMN folder_path TEXT DEFAULT ''")
migrations = {
1: m1,
}
cur = _get_schema_version(conn)
# 未设置版本但已有表:视为 0,走迁移补齐并写入版本号
while cur < LATEST_SCHEMA_VERSION:
nxt = cur + 1
fn = migrations.get(nxt)
if fn is None:
raise RuntimeError(f"missing migration for version {nxt}")
with conn:
fn()
_set_schema_version(conn, nxt)
cur = nxt
def init_db():
_migrate_old_db_if_needed()
conn = get_conn()
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
position INTEGER DEFAULT 0,
folder_path TEXT DEFAULT ''
# 先确保 settings 表存在,才能读写 schema_version
with conn:
conn.execute(
"""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
"""
)
""")
c.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL,
icon_path TEXT,
position INTEGER DEFAULT 0,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
)
""")
c.execute("""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
""")
# 迁移:旧库没有 folder_path 字段时自动添加
try:
c.execute("ALTER TABLE groups ADD COLUMN folder_path TEXT DEFAULT ''")
conn.commit()
except Exception:
pass # 字段已存在则忽略
_apply_migrations(conn)
# 默认分组
c.execute("SELECT COUNT(*) FROM groups")
if c.fetchone()[0] == 0:
c.execute("INSERT INTO groups (name, position) VALUES ('常用程序', 0)")
conn.commit()
# 默认分组(数据迁移/初始化)
with conn:
row = conn.execute("SELECT COUNT(*) FROM groups").fetchone()
cnt = int(row[0] if row else 0)
if cnt == 0:
conn.execute("INSERT INTO groups (name, position) VALUES ('常用程序', 0)")
conn.close()
# 非结构类迁移(数据清洗/一次性转换)
_migrate_item_shortcut_paths_to_targets()