use configparser::ini::Ini; use regex::Regex; use rustc_hash::FxHashSet; use serde::Serialize; use std::sync::LazyLock; use crate::{wheel, Error}; /// A script defining the name of the runnable entrypoint and the module and function that should be /// run. #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub(crate) struct Script { pub(crate) name: String, pub(crate) module: String, pub(crate) function: String, } impl Script { /// Parses a script definition like `foo.bar:main` or `foomod:main_bar [bar,baz]` /// /// /// /// Extras are supposed to be ignored, which happens if you pass None for extras pub(crate) fn from_value( script_name: &str, value: &str, extras: Option<&[String]>, ) -> Result, Error> { // "Within a value, readers must accept and ignore spaces (including multiple consecutive spaces) before or after the colon, // between the object reference and the left square bracket, between the extra names and the square brackets and colons delimiting them, // and after the right square bracket." // – https://packaging.python.org/en/latest/specifications/entry-points/#file-format static SCRIPT_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r"^(?P[\w\d_\-.]+)\s*:\s*(?P[\w\d_\-.]+)(?:\s*\[\s*(?P(?:[^,]+,?\s*)+)\])?\s*$").unwrap() }); let captures = SCRIPT_REGEX .captures(value) .ok_or_else(|| Error::InvalidWheel(format!("invalid console script: '{value}'")))?; if let Some(script_extras) = captures.name("extras") { if let Some(extras) = extras { let script_extras = script_extras .as_str() .split(',') .map(|extra| extra.trim().to_string()) .collect::>(); if !script_extras.is_subset(&extras.iter().cloned().collect()) { return Ok(None); } } } Ok(Some(Self { name: script_name.to_string(), module: captures.name("module").unwrap().as_str().to_string(), function: captures.name("function").unwrap().as_str().to_string(), })) } pub(crate) fn import_name(&self) -> &str { self.function .split_once('.') .map_or(&self.function, |(import_name, _)| import_name) } } pub(crate) fn scripts_from_ini( extras: Option<&[String]>, python_minor: u8, ini: String, ) -> Result<(Vec