update ffl run impls

This commit is contained in:
llama 2025-11-02 17:58:48 +08:00
parent cea6263688
commit 2c018574e1
No known key found for this signature in database
GPG key ID: 0B7543854B9413C3
2 changed files with 9 additions and 81 deletions

View file

@ -6,10 +6,9 @@ use std::ffi::CString;
use std::os::unix::prelude::OsStrExt; use std::os::unix::prelude::OsStrExt;
use anki_io::ToUtf8Path; use anki_io::ToUtf8Path;
use anyhow::anyhow;
use anyhow::Result; use anyhow::Result;
use crate::get_libpython_path; use crate::get_python_env_info;
use crate::platform::PyFfi; use crate::platform::PyFfi;
use crate::State; use crate::State;
@ -72,44 +71,12 @@ impl PyFfi {
} }
pub fn run(state: &State) -> Result<()> { pub fn run(state: &State) -> Result<()> {
let lib_path = get_libpython_path(state)?; let (version, lib_path, exec) = get_python_env_info(state)?;
// NOTE: activate venv before loading lib
let path = std::env::var("PATH")?;
let paths = std::env::split_paths(&path);
let path = std::env::join_paths(std::iter::once(state.venv_folder.join("bin")).chain(paths))?;
std::env::set_var("PATH", path);
std::env::set_var("VIRTUAL_ENV", &state.venv_folder);
std::env::set_var("PYTHONHOME", "");
std::env::set_var("ANKI_LAUNCHER", std::env::current_exe()?.utf8()?.as_str()); std::env::set_var("ANKI_LAUNCHER", std::env::current_exe()?.utf8()?.as_str());
std::env::set_var("ANKI_LAUNCHER_UV", state.uv_path.utf8()?.as_str()); std::env::set_var("ANKI_LAUNCHER_UV", state.uv_path.utf8()?.as_str());
std::env::set_var("UV_PROJECT", state.uv_install_root.utf8()?.as_str()); std::env::set_var("UV_PROJECT", state.uv_install_root.utf8()?.as_str());
std::env::remove_var("SSLKEYLOGFILE"); std::env::remove_var("SSLKEYLOGFILE");
let ffi = PyFfi::load(lib_path)?; PyFfi::load(lib_path, exec)?.run(&version, None)
// NOTE: sys.argv would normally be set via PyConfig, but we don't have it here
let args: String = std::env::args()
.skip(1)
.map(|s| format!(r#","{s}""#))
.collect();
// NOTE:
// the venv activation script doesn't seem to be
// necessary for linux, only PATH and VIRTUAL_ENV
// but just call it anyway to have a standard setup
let venv_activate_path = state.venv_folder.join("bin/activate_this.py");
let venv_activate_path = venv_activate_path
.as_os_str()
.to_str()
.ok_or_else(|| anyhow!("failed to get venv activation script path"))?;
let preamble = std::ffi::CString::new(format!(
r#"import sys, runpy; sys.argv = ['Anki'{args}]; runpy.run_path("{venv_activate_path}")"#,
))?;
ffi.run(preamble)?;
Ok(())
} }

View file

@ -32,7 +32,7 @@ use windows::Win32::System::Registry::REG_SZ;
use windows::Win32::System::SystemInformation::OSVERSIONINFOW; use windows::Win32::System::SystemInformation::OSVERSIONINFOW;
use windows::Win32::UI::Shell::SetCurrentProcessExplicitAppUserModelID; use windows::Win32::UI::Shell::SetCurrentProcessExplicitAppUserModelID;
use crate::get_libpython_path; use crate::get_python_env_info;
use crate::platform::PyFfi; use crate::platform::PyFfi;
use crate::State; use crate::State;
@ -335,58 +335,19 @@ impl PyFfi {
} }
pub fn run(state: &State, console: bool) -> Result<()> { pub fn run(state: &State, console: bool) -> Result<()> {
let lib_path = get_libpython_path(state)?; let (version, lib_path, exec) = get_python_env_info(state)?;
// NOTE: needed for 3.9 on windows (not for 3.13)
std::env::set_current_dir(
lib_path
.parent()
.ok_or_else(|| anyhow!("expected parent dir for lib_path: {lib_path:?}"))?,
)?;
let path = std::env::var("PATH")?;
let paths = std::env::split_paths(&path);
let path =
std::env::join_paths(std::iter::once(state.venv_folder.join("Scripts")).chain(paths))?;
std::env::set_var("PATH", path);
std::env::set_var("VIRTUAL_ENV", &state.venv_folder);
std::env::set_var("PYTHONHOME", "");
std::env::set_var("ANKI_LAUNCHER", std::env::current_exe()?.utf8()?.as_str()); std::env::set_var("ANKI_LAUNCHER", std::env::current_exe()?.utf8()?.as_str());
std::env::set_var("ANKI_LAUNCHER_UV", state.uv_path.utf8()?.as_str()); std::env::set_var("ANKI_LAUNCHER_UV", state.uv_path.utf8()?.as_str());
std::env::set_var("UV_PROJECT", state.uv_install_root.utf8()?.as_str()); std::env::set_var("UV_PROJECT", state.uv_install_root.utf8()?.as_str());
std::env::remove_var("SSLKEYLOGFILE"); std::env::remove_var("SSLKEYLOGFILE");
let ffi = PyFfi::load(lib_path)?;
let args: String = std::env::args()
.skip(1)
.map(|s| format!(r#","{s}""#))
.collect::<String>()
.replace('\\', "\\\\");
let venv_activate_path = state.venv_folder.join("Scripts\\activate_this.py");
let venv_activate_path = venv_activate_path
.as_os_str()
.to_str()
.ok_or_else(|| anyhow!("failed to get venv activation script path"))?
.replace('\\', "\\\\");
// NOTE: without windows_subsystem=console or pythonw, // NOTE: without windows_subsystem=console or pythonw,
// we need to reconnect stdin/stdout/stderr within the interp // we need to reconnect stdin/stdout/stderr within the interp
// reconnect_stdio_to_console doesn't make a difference here // reconnect_stdio_to_console doesn't make a difference here
let console_snippet = if console { let preamble = console.then_some(
r#" sys.stdout = sys.stderr = open("CONOUT$", "w"); sys.stdin = open("CONIN$", "r");"# cr#"import sys; sys.stdout = sys.stderr = open("CONOUT$", "w"); sys.stdin = open("CONIN$", "r");"#,
} else { );
""
};
// NOTE: windows needs the venv activation script PyFfi::load(lib_path, exec)?.run(&version, preamble)
let preamble = CString::new(format!(
r#"import sys, runpy; sys.argv = ['Anki'{args}]; runpy.run_path("{venv_activate_path}");{console_snippet}"#,
))?;
ffi.run(preamble)?;
Ok(())
} }