use std::env;
use serde::{Deserialize, Serialize};
use tracing::instrument;
use uv_pep508::MarkerEnvironment;
use uv_platform_tags::{Os, Platform};
use uv_static::EnvVars;
use uv_version::version;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Installer {
pub name: Option<String>,
pub version: Option<String>,
pub subcommand: Option<Vec<String>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Implementation {
pub name: Option<String>,
pub version: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Libc {
pub lib: Option<String>,
pub version: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Distro {
pub name: Option<String>,
pub version: Option<String>,
pub id: Option<String>,
pub libc: Option<Libc>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct System {
pub name: Option<String>,
pub release: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct LineHaul {
pub installer: Option<Installer>,
pub python: Option<String>,
pub implementation: Option<Implementation>,
pub distro: Option<Distro>,
pub system: Option<System>,
pub cpu: Option<String>,
pub openssl_version: Option<String>,
pub setuptools_version: Option<String>,
pub rustc_version: Option<String>,
pub ci: Option<bool>,
}
impl LineHaul {
#[instrument(name = "linehaul", skip_all)]
pub fn new(
markers: Option<&MarkerEnvironment>,
platform: Option<&Platform>,
subcommand: Option<Vec<String>>,
) -> Self {
let looks_like_ci = [
EnvVars::BUILD_BUILDID,
EnvVars::BUILD_ID,
EnvVars::CI,
EnvVars::PIP_IS_CI,
]
.iter()
.find_map(|&var_name| env::var(var_name).ok().map(|_| true));
let libc = match platform.map(Platform::os) {
Some(Os::Manylinux { major, minor }) => Some(Libc {
lib: Some("glibc".to_string()),
version: Some(format!("{major}.{minor}")),
}),
Some(Os::Musllinux { major, minor }) => Some(Libc {
lib: Some("musl".to_string()),
version: Some(format!("{major}.{minor}")),
}),
_ => None,
};
let distro: Option<Distro> = if cfg!(target_os = "linux") {
sys_info::linux_os_release().ok().map(|info| Distro {
id: info.version_codename,
name: info.name,
version: info.version_id,
libc,
})
} else if cfg!(target_os = "macos") {
let version = match platform.map(Platform::os) {
Some(Os::Macos { major, minor }) => Some(format!("{major}.{minor}")),
_ => None,
};
Some(Distro {
id: None,
name: Some("macOS".to_string()),
version,
libc: None,
})
} else {
None
};
Self {
installer: Option::from(Installer {
name: Some("uv".to_string()),
version: Some(version().to_string()),
subcommand,
}),
python: markers.map(|markers| markers.python_full_version().version.to_string()),
implementation: Option::from(Implementation {
name: markers.map(|markers| markers.platform_python_implementation().to_string()),
version: markers.map(|markers| markers.python_full_version().version.to_string()),
}),
distro,
system: Option::from(System {
name: markers.map(|markers| markers.platform_system().to_string()),
release: markers.map(|markers| markers.platform_release().to_string()),
}),
cpu: markers.map(|markers| markers.platform_machine().to_string()),
openssl_version: None,
setuptools_version: None,
rustc_version: None,
ci: looks_like_ci,
}
}
}