mirror of https://github.com/astral-sh/uv
refactor(uv-trampoline,uv-trampoline-builder): address feedback
This commit is contained in:
parent
333306dd9f
commit
ee07f64b17
|
|
@ -619,11 +619,11 @@ mod test {
|
||||||
"#};
|
"#};
|
||||||
|
|
||||||
assert_snapshot!(format_err(input).await, @r#"
|
assert_snapshot!(format_err(input).await, @r#"
|
||||||
error: TOML parse error at line 8, column 16
|
error: TOML parse error at line 8, column 28
|
||||||
|
|
|
|
||||||
8 | tqdm = { url = invalid url to tqdm-4.66.0-py3-none-any.whl" }
|
8 | tqdm = { url = invalid url to tqdm-4.66.0-py3-none-any.whl" }
|
||||||
| ^
|
| ^
|
||||||
missing opening quote, expected `"`
|
missing comma between key-value pairs, expected `,`
|
||||||
"#);
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
use std::io::{self, Cursor, Write};
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uv_fs::Simplified;
|
|
||||||
use zip::ZipWriter;
|
|
||||||
use zip::write::SimpleFileOptions;
|
|
||||||
|
|
||||||
#[cfg(all(windows, target_arch = "x86"))]
|
#[cfg(all(windows, target_arch = "x86"))]
|
||||||
const LAUNCHER_I686_GUI: &[u8] =
|
const LAUNCHER_I686_GUI: &[u8] =
|
||||||
|
|
@ -36,12 +33,15 @@ const LAUNCHER_AARCH64_CONSOLE: &[u8] =
|
||||||
const RT_RCDATA: u16 = 10;
|
const RT_RCDATA: u16 = 10;
|
||||||
|
|
||||||
// Resource IDs matching uv-trampoline
|
// Resource IDs matching uv-trampoline
|
||||||
const RESOURCE_TRAMPOLINE_KIND: &str = "UV_TRAMPOLINE_KIND\0";
|
#[cfg(windows)]
|
||||||
const RESOURCE_PYTHON_PATH: &str = "UV_PYTHON_PATH\0";
|
const RESOURCE_TRAMPOLINE_KIND: windows::core::PCWSTR = windows::core::w!("UV_TRAMPOLINE_KIND");
|
||||||
|
#[cfg(windows)]
|
||||||
|
const RESOURCE_PYTHON_PATH: windows::core::PCWSTR = windows::core::w!("UV_PYTHON_PATH");
|
||||||
// Note: This does not need to be looked up as a resource, as we rely on `zipimport`
|
// Note: This does not need to be looked up as a resource, as we rely on `zipimport`
|
||||||
// to do the loading work. Still, keeping the content under a resource means that it
|
// to do the loading work. Still, keeping the content under a resource means that it
|
||||||
// sits nicely under the PE format.
|
// sits nicely under the PE format.
|
||||||
const RESOURCE_SCRIPT_DATA: &str = "UV_SCRIPT_DATA\0";
|
#[cfg(windows)]
|
||||||
|
const RESOURCE_SCRIPT_DATA: windows::core::PCWSTR = windows::core::w!("UV_SCRIPT_DATA");
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Launcher {
|
pub struct Launcher {
|
||||||
|
|
@ -67,8 +67,11 @@ impl Launcher {
|
||||||
use windows::Win32::System::LibraryLoader::LOAD_LIBRARY_AS_DATAFILE;
|
use windows::Win32::System::LibraryLoader::LOAD_LIBRARY_AS_DATAFILE;
|
||||||
use windows::Win32::System::LibraryLoader::LoadLibraryExW;
|
use windows::Win32::System::LibraryLoader::LoadLibraryExW;
|
||||||
|
|
||||||
let mut path_str = path.as_os_str().encode_wide().collect::<Vec<_>>();
|
let path_str = path
|
||||||
path_str.push(0);
|
.as_os_str()
|
||||||
|
.encode_wide()
|
||||||
|
.chain(std::iter::once(0))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// SAFETY: winapi call; null-terminated strings
|
// SAFETY: winapi call; null-terminated strings
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
@ -119,29 +122,38 @@ impl Launcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
pub fn write_to_file(self, file_path: &Path, is_gui: bool) -> Result<(), Error> {
|
pub fn write_to_file(self, file_path: &Path, is_gui: bool) -> Result<(), Error> {
|
||||||
let python_path = self.python_path.simplified_display().to_string();
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
// Write the launcher binary
|
Err(Error::NotWindows)
|
||||||
fs_err::write(file_path, get_launcher_bin(is_gui)?)?;
|
|
||||||
|
|
||||||
// Write resources
|
|
||||||
let resources = &[
|
|
||||||
(
|
|
||||||
RESOURCE_TRAMPOLINE_KIND,
|
|
||||||
&[self.kind.to_resource_value()][..],
|
|
||||||
),
|
|
||||||
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
|
||||||
];
|
|
||||||
if let Some(script_data) = self.script_data {
|
|
||||||
let mut all_resources = resources.to_vec();
|
|
||||||
all_resources.push((RESOURCE_SCRIPT_DATA, &script_data));
|
|
||||||
write_resources(file_path, &all_resources)?;
|
|
||||||
} else {
|
|
||||||
write_resources(file_path, resources)?;
|
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use uv_fs::Simplified;
|
||||||
|
let python_path = self.python_path.simplified_display().to_string();
|
||||||
|
|
||||||
Ok(())
|
// Write the launcher binary
|
||||||
|
fs_err::write(file_path, get_launcher_bin(is_gui)?)?;
|
||||||
|
|
||||||
|
// Write resources
|
||||||
|
let resources = &[
|
||||||
|
(
|
||||||
|
RESOURCE_TRAMPOLINE_KIND,
|
||||||
|
&[self.kind.to_resource_value()][..],
|
||||||
|
),
|
||||||
|
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
||||||
|
];
|
||||||
|
if let Some(script_data) = self.script_data {
|
||||||
|
let mut all_resources = resources.to_vec();
|
||||||
|
all_resources.push((RESOURCE_SCRIPT_DATA, &script_data));
|
||||||
|
write_resources(file_path, &all_resources)?;
|
||||||
|
} else {
|
||||||
|
write_resources(file_path, resources)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -166,6 +178,7 @@ pub enum LauncherKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LauncherKind {
|
impl LauncherKind {
|
||||||
|
#[cfg(windows)]
|
||||||
fn to_resource_value(self) -> u8 {
|
fn to_resource_value(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Self::Script => 1,
|
Self::Script => 1,
|
||||||
|
|
@ -203,6 +216,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps, unused_variables)]
|
#[allow(clippy::unnecessary_wraps, unused_variables)]
|
||||||
|
#[cfg(windows)]
|
||||||
fn get_launcher_bin(gui: bool) -> Result<&'static [u8], Error> {
|
fn get_launcher_bin(gui: bool) -> Result<&'static [u8], Error> {
|
||||||
Ok(match std::env::consts::ARCH {
|
Ok(match std::env::consts::ARCH {
|
||||||
#[cfg(all(windows, target_arch = "x86"))]
|
#[cfg(all(windows, target_arch = "x86"))]
|
||||||
|
|
@ -233,58 +247,54 @@ fn get_launcher_bin(gui: bool) -> Result<&'static [u8], Error> {
|
||||||
arch => {
|
arch => {
|
||||||
return Err(Error::UnsupportedWindowsArch(arch));
|
return Err(Error::UnsupportedWindowsArch(arch));
|
||||||
}
|
}
|
||||||
#[cfg(not(windows))]
|
|
||||||
_ => &[],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to write Windows PE resources
|
/// Helper to write Windows PE resources
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn write_resources(path: &Path, resources: &[(&str, &[u8])]) -> Result<(), Error> {
|
#[cfg(windows)]
|
||||||
#[cfg(not(windows))]
|
fn write_resources(path: &Path, resources: &[(windows::core::PCWSTR, &[u8])]) -> Result<(), Error> {
|
||||||
{
|
// SAFETY: winapi calls; null-terminated strings
|
||||||
Err(Error::NotWindows)
|
#[allow(unsafe_code)]
|
||||||
}
|
unsafe {
|
||||||
#[cfg(windows)]
|
use std::os::windows::ffi::OsStrExt;
|
||||||
{
|
use windows::Win32::System::LibraryLoader::{
|
||||||
// SAFETY: winapi calls; null-terminated strings
|
BeginUpdateResourceW, EndUpdateResourceW, UpdateResourceW,
|
||||||
#[allow(unsafe_code)]
|
};
|
||||||
unsafe {
|
|
||||||
use std::os::windows::ffi::OsStrExt;
|
|
||||||
use windows::Win32::System::LibraryLoader::{
|
|
||||||
BeginUpdateResourceW, EndUpdateResourceW, UpdateResourceW,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut path_str = path.as_os_str().encode_wide().collect::<Vec<_>>();
|
let path_str = path
|
||||||
path_str.push(0);
|
.as_os_str()
|
||||||
let handle = BeginUpdateResourceW(windows::core::PCWSTR(path_str.as_ptr()), false)
|
.encode_wide()
|
||||||
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
.chain(std::iter::once(0))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let handle = BeginUpdateResourceW(windows::core::PCWSTR(path_str.as_ptr()), false)
|
||||||
|
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
||||||
|
|
||||||
for (name, data) in resources {
|
for (name, data) in resources {
|
||||||
let mut name_null_term = name.encode_utf16().collect::<Vec<_>>();
|
UpdateResourceW(
|
||||||
name_null_term.push(0);
|
handle,
|
||||||
UpdateResourceW(
|
windows::core::PCWSTR(RT_RCDATA as *const _),
|
||||||
handle,
|
*name,
|
||||||
windows::core::PCWSTR(RT_RCDATA as *const _),
|
0,
|
||||||
windows::core::PCWSTR(name_null_term.as_ptr()),
|
Some(data.as_ptr().cast()),
|
||||||
0,
|
u32::try_from(data.len()).map_err(|_| Error::ResourceTooLarge)?,
|
||||||
Some(data.as_ptr().cast()),
|
)
|
||||||
u32::try_from(data.len()).map_err(|_| Error::ResourceTooLarge)?,
|
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
||||||
)
|
|
||||||
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
EndUpdateResourceW(handle, false)
|
|
||||||
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
EndUpdateResourceW(handle, false)
|
||||||
|
.map_err(|err| Error::Io(io::Error::from_raw_os_error(err.code().0)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
/// Safely reads a resource from a PE file
|
/// Safely reads a resource from a PE file
|
||||||
fn read_resource(handle: windows::Win32::Foundation::HMODULE, name: &str) -> Option<Vec<u8>> {
|
fn read_resource(
|
||||||
|
handle: windows::Win32::Foundation::HMODULE,
|
||||||
|
name: windows::core::PCWSTR,
|
||||||
|
) -> Option<Vec<u8>> {
|
||||||
// SAFETY: winapi calls; null-terminated strings; all pointers are checked.
|
// SAFETY: winapi calls; null-terminated strings; all pointers are checked.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -294,7 +304,7 @@ fn read_resource(handle: windows::Win32::Foundation::HMODULE, name: &str) -> Opt
|
||||||
// Find the resource
|
// Find the resource
|
||||||
let resource = FindResourceW(
|
let resource = FindResourceW(
|
||||||
Some(handle),
|
Some(handle),
|
||||||
windows::core::PCWSTR(name.encode_utf16().collect::<Vec<_>>().as_ptr()),
|
name,
|
||||||
windows::core::PCWSTR(RT_RCDATA as *const _),
|
windows::core::PCWSTR(RT_RCDATA as *const _),
|
||||||
);
|
);
|
||||||
if resource.is_invalid() {
|
if resource.is_invalid() {
|
||||||
|
|
@ -303,6 +313,9 @@ fn read_resource(handle: windows::Win32::Foundation::HMODULE, name: &str) -> Opt
|
||||||
|
|
||||||
// Get resource size and data
|
// Get resource size and data
|
||||||
let size = SizeofResource(Some(handle), resource);
|
let size = SizeofResource(Some(handle), resource);
|
||||||
|
if size == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let data = LoadResource(Some(handle), resource).ok()?;
|
let data = LoadResource(Some(handle), resource).ok()?;
|
||||||
let ptr = LockResource(data) as *const u8;
|
let ptr = LockResource(data) as *const u8;
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
|
|
@ -324,57 +337,67 @@ pub fn windows_script_launcher(
|
||||||
is_gui: bool,
|
is_gui: bool,
|
||||||
python_executable: impl AsRef<Path>,
|
python_executable: impl AsRef<Path>,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
// This method should only be called on Windows, but we avoid `#[cfg(windows)]` to retain
|
// This method should only be called on Windows, but we avoid function-scope
|
||||||
// compilation on all platforms.
|
// `#[cfg(windows)]` to retain compilation on all platforms.
|
||||||
if cfg!(not(windows)) {
|
#[cfg(not(windows))]
|
||||||
return Err(Error::NotWindows);
|
|
||||||
}
|
|
||||||
|
|
||||||
let launcher_bin: &[u8] = get_launcher_bin(is_gui)?;
|
|
||||||
|
|
||||||
let mut payload: Vec<u8> = Vec::new();
|
|
||||||
{
|
{
|
||||||
// We're using the zip writer, but with stored compression
|
Err(Error::NotWindows)
|
||||||
// https://github.com/njsmith/posy/blob/04927e657ca97a5e35bb2252d168125de9a3a025/src/trampolines/mod.rs#L75-L82
|
|
||||||
// https://github.com/pypa/distlib/blob/8ed03aab48add854f377ce392efffb79bb4d6091/PC/launcher.c#L259-L271
|
|
||||||
let stored =
|
|
||||||
SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
|
|
||||||
let mut archive = ZipWriter::new(Cursor::new(&mut payload));
|
|
||||||
let error_msg = "Writing to Vec<u8> should never fail";
|
|
||||||
archive.start_file("__main__.py", stored).expect(error_msg);
|
|
||||||
archive
|
|
||||||
.write_all(launcher_python_script.as_bytes())
|
|
||||||
.expect(error_msg);
|
|
||||||
archive.finish().expect(error_msg);
|
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
let python = python_executable.as_ref();
|
use zip::ZipWriter;
|
||||||
let python_path = python.simplified_display().to_string();
|
use zip::write::SimpleFileOptions;
|
||||||
|
|
||||||
// Start with base launcher binary
|
use uv_fs::Simplified;
|
||||||
// Create temporary file for the launcher
|
|
||||||
let temp_dir = tempfile::tempdir()?;
|
|
||||||
let temp_file = temp_dir
|
|
||||||
.path()
|
|
||||||
.join(format!("uv-trampoline-{}.exe", std::process::id()));
|
|
||||||
fs_err::write(&temp_file, launcher_bin)?;
|
|
||||||
|
|
||||||
// Write resources
|
let launcher_bin: &[u8] = get_launcher_bin(is_gui)?;
|
||||||
let resources = &[
|
|
||||||
(
|
|
||||||
RESOURCE_TRAMPOLINE_KIND,
|
|
||||||
&[LauncherKind::Script.to_resource_value()][..],
|
|
||||||
),
|
|
||||||
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
|
||||||
(RESOURCE_SCRIPT_DATA, &payload),
|
|
||||||
];
|
|
||||||
write_resources(&temp_file, resources)?;
|
|
||||||
|
|
||||||
// Read back the complete file
|
let mut payload: Vec<u8> = Vec::new();
|
||||||
let launcher = fs_err::read(&temp_file)?;
|
{
|
||||||
fs_err::remove_file(temp_file)?;
|
// We're using the zip writer, but with stored compression
|
||||||
|
// https://github.com/njsmith/posy/blob/04927e657ca97a5e35bb2252d168125de9a3a025/src/trampolines/mod.rs#L75-L82
|
||||||
|
// https://github.com/pypa/distlib/blob/8ed03aab48add854f377ce392efffb79bb4d6091/PC/launcher.c#L259-L271
|
||||||
|
let stored =
|
||||||
|
SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
|
||||||
|
let mut archive = ZipWriter::new(Cursor::new(&mut payload));
|
||||||
|
let error_msg = "Writing to Vec<u8> should never fail";
|
||||||
|
archive.start_file("__main__.py", stored).expect(error_msg);
|
||||||
|
archive
|
||||||
|
.write_all(launcher_python_script.as_bytes())
|
||||||
|
.expect(error_msg);
|
||||||
|
archive.finish().expect(error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(launcher)
|
let python = python_executable.as_ref();
|
||||||
|
let python_path = python.simplified_display().to_string();
|
||||||
|
|
||||||
|
// Start with base launcher binary
|
||||||
|
// Create temporary file for the launcher
|
||||||
|
let temp_dir = tempfile::TempDir::new()?;
|
||||||
|
let temp_file = temp_dir
|
||||||
|
.path()
|
||||||
|
.join(format!("uv-trampoline-{}.exe", std::process::id()));
|
||||||
|
fs_err::write(&temp_file, launcher_bin)?;
|
||||||
|
|
||||||
|
// Write resources
|
||||||
|
let resources = &[
|
||||||
|
(
|
||||||
|
RESOURCE_TRAMPOLINE_KIND,
|
||||||
|
&[LauncherKind::Script.to_resource_value()][..],
|
||||||
|
),
|
||||||
|
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
||||||
|
(RESOURCE_SCRIPT_DATA, &payload),
|
||||||
|
];
|
||||||
|
write_resources(&temp_file, resources)?;
|
||||||
|
|
||||||
|
// Read back the complete file
|
||||||
|
let launcher = fs_err::read(&temp_file)?;
|
||||||
|
fs_err::remove_file(temp_file)?;
|
||||||
|
|
||||||
|
Ok(launcher)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A minimal .exe launcher binary for Python.
|
/// A minimal .exe launcher binary for Python.
|
||||||
|
|
@ -385,39 +408,44 @@ pub fn windows_python_launcher(
|
||||||
python_executable: impl AsRef<Path>,
|
python_executable: impl AsRef<Path>,
|
||||||
is_gui: bool,
|
is_gui: bool,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
// This method should only be called on Windows, but we avoid `#[cfg(windows)]` to retain
|
// This method should only be called on Windows, but we avoid function-scope
|
||||||
// compilation on all platforms.
|
// `#[cfg(windows)]` to retain compilation on all platforms.
|
||||||
if cfg!(not(windows)) {
|
#[cfg(not(windows))]
|
||||||
return Err(Error::NotWindows);
|
{
|
||||||
|
Err(Error::NotWindows)
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use uv_fs::Simplified;
|
||||||
|
|
||||||
let launcher_bin: &[u8] = get_launcher_bin(is_gui)?;
|
let launcher_bin: &[u8] = get_launcher_bin(is_gui)?;
|
||||||
|
|
||||||
let python = python_executable.as_ref();
|
let python = python_executable.as_ref();
|
||||||
let python_path = python.simplified_display().to_string();
|
let python_path = python.simplified_display().to_string();
|
||||||
|
|
||||||
// Create temporary file for the launcher
|
// Create temporary file for the launcher
|
||||||
let temp_dir = tempfile::tempdir()?;
|
let temp_dir = tempfile::TempDir::new()?;
|
||||||
let temp_file = temp_dir
|
let temp_file = temp_dir
|
||||||
.path()
|
.path()
|
||||||
.join(format!("uv-trampoline-{}.exe", std::process::id()));
|
.join(format!("uv-trampoline-{}.exe", std::process::id()));
|
||||||
fs_err::write(&temp_file, launcher_bin)?;
|
fs_err::write(&temp_file, launcher_bin)?;
|
||||||
|
|
||||||
// Write resources
|
// Write resources
|
||||||
let resources = &[
|
let resources = &[
|
||||||
(
|
(
|
||||||
RESOURCE_TRAMPOLINE_KIND,
|
RESOURCE_TRAMPOLINE_KIND,
|
||||||
&[LauncherKind::Python.to_resource_value()][..],
|
&[LauncherKind::Python.to_resource_value()][..],
|
||||||
),
|
),
|
||||||
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
(RESOURCE_PYTHON_PATH, python_path.as_bytes()),
|
||||||
];
|
];
|
||||||
write_resources(&temp_file, resources)?;
|
write_resources(&temp_file, resources)?;
|
||||||
|
|
||||||
// Read back the complete file
|
// Read back the complete file
|
||||||
let launcher = fs_err::read(&temp_file)?;
|
let launcher = fs_err::read(&temp_file)?;
|
||||||
fs_err::remove_file(temp_file)?;
|
fs_err::remove_file(temp_file)?;
|
||||||
|
|
||||||
Ok(launcher)
|
Ok(launcher)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, windows))]
|
#[cfg(all(test, windows))]
|
||||||
|
|
@ -569,7 +597,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
/// Signs the given binary using `PowerShell`'s `Set-AuthenticodeSignature` with a temporary certificate.
|
/// Signs the given binary using `PowerShell`'s `Set-AuthenticodeSignature` with a temporary certificate.
|
||||||
fn sign_authenticode(bin_path: impl AsRef<Path>) {
|
fn sign_authenticode(bin_path: impl AsRef<Path>) {
|
||||||
let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");
|
let temp_dir = tempfile::TempDir::new().expect("Failed to create temporary directory");
|
||||||
let temp_pfx =
|
let temp_pfx =
|
||||||
create_temp_certificate(&temp_dir).expect("Failed to create self-signed certificate");
|
create_temp_certificate(&temp_dir).expect("Failed to create self-signed certificate");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ use crate::{error, format, warn};
|
||||||
const RT_RCDATA: u16 = 10;
|
const RT_RCDATA: u16 = 10;
|
||||||
|
|
||||||
/// Resource IDs for the trampoline metadata
|
/// Resource IDs for the trampoline metadata
|
||||||
const RESOURCE_TRAMPOLINE_KIND: &str = "UV_TRAMPOLINE_KIND\0";
|
const RESOURCE_TRAMPOLINE_KIND: windows::core::PCWSTR = windows::core::w!("UV_TRAMPOLINE_KIND");
|
||||||
const RESOURCE_PYTHON_PATH: &str = "UV_PYTHON_PATH\0";
|
const RESOURCE_PYTHON_PATH: windows::core::PCWSTR = windows::core::w!("UV_PYTHON_PATH");
|
||||||
|
|
||||||
/// The kind of trampoline.
|
/// The kind of trampoline.
|
||||||
enum TrampolineKind {
|
enum TrampolineKind {
|
||||||
|
|
@ -58,15 +58,13 @@ impl TrampolineKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Safely loads a resource from the current module
|
/// Safely loads a resource from the current module
|
||||||
fn load_resource(resource_id: &str) -> Option<Vec<u8>> {
|
fn load_resource(resource_id: windows::core::PCWSTR) -> Option<Vec<u8>> {
|
||||||
// SAFETY: winapi calls; null-terminated strings; all pointers are checked.
|
// SAFETY: winapi calls; null-terminated strings; all pointers are checked.
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut resource_id_null_term = resource_id.encode_utf16().collect::<Vec<_>>();
|
|
||||||
resource_id_null_term.push(0);
|
|
||||||
// Find the resource
|
// Find the resource
|
||||||
let resource = FindResourceW(
|
let resource = FindResourceW(
|
||||||
None,
|
None,
|
||||||
windows::core::PCWSTR(resource_id_null_term.as_ptr()),
|
resource_id,
|
||||||
windows::core::PCWSTR(RT_RCDATA as *const _),
|
windows::core::PCWSTR(RT_RCDATA as *const _),
|
||||||
);
|
);
|
||||||
if resource.is_invalid() {
|
if resource.is_invalid() {
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue