use std::collections::HashMap; use std::ffi::OsString; use std::io::{BufRead, BufReader, BufWriter, Cursor, Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; use std::{env, io, iter}; use configparser::ini::Ini; use data_encoding::BASE64URL_NOPAD; use fs_err as fs; use fs_err::{DirEntry, File}; use mailparse::MailHeaderMap; use rustc_hash::{FxHashMap, FxHashSet}; use sha2::{Digest, Sha256}; use tempfile::tempdir; use tracing::{debug, error, span, warn, Level}; use walkdir::WalkDir; use zip::result::ZipError; use zip::write::FileOptions; use zip::{ZipArchive, ZipWriter}; use distribution_filename::WheelFilename; use pypi_types::DirectUrl; use crate::install_location::{InstallLocation, LockedDir}; use crate::record::RecordEntry; use crate::script::Script; use crate::{find_dist_info, Error}; /// `#!/usr/bin/env python` pub const SHEBANG_PYTHON: &str = "#!/usr/bin/env python"; pub(crate) const LAUNCHER_T32: &[u8] = include_bytes!("../windows-launcher/t32.exe"); pub(crate) const LAUNCHER_T64: &[u8] = include_bytes!("../windows-launcher/t64.exe"); pub(crate) const LAUNCHER_T64_ARM: &[u8] = include_bytes!("../windows-launcher/t64-arm.exe"); /// Wrapper script template function /// /// pub fn get_script_launcher(module: &str, import_name: &str, shebang: &str) -> String { format!( r##"{shebang} # -*- coding: utf-8 -*- import re import sys from {module} import {import_name} if __name__ == "__main__": sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) sys.exit({import_name}()) "## ) } /// Part of entrypoints parsing pub(crate) fn read_scripts_from_section( scripts_section: &HashMap>, section_name: &str, extras: Option<&[String]>, ) -> Result, Error> { let mut scripts = Vec::new(); for (script_name, python_location) in scripts_section { match python_location { Some(value) => { if let Some(script) = Script::from_value(script_name, value, extras)? { scripts.push(script); } } None => { return Err(Error::InvalidWheel(format!( "[{section_name}] key {script_name} must have a value" ))); } } } Ok(scripts) } /// Parses the `entry_points.txt` entry in the wheel for console scripts /// /// Returns (`script_name`, module, function) /// /// Extras are supposed to be ignored, which happens if you pass None for extras fn parse_scripts( archive: &mut ZipArchive, dist_info_dir: &str, extras: Option<&[String]>, ) -> Result<(Vec