mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Support user pyproject modifications again
This changes 'keep existing version' to 'sync project changes' when changes to the pyproject.toml file have been detected that are newer than the installer's version. Also adds a way to temporarily enable the launcher, as we needed some other trigger than the pyproject.toml file anyway, and this approach also solves #4165. And removes the 'quit' option, since it's an uncommon operation, and the user can just close the window instead. Short-term caveat: users with older launchers/addon will trigger the old pyproject.toml mtime bump, leading to a 'sync project changes' message that will not make much sense to a typical user.
This commit is contained in:
parent
c56fd3ee28
commit
3b18097550
3 changed files with 42 additions and 29 deletions
|
@ -124,17 +124,14 @@ def launcher_executable() -> str | None:
|
|||
|
||||
|
||||
def trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
"""Create a trigger file to request launcher UI on next run."""
|
||||
try:
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return
|
||||
|
||||
pyproject_path = Path(root) / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
trigger_path = Path(root) / ".want-launcher"
|
||||
trigger_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
|
|
@ -69,17 +69,14 @@ def add_python_requirements(reqs: list[str]) -> tuple[bool, str]:
|
|||
|
||||
|
||||
def trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
"""Create a trigger file to request launcher UI on next run."""
|
||||
try:
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return
|
||||
|
||||
pyproject_path = Path(root) / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
trigger_path = Path(root) / ".want-launcher"
|
||||
trigger_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ struct State {
|
|||
dist_python_version_path: std::path::PathBuf,
|
||||
uv_lock_path: std::path::PathBuf,
|
||||
sync_complete_marker: std::path::PathBuf,
|
||||
launcher_trigger_file: std::path::PathBuf,
|
||||
pyproject_modified_by_user: bool,
|
||||
previous_version: Option<String>,
|
||||
resources_dir: std::path::PathBuf,
|
||||
}
|
||||
|
@ -70,7 +72,6 @@ pub enum MainMenuChoice {
|
|||
ToggleBetas,
|
||||
ToggleCache,
|
||||
Uninstall,
|
||||
Quit,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -106,6 +107,8 @@ fn run() -> Result<()> {
|
|||
dist_python_version_path: resources_dir.join(".python-version"),
|
||||
uv_lock_path: uv_install_root.join("uv.lock"),
|
||||
sync_complete_marker: uv_install_root.join(".sync_complete"),
|
||||
launcher_trigger_file: uv_install_root.join(".want-launcher"),
|
||||
pyproject_modified_by_user: false, // calculated later
|
||||
previous_version: None,
|
||||
resources_dir,
|
||||
};
|
||||
|
@ -125,15 +128,15 @@ fn run() -> Result<()> {
|
|||
&state.user_python_version_path,
|
||||
)?;
|
||||
|
||||
let pyproject_has_changed = !state.sync_complete_marker.exists() || {
|
||||
let pyproject_toml_time = modified_time(&state.user_pyproject_path)?;
|
||||
let sync_complete_time = modified_time(&state.sync_complete_marker)?;
|
||||
Ok::<bool, anyhow::Error>(pyproject_toml_time > sync_complete_time)
|
||||
}
|
||||
.unwrap_or(true);
|
||||
let launcher_requested = state.launcher_trigger_file.exists();
|
||||
|
||||
if !pyproject_has_changed {
|
||||
// If venv is already up to date, launch Anki normally
|
||||
// Calculate whether user has custom edits that need syncing
|
||||
let pyproject_time = file_timestamp_secs(&state.user_pyproject_path);
|
||||
let sync_time = file_timestamp_secs(&state.sync_complete_marker);
|
||||
state.pyproject_modified_by_user = pyproject_time > sync_time;
|
||||
let pyproject_has_changed = state.pyproject_modified_by_user;
|
||||
if !launcher_requested && !pyproject_has_changed {
|
||||
// If no launcher request and venv is already up to date, launch Anki normally
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let cmd = build_python_command(&state, &args)?;
|
||||
launch_anki_normally(cmd)?;
|
||||
|
@ -143,6 +146,11 @@ fn run() -> Result<()> {
|
|||
// If we weren't in a terminal, respawn ourselves in one
|
||||
ensure_terminal_shown()?;
|
||||
|
||||
if launcher_requested {
|
||||
// Remove the trigger file to make request ephemeral
|
||||
let _ = remove_file(&state.launcher_trigger_file);
|
||||
}
|
||||
|
||||
print!("\x1B[2J\x1B[H"); // Clear screen and move cursor to top
|
||||
println!("\x1B[1mAnki Launcher\x1B[0m\n");
|
||||
|
||||
|
@ -313,9 +321,11 @@ fn main_menu_loop(state: &State) -> Result<()> {
|
|||
let menu_choice = get_main_menu_choice(state)?;
|
||||
|
||||
match menu_choice {
|
||||
MainMenuChoice::Quit => std::process::exit(0),
|
||||
MainMenuChoice::KeepExisting => {
|
||||
// Skip sync, just launch existing installation
|
||||
if state.pyproject_modified_by_user {
|
||||
// User has custom edits, sync them
|
||||
handle_version_install_or_update(state, MainMenuChoice::KeepExisting)?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
MainMenuChoice::ToggleBetas => {
|
||||
|
@ -372,14 +382,28 @@ fn write_sync_marker(sync_complete_marker: &std::path::Path) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Get mtime of provided file, or 0 if unavailable
|
||||
fn file_timestamp_secs(path: &std::path::Path) -> i64 {
|
||||
modified_time(path)
|
||||
.map(|t| t.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as i64)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
||||
loop {
|
||||
println!("1) Latest Anki (press Enter)");
|
||||
println!("2) Choose a version");
|
||||
|
||||
if let Some(current_version) = &state.current_version {
|
||||
let normalized_current = normalize_version(current_version);
|
||||
println!("3) Keep existing version ({normalized_current})");
|
||||
|
||||
if state.pyproject_modified_by_user {
|
||||
println!("3) Sync project changes");
|
||||
} else {
|
||||
println!("3) Keep existing version ({normalized_current})");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(prev_version) = &state.previous_version {
|
||||
if state.current_version.as_ref() != Some(prev_version) {
|
||||
let normalized_prev = normalize_version(prev_version);
|
||||
|
@ -400,7 +424,6 @@ fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
|||
);
|
||||
println!();
|
||||
println!("7) Uninstall");
|
||||
println!("8) Quit");
|
||||
print!("> ");
|
||||
let _ = stdout().flush();
|
||||
|
||||
|
@ -440,7 +463,6 @@ fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
|||
"5" => MainMenuChoice::ToggleBetas,
|
||||
"6" => MainMenuChoice::ToggleCache,
|
||||
"7" => MainMenuChoice::Uninstall,
|
||||
"8" => MainMenuChoice::Quit,
|
||||
_ => {
|
||||
println!("Invalid input. Please try again.");
|
||||
continue;
|
||||
|
@ -698,9 +720,6 @@ fn update_pyproject_for_version(menu_choice: MainMenuChoice, state: &State) -> R
|
|||
MainMenuChoice::Version(version_kind) => {
|
||||
apply_version_kind(&version_kind, state)?;
|
||||
}
|
||||
MainMenuChoice::Quit => {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue