use failure::{bail, format_err, Error};
use platform_info::*;
use platforms;
use platforms::target::Arch;
use serde::{Deserialize, Serialize};
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::str::FromStr;
use target_info;
#[derive(Debug, Clone, Eq, PartialEq)]
enum OS {
Linux,
Windows,
Macos,
FreeBSD,
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Manylinux {
Manylinux1,
Manylinux1Unchecked,
Manylinux2010,
Manylinux2010Unchecked,
Off,
}
impl FromStr for Manylinux {
type Err = &'static str;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"1" => Ok(Manylinux::Manylinux1),
"1-unchecked" => Ok(Manylinux::Manylinux1Unchecked),
"2010" => Ok(Manylinux::Manylinux2010),
"2010-unchecked" => Ok(Manylinux::Manylinux2010Unchecked),
"off" => Ok(Manylinux::Off),
_ => Err("Invalid value for the manylinux option"),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Target {
os: OS,
is_64_bit: bool,
}
impl Target {
pub fn current() -> Self {
let os = match target_info::Target::os() {
"linux" => OS::Linux,
"windows" => OS::Windows,
"macos" => OS::Macos,
"freebsd" => OS::FreeBSD,
unsupported => panic!("The platform {} is not supported", unsupported),
};
let is_64_bit = match target_info::Target::pointer_width() {
"64" => true,
"32" => false,
unsupported => panic!("The pointer width {} is not supported ಠ_ಠ", unsupported),
};
Target { os, is_64_bit }
}
pub fn from_target_triple(target_triple: Option<String>) -> Result<Self, Error> {
let platform = if let Some(ref target_triple) = target_triple {
platforms::find(target_triple)
.ok_or_else(|| format_err!("Unknown target triple {}", target_triple))?
} else {
platforms::guess_current()
.ok_or_else(|| format_err!("Could guess the current platform"))?
};
let os = match platform.target_os {
platforms::target::OS::Linux => OS::Linux,
platforms::target::OS::Windows => OS::Windows,
platforms::target::OS::MacOS => OS::Macos,
platforms::target::OS::FreeBSD => OS::FreeBSD,
unsupported => bail!("The operating system {:?} is not supported", unsupported),
};
let is_64_bit = match platform.target_arch {
Arch::X86_64 => true,
Arch::X86 => false,
unsupported => bail!("The architecture {:?} is not supported", unsupported),
};
Ok(Target { os, is_64_bit })
}
pub fn pointer_width(&self) -> usize {
if self.is_64_bit {
64
} else {
32
}
}
pub fn is_unix(&self) -> bool {
self.os != OS::Windows
}
pub fn is_linux(&self) -> bool {
self.os == OS::Linux
}
pub fn is_freebsd(&self) -> bool {
self.os == OS::FreeBSD
}
pub fn is_macos(&self) -> bool {
self.os == OS::Macos
}
pub fn is_windows(&self) -> bool {
self.os == OS::Windows
}
pub fn get_platform_tag(&self, manylinux: &Manylinux) -> String {
match (&self.os, self.is_64_bit, manylinux) {
(&OS::Linux, true, Manylinux::Off) => "linux_x86_64".to_string(),
(&OS::Linux, false, Manylinux::Off) => "linux_i686".to_string(),
(&OS::Linux, true, Manylinux::Manylinux1) => "manylinux1_x86_64".to_string(),
(&OS::Linux, true, Manylinux::Manylinux1Unchecked) => "manylinux1_x86_64".to_string(),
(&OS::Linux, true, Manylinux::Manylinux2010) => "manylinux2010_x86_64".to_string(),
(&OS::Linux, true, Manylinux::Manylinux2010Unchecked) => {
"manylinux2010_x86_64".to_string()
}
(&OS::Linux, false, Manylinux::Manylinux1) => "manylinux1_i686".to_string(),
(&OS::Linux, false, Manylinux::Manylinux1Unchecked) => "manylinux1_i686".to_string(),
(&OS::Linux, false, Manylinux::Manylinux2010) => "manylinux2010_i686".to_string(),
(&OS::Linux, false, Manylinux::Manylinux2010Unchecked) => {
"manylinux2010_i686".to_string()
}
(&OS::Windows, true, _) => "win_amd64".to_string(),
(&OS::Windows, false, _) => "win32".to_string(),
(&OS::Macos, true, _) => "macosx_10_7_x86_64".to_string(),
(&OS::Macos, false, _) => panic!("32-bit wheels are not supported for mac os"),
(&OS::FreeBSD, true, _) => {
let info = match PlatformInfo::new() {
Ok(info) => info,
Err(error) => panic!(error),
};
let release = info.release().replace(".", "_").replace("-", "_");
format!("freebsd_{}_amd64", release)
}
(&OS::FreeBSD, false, _) => panic!("32-bit wheels are not supported for FreeBSD"),
}
}
pub fn get_py2_and_py3_tags(&self, manylinux: &Manylinux) -> Vec<String> {
vec![
format!("py2-none-{}", self.get_platform_tag(&manylinux)),
format!("py3-none-{}", self.get_platform_tag(&manylinux)),
]
}
pub fn get_shared_platform_tag(&self) -> &'static str {
match self.os {
OS::Linux => {
if self.is_64_bit {
"x86_64-linux-gnu"
} else {
"x86-linux-gnu"
}
}
OS::Macos => "darwin",
OS::FreeBSD => "",
OS::Windows => {
if self.is_64_bit {
"win_amd64"
} else {
"win32"
}
}
}
}
pub fn get_venv_python(&self, venv_base: impl AsRef<Path>) -> PathBuf {
if self.is_windows() {
venv_base.as_ref().join("Scripts").join("python.exe")
} else {
venv_base.as_ref().join("bin").join("python")
}
}
pub fn get_venv_bin_dir(&self, venv_base: impl AsRef<Path>) -> PathBuf {
if self.is_windows() {
venv_base.as_ref().join("Scripts")
} else {
venv_base.as_ref().join("bin")
}
}
pub fn get_python(&self) -> PathBuf {
if self.is_windows() {
PathBuf::from("python.exe")
} else if env::var_os("VIRTUAL_ENV").is_some() {
PathBuf::from("python")
} else {
PathBuf::from("python3")
}
}
pub fn get_universal_tags(&self, manylinux: &Manylinux) -> (String, Vec<String>) {
let tag = format!(
"py2.py3-none-{platform}",
platform = self.get_platform_tag(&manylinux)
);
let tags = self.get_py2_and_py3_tags(&manylinux);
(tag, tags)
}
}