mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-09 09:43:47 +08:00
FrogPilot 0.9.7
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
|
||||
import datetime
|
||||
import filecmp
|
||||
import glob
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
import tarfile
|
||||
import threading
|
||||
import time
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.params_pyx import ParamKeyType
|
||||
from openpilot.common.time import system_time_valid
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
from openpilot.selfdrive.frogpilot.assets.theme_manager import HOLIDAY_THEME_PATH, ThemeManager
|
||||
from openpilot.selfdrive.frogpilot.frogpilot_utilities import run_cmd
|
||||
from openpilot.selfdrive.frogpilot.frogpilot_variables import MODELS_PATH, THEME_SAVE_PATH, FrogPilotVariables, get_frogpilot_toggles, params
|
||||
|
||||
def backup_directory(backup, destination, success_message, fail_message, minimum_backup_size=0, compressed=False):
|
||||
if compressed:
|
||||
destination_compressed = destination.with_suffix(".tar.gz")
|
||||
if destination_compressed.exists():
|
||||
print("Backup already exists. Aborting")
|
||||
return
|
||||
|
||||
in_progress_destination = destination.parent / (destination.name + "_in_progress")
|
||||
run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", in_progress_destination], "", fail_message)
|
||||
|
||||
in_progress_compressed = destination_compressed.with_suffix(".tar.gz_in_progress")
|
||||
with tarfile.open(in_progress_compressed, "w:gz") as tar:
|
||||
tar.add(in_progress_destination, arcname=destination.name)
|
||||
|
||||
run_cmd(["sudo", "rm", "-rf", in_progress_destination], success_message, fail_message)
|
||||
in_progress_compressed.rename(destination_compressed)
|
||||
|
||||
compressed_backup_size = destination_compressed.stat().st_size
|
||||
if minimum_backup_size == 0 or compressed_backup_size < minimum_backup_size:
|
||||
params.put_int("MinimumBackupSize", compressed_backup_size)
|
||||
else:
|
||||
if destination.exists():
|
||||
print("Backup already exists. Aborting")
|
||||
return
|
||||
|
||||
run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", destination], success_message, fail_message)
|
||||
|
||||
def cleanup_backups(directory, limit, success_message, fail_message, compressed=False):
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
backups = sorted(directory.glob("*_auto*"), key=lambda x: x.stat().st_mtime, reverse=True)
|
||||
for backup in backups[:]:
|
||||
if backup.name.endswith("_in_progress") or backup.name.endswith("_in_progress.tar.gz"):
|
||||
run_cmd(["sudo", "rm", "-rf", backup], "", fail_message)
|
||||
backups.remove(backup)
|
||||
|
||||
for oldest_backup in backups[limit:]:
|
||||
if oldest_backup.is_dir():
|
||||
run_cmd(["sudo", "rm", "-rf", oldest_backup], success_message, fail_message)
|
||||
else:
|
||||
run_cmd(["sudo", "rm", oldest_backup], success_message, fail_message)
|
||||
|
||||
def backup_frogpilot(build_metadata):
|
||||
backup_path = Path("/data/backups")
|
||||
maximum_backups = 5
|
||||
cleanup_backups(backup_path, maximum_backups, "Successfully cleaned up old FrogPilot backups", "Failed to cleanup old FrogPilot backups", compressed=True)
|
||||
|
||||
_, _, free = shutil.disk_usage(backup_path)
|
||||
minimum_backup_size = params.get_int("MinimumBackupSize")
|
||||
if free > minimum_backup_size * maximum_backups:
|
||||
directory = Path(BASEDIR)
|
||||
destination_directory = backup_path / f"{build_metadata.channel}_{build_metadata.openpilot.git_commit_date[12:-16]}_auto"
|
||||
backup_directory(directory, destination_directory, f"Successfully backed up FrogPilot to {destination_directory}", f"Failed to backup FrogPilot to {destination_directory}", minimum_backup_size, compressed=True)
|
||||
|
||||
def backup_toggles(params_storage):
|
||||
for key in params.all_keys():
|
||||
if params.get_key_type(key) & ParamKeyType.PERSISTENT:
|
||||
value = params.get(key)
|
||||
if value is not None:
|
||||
params_storage.put(key, value)
|
||||
|
||||
backup_path = Path("/data/toggle_backups")
|
||||
maximum_backups = 10
|
||||
cleanup_backups(backup_path, maximum_backups, "Successfully cleaned up old toggle backups", "Failed to cleanup old toggle backups")
|
||||
|
||||
directory = Path("/data/params/d")
|
||||
destination_directory = backup_path / f"{datetime.datetime.now().strftime('%Y-%m-%d_%I-%M%p').lower()}_auto"
|
||||
backup_directory(directory, destination_directory, f"Successfully backed up toggles to {destination_directory}", f"Failed to backup toggles to {destination_directory}")
|
||||
|
||||
def convert_params(params_storage):
|
||||
print("Starting to convert params")
|
||||
|
||||
def update_values(keys, mappings):
|
||||
for key in keys:
|
||||
for original, replacement in mappings.items():
|
||||
if params.get(key, encoding='utf-8') == original:
|
||||
params.put(key, replacement)
|
||||
if params_storage.get(key, encoding='utf-8') == original:
|
||||
params_storage.put(key, replacement)
|
||||
|
||||
priority_keys = ["SLCPriority1", "SLCPriority2", "SLCPriority3"]
|
||||
update_values(priority_keys, {"Offline Maps": "Map Data"})
|
||||
|
||||
bottom_key = ["StartupMessageBottom"]
|
||||
update_values(bottom_key, {"so I do what I want 🐸": "Human-tested, frog-approved 🐸"})
|
||||
|
||||
top_key = ["StartupMessageTop"]
|
||||
update_values(top_key, {"Hippity hoppity this is my property": "Hop in and buckle up!"})
|
||||
|
||||
models = [
|
||||
("Certified Herbalist", "CertifiedHerbalistDrives", "CertifiedHerbalistScore"),
|
||||
("Dissolved Oxygen", "DissolvedOxygenDrives", "DissolvedOxygenScore"),
|
||||
("Duck Amigo", "DuckAmigoDrives", "DuckAmigoScore"),
|
||||
("Los Angeles", "LosAngelesDrives", "LosAngelesScore"),
|
||||
("North Dakota", "NorthDakotaDrives", "NorthDakotaScore"),
|
||||
("Notre Dame", "NotreDameDrives", "NotreDameScore"),
|
||||
("Radical Turtle", "RadicalTurtleDrives", "RadicalTurtleScore"),
|
||||
("Recertified Herbalist", "RecertifiedHerbalistDrives", "RecertifiedHerbalistScore"),
|
||||
("SecretGoodOpenpilot", "SecretGoodOpenpilotDrives", "SecretGoodOpenpilotScore"),
|
||||
("WD-40", "WD40Drives", "WD40Score")
|
||||
]
|
||||
|
||||
try:
|
||||
model_drives_and_scores = json.loads(params.get("ModelDrivesAndScores") or "{}")
|
||||
except Exception as error:
|
||||
print(f"Error parsing ModelDrivesAndScores JSON: {error}. Initializing empty structure")
|
||||
model_drives_and_scores = {}
|
||||
|
||||
for model, drives_param, score_param in models:
|
||||
drives = params.get_int(drives_param)
|
||||
score = params.get_int(score_param)
|
||||
|
||||
if drives > 0 or score > 0:
|
||||
model_drives_and_scores[model] = {
|
||||
"Drives": drives,
|
||||
"Score": score
|
||||
}
|
||||
|
||||
params.remove(drives_param)
|
||||
params_storage.remove(drives_param)
|
||||
params.remove(score_param)
|
||||
params_storage.remove(score_param)
|
||||
|
||||
params.put("ModelDrivesAndScores", json.dumps(model_drives_and_scores))
|
||||
|
||||
print("Param conversion completed")
|
||||
|
||||
def frogpilot_boot_functions(build_metadata, params_storage):
|
||||
if params.get_bool("HasAcceptedTerms"):
|
||||
params_storage.clear_all()
|
||||
|
||||
source = THEME_SAVE_PATH / "distance_icons"
|
||||
destination = THEME_SAVE_PATH / "theme_packs"
|
||||
if source.exists():
|
||||
for item in source.iterdir():
|
||||
if item.is_dir():
|
||||
destination_path = destination / item.name / "distance_icons"
|
||||
destination_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for sub_item in item.iterdir():
|
||||
destination_file = destination_path / sub_item.name
|
||||
if destination_file.exists():
|
||||
destination_file.unlink()
|
||||
|
||||
shutil.move(sub_item, destination_path)
|
||||
|
||||
if not any(item.iterdir()):
|
||||
item.rmdir()
|
||||
|
||||
if not any(source.iterdir()):
|
||||
source.rmdir()
|
||||
|
||||
FrogPilotVariables().update(holiday_theme="stock", started=False)
|
||||
ThemeManager().update_active_theme(time_validated=system_time_valid(), frogpilot_toggles=get_frogpilot_toggles(), boot_run=True)
|
||||
|
||||
def backup_thread():
|
||||
while not system_time_valid():
|
||||
print("Waiting for system time to become valid...")
|
||||
time.sleep(1)
|
||||
|
||||
subprocess.run(["pkill", "-SIGUSR1", "-f", "system.updated.updated"], check=False)
|
||||
|
||||
backup_frogpilot(build_metadata)
|
||||
backup_toggles(params_storage)
|
||||
|
||||
threading.Thread(target=backup_thread, daemon=True).start()
|
||||
|
||||
def setup_frogpilot(build_metadata):
|
||||
run_cmd(["sudo", "mount", "-o", "remount,rw", "/persist"], "Successfully remounted /persist as read-write", "Failed to remount /persist")
|
||||
|
||||
Path(MODELS_PATH).mkdir(parents=True, exist_ok=True)
|
||||
Path(THEME_SAVE_PATH).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for source_suffix, destination_suffix in [
|
||||
("world_frog_day/colors", "theme_packs/frog/colors"),
|
||||
("world_frog_day/distance_icons", "theme_packs/frog-animated/distance_icons"),
|
||||
("world_frog_day/icons", "theme_packs/frog-animated/icons"),
|
||||
("world_frog_day/signals", "theme_packs/frog/signals"),
|
||||
("world_frog_day/sounds", "theme_packs/frog/sounds"),
|
||||
]:
|
||||
source = Path(HOLIDAY_THEME_PATH) / source_suffix
|
||||
destination = Path(THEME_SAVE_PATH) / destination_suffix
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copytree(source, destination, dirs_exist_ok=True)
|
||||
|
||||
for source_suffix, destination_suffix in [
|
||||
("world_frog_day/steering_wheel/wheel.png", "steering_wheels/frog.png"),
|
||||
]:
|
||||
source = Path(HOLIDAY_THEME_PATH) / source_suffix
|
||||
destination = Path(THEME_SAVE_PATH) / destination_suffix
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(source, destination)
|
||||
|
||||
run_cmd(["sudo", "mount", "-o", "remount,rw", "/"], "Successfully remounted the file system as read-write", "Failed to remount the file system")
|
||||
boot_logo_location = Path("/usr/comma/bg.jpg")
|
||||
frogpilot_boot_logo = Path(__file__).parent / "assets/other_images/frogpilot_boot_logo.png"
|
||||
if not filecmp.cmp(frogpilot_boot_logo, boot_logo_location, shallow=False):
|
||||
run_cmd(["sudo", "cp", frogpilot_boot_logo, boot_logo_location], "Successfully replaced boot logo", "Failed to replace boot logo")
|
||||
|
||||
if build_metadata.channel == "FrogPilot-Development":
|
||||
subprocess.run(["sudo", "python3", "/persist/frogsgomoo.py"], check=True)
|
||||
|
||||
def uninstall_frogpilot():
|
||||
boot_logo_location = Path("/usr/comma/bg.jpg")
|
||||
stock_boot_logo = Path(__file__).parent / "assets/other_images/original_bg.jpg"
|
||||
run_cmd(["sudo", "cp", stock_boot_logo, boot_logo_location], "Successfully restored the stock boot logo", "Failed to restore the stock boot logo")
|
||||
|
||||
HARDWARE.uninstall()
|
||||
Reference in New Issue
Block a user