use failure::{bail, format_err, Error};
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,
}
#[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,
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,
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_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) -> &'static str {
match (&self.os, self.is_64_bit, manylinux) {
(&OS::Linux, true, Manylinux::Off) => "linux_x86_64",
(&OS::Linux, false, Manylinux::Off) => "linux_i686",
(&OS::Linux, true, Manylinux::Manylinux1) => "manylinux1_x86_64",
(&OS::Linux, true, Manylinux::Manylinux1Unchecked) => "manylinux1_x86_64",
(&OS::Linux, true, Manylinux::Manylinux2010) => "manylinux2010_x86_64",
(&OS::Linux, true, Manylinux::Manylinux2010Unchecked) => "manylinux2010_x86_64",
(&OS::Linux, false, Manylinux::Manylinux1) => "manylinux1_i686",
(&OS::Linux, false, Manylinux::Manylinux1Unchecked) => "manylinux1_i686",
(&OS::Linux, false, Manylinux::Manylinux2010) => "manylinux2010_i686",
(&OS::Linux, false, Manylinux::Manylinux2010Unchecked) => "manylinux2010_i686",
(&OS::Windows, true, _) => "win_amd64",
(&OS::Windows, false, _) => "win32",
(&OS::Macos, true, _) => "macosx_10_7_x86_64",
(&OS::Macos, false, _) => panic!("32-bit wheels are not supported for mac os"),
}
}
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::Windows => {
if self.is_64_bit {
"win_amd64"
} else {
"win32"
}
}
}
}
pub fn get_venv_python(&self, venv_base: impl AsRef<Path>) -> PathBuf {
let message = "expected python to be the venv";
if self.is_windows() {
venv_base
.as_ref()
.join("Scripts")
.join("python.exe")
.canonicalize()
.expect(message)
} else {
venv_base
.as_ref()
.join("bin")
.join("python")
.canonicalize()
.expect(message)
}
}
pub fn get_venv_bin_dir(&self, venv_base: impl AsRef<Path>) -> PathBuf {
let message = "expected the venv to contain a folder for the binaries";
if self.is_windows() {
venv_base
.as_ref()
.join("Scripts")
.canonicalize()
.expect(message)
} else {
venv_base
.as_ref()
.join("bin")
.canonicalize()
.expect(message)
}
}
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")
}
}
}