Android build v1.1.10
This commit is contained in:
+139
-1
@@ -1,15 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -23,6 +26,24 @@ GITEA_REPO = "i-want-to-heal"
|
||||
GITEA_TOKEN = "ed2db3fd54546e9658377d0551b3fc3961583f1d"
|
||||
BRANCH = "main"
|
||||
TRUENAS_PATH = Path("/mnt/usbssds/apps/iwanttoheal/app")
|
||||
PLAYER_DATA_TABLES = [
|
||||
"encounter_loot_roll_items",
|
||||
"encounter_loot_rolls",
|
||||
"dungeon_runs",
|
||||
"character_pvp_stats",
|
||||
"character_boss_stats",
|
||||
"character_inventory",
|
||||
"character_talents",
|
||||
"character_ability_slots",
|
||||
"action_encounter_loot_rolls",
|
||||
"action_dungeon_runs",
|
||||
"action_character_inventory",
|
||||
"action_gear_items",
|
||||
"action_characters",
|
||||
"sessions",
|
||||
"characters",
|
||||
"accounts",
|
||||
]
|
||||
|
||||
|
||||
def run(args: list[str], *, cwd: Path, env: dict[str, str] | None = None) -> None:
|
||||
@@ -30,6 +51,29 @@ def run(args: list[str], *, cwd: Path, env: dict[str, str] | None = None) -> Non
|
||||
subprocess.run(args, cwd=cwd, env=env, check=True)
|
||||
|
||||
|
||||
def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Build and publish an Android release.")
|
||||
parser.add_argument(
|
||||
"--reset-player-data",
|
||||
action="store_true",
|
||||
help="After release, back up the database and delete all accounts, characters, sessions, runs, loot, inventory, and PvP stats.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reset-db",
|
||||
type=Path,
|
||||
help="SQLite game.db path to reset. Defaults to mounted TrueNAS data/game.db when present, otherwise local data/game.db.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--yes-reset",
|
||||
action="store_true",
|
||||
help="Skip the RESET confirmation when used with --reset-player-data.",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
if args.yes_reset and not args.reset_player_data:
|
||||
parser.error("--yes-reset requires --reset-player-data")
|
||||
return args
|
||||
|
||||
|
||||
def prompt_version() -> str:
|
||||
current = GRADLE_FILE.read_text()
|
||||
match = re.search(r'versionName\s+"([^"]+)"', current)
|
||||
@@ -151,13 +195,107 @@ def update_truenas() -> None:
|
||||
print("Then restart app in TrueNAS UI.")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
def default_reset_database_path() -> Path:
|
||||
truenas_database = TRUENAS_PATH / "data" / "game.db"
|
||||
if truenas_database.exists():
|
||||
return truenas_database
|
||||
return REPO_ROOT / "data" / "game.db"
|
||||
|
||||
|
||||
def table_exists(database: sqlite3.Connection, table: str) -> bool:
|
||||
return database.execute(
|
||||
"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?",
|
||||
(table,),
|
||||
).fetchone() is not None
|
||||
|
||||
|
||||
def count_rows(database: sqlite3.Connection, table: str) -> int:
|
||||
if not table_exists(database, table):
|
||||
return 0
|
||||
return int(database.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0])
|
||||
|
||||
|
||||
def backup_database(database_path: Path) -> Path:
|
||||
backup_dir = database_path.parent / "backups"
|
||||
backup_dir.mkdir(parents=True, exist_ok=True)
|
||||
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
backup_path = backup_dir / f"{database_path.stem}-pre-player-reset-{timestamp}{database_path.suffix}"
|
||||
|
||||
source = sqlite3.connect(database_path)
|
||||
try:
|
||||
destination = sqlite3.connect(backup_path)
|
||||
try:
|
||||
source.backup(destination)
|
||||
finally:
|
||||
destination.close()
|
||||
finally:
|
||||
source.close()
|
||||
|
||||
return backup_path
|
||||
|
||||
|
||||
def reset_player_data(database_path: Path, *, assume_yes: bool) -> None:
|
||||
database_path = database_path.expanduser().resolve()
|
||||
if not database_path.exists():
|
||||
raise SystemExit(f"Database not found: {database_path}")
|
||||
|
||||
if not assume_yes:
|
||||
print(f"Reset target: {database_path}")
|
||||
confirmation = input("Type RESET to delete all accounts/characters/player data: ").strip()
|
||||
if confirmation != "RESET":
|
||||
raise SystemExit("Player data reset cancelled.")
|
||||
|
||||
backup_path = backup_database(database_path)
|
||||
database = sqlite3.connect(database_path)
|
||||
try:
|
||||
before = {
|
||||
"accounts": count_rows(database, "accounts"),
|
||||
"characters": count_rows(database, "characters"),
|
||||
"action_characters": count_rows(database, "action_characters"),
|
||||
"dungeon_runs": count_rows(database, "dungeon_runs"),
|
||||
"encounter_loot_rolls": count_rows(database, "encounter_loot_rolls"),
|
||||
}
|
||||
database.execute("PRAGMA foreign_keys = ON")
|
||||
database.execute("BEGIN")
|
||||
try:
|
||||
for table in PLAYER_DATA_TABLES:
|
||||
if table_exists(database, table):
|
||||
database.execute(f'DELETE FROM "{table}"')
|
||||
database.execute("COMMIT")
|
||||
except Exception:
|
||||
database.execute("ROLLBACK")
|
||||
raise
|
||||
|
||||
after_accounts = count_rows(database, "accounts")
|
||||
after_characters = count_rows(database, "characters")
|
||||
if after_accounts or after_characters:
|
||||
raise SystemExit(
|
||||
f"Player data reset incomplete: {after_accounts} accounts, {after_characters} characters remain."
|
||||
)
|
||||
|
||||
print(f"Database backup: {backup_path}")
|
||||
print(
|
||||
"Player data reset: "
|
||||
f"{before['accounts']} accounts, "
|
||||
f"{before['characters']} characters, "
|
||||
f"{before['action_characters']} action characters, "
|
||||
f"{before['dungeon_runs']} dungeon runs, "
|
||||
f"{before['encounter_loot_rolls']} loot rolls removed."
|
||||
)
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(sys.argv[1:] if argv is None else argv)
|
||||
os.chdir(REPO_ROOT)
|
||||
version = prompt_version()
|
||||
apk = build_apk(version)
|
||||
commit_and_push(version)
|
||||
create_gitea_release(version, apk)
|
||||
update_truenas()
|
||||
if args.reset_player_data:
|
||||
reset_player_data(args.reset_db or default_reset_database_path(), assume_yes=args.yes_reset)
|
||||
print("Done.")
|
||||
return 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user