-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
159 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,161 @@ | ||
pub mod bounce; | ||
mod diagnostics; | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use std::io::{Cursor, Write}; | ||
use std::path::Path; | ||
use std::process::Command; | ||
use std::{env, io}; | ||
|
||
use anyhow::Result; | ||
use assert_cmd::prelude::OutputAssertExt; | ||
use assert_fs::prelude::PathChild; | ||
use fs_err::File; | ||
use thiserror::Error; | ||
use which::which; | ||
use zip::write::FileOptions; | ||
use zip::ZipWriter; | ||
|
||
use uv_trampoline_builder::windows_script_launcher; | ||
|
||
/// Wrapper script template function | ||
/// | ||
/// <https://github.com/pypa/pip/blob/7f8a6844037fb7255cfd0d34ff8e8cf44f2598d4/src/pip/_vendor/distlib/scripts.py#L41-L48> | ||
fn get_script_launcher(shebang: &str, is_gui: bool) -> String { | ||
if is_gui { | ||
format!( | ||
r##"{shebang} | ||
# -*- coding: utf-8 -*- | ||
import re | ||
import sys | ||
def make_gui() -> None: | ||
from tkinter import Tk, ttk | ||
root = Tk() | ||
root.title("uv Test App") | ||
frm = ttk.Frame(root, padding=10) | ||
frm.grid() | ||
ttk.Label(frm, text="Hello from uv-trampoline-gui.exe").grid(column=0, row=0) | ||
root.mainloop() | ||
if __name__ == "__main__": | ||
sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) | ||
sys.exit(make_gui()) | ||
"## | ||
) | ||
} else { | ||
format!( | ||
r##"{shebang} | ||
# -*- coding: utf-8 -*- | ||
import re | ||
import sys | ||
def main_console() -> None: | ||
print("Hello from uv-trampoline-console.exe", file=sys.stdout) | ||
print("Hello from uv-trampoline-console.exe", file=sys.stderr) | ||
for arg in sys.argv[1:]: | ||
print(arg, file=sys.stderr) | ||
if __name__ == "__main__": | ||
sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) | ||
sys.exit(main_console()) | ||
"## | ||
) | ||
} | ||
} | ||
|
||
/// Format the shebang for a given Python executable. | ||
/// | ||
/// Like pip, if a shebang is non-simple (too long or contains spaces), we use `/bin/sh` as the | ||
/// executable. | ||
/// | ||
/// See: <https://github.com/pypa/pip/blob/0ad4c94be74cc24874c6feb5bb3c2152c398a18e/src/pip/_vendor/distlib/scripts.py#L136-L165> | ||
fn format_shebang(executable: impl AsRef<Path>) -> String { | ||
// Convert the executable to a simplified path. | ||
let executable = executable.as_ref().display().to_string(); | ||
format!("#!{executable}") | ||
} | ||
|
||
#[test] | ||
fn generate_console_launcher() -> Result<()> { | ||
// Create Temp Dirs | ||
let temp_dir = assert_fs::TempDir::new()?; | ||
let console_bin_path = temp_dir.child("launcher.console.exe"); | ||
|
||
// Locate an arbitrary python installation from PATH | ||
let python_executable_path = which("python")?; | ||
|
||
// Generate Launcher Script | ||
let launcher_console_script = | ||
get_script_launcher(&format_shebang(&python_executable_path), false); | ||
|
||
// Generate Launcher Payload | ||
let console_launcher = | ||
windows_script_launcher(&launcher_console_script, false, &python_executable_path)?; | ||
|
||
// Create Launcher | ||
File::create(console_bin_path.path())?.write_all(console_launcher.as_ref())?; | ||
|
||
println!( | ||
"Wrote Console Launcher in {}", | ||
console_bin_path.path().display() | ||
); | ||
|
||
let stdout_predicate = "Hello from uv-trampoline-console.exe\r\n"; | ||
let stderr_predicate = "Hello from uv-trampoline-console.exe\r\n"; | ||
|
||
// Test Console Launcher | ||
#[cfg(windows)] | ||
Command::new(console_bin_path.path()) | ||
.assert() | ||
.success() | ||
.stdout(stdout_predicate) | ||
.stderr(stderr_predicate); | ||
|
||
let args_to_test = vec!["foo", "bar", "foo bar", "foo \"bar\"", "foo 'bar'"]; | ||
let stderr_predicate = format!("{}{}\r\n", stderr_predicate, args_to_test.join("\r\n")); | ||
|
||
// Test Console Launcher (with args) | ||
#[cfg(windows)] | ||
Command::new(console_bin_path.path()) | ||
.args(args_to_test) | ||
.assert() | ||
.success() | ||
.stdout(stdout_predicate) | ||
.stderr(stderr_predicate); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
#[ignore] | ||
fn generate_gui_launcher() -> Result<()> { | ||
// Create Temp Dirs | ||
let temp_dir = assert_fs::TempDir::new()?; | ||
let gui_bin_path = temp_dir.child("launcher.gui.exe"); | ||
|
||
// Locate an arbitrary pythonw installation from PATH | ||
let pythonw_executable_path = which("pythonw")?; | ||
|
||
// Generate Launcher Script | ||
let launcher_gui_script = | ||
get_script_launcher(&format_shebang(&pythonw_executable_path), true); | ||
|
||
// Generate Launcher Payload | ||
let gui_launcher = | ||
windows_script_launcher(&launcher_gui_script, true, &pythonw_executable_path)?; | ||
|
||
// Create Launcher | ||
File::create(gui_bin_path.path())?.write_all(gui_launcher.as_ref())?; | ||
|
||
println!("Wrote GUI Launcher in {}", gui_bin_path.path().display()); | ||
|
||
// Test GUI Launcher | ||
// NOTICE: This will spawn a GUI and will wait until you close the window. | ||
#[cfg(windows)] | ||
Command::new(gui_bin_path.path()).assert().success(); | ||
|
||
Ok(()) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.