1use std::process::{Command, ExitStatus};
17use std::collections::HashMap;
18use std::convert::TryFrom;
19use super::Error;
20use super::StatusWrapper;
21
22#[derive(Clone, Debug)]
23pub enum Arch {
24 Aarch64,
25 Armv7h,
26 Armv7hMusl,
27 Armh,
28 ArmhMusl,
29 Amd64,
30 Amd64Musl,
31 I686,
32}
33
34impl<'a> TryFrom<&'a str> for Arch {
35 type Error = &'a str;
36 fn try_from(value: &'a str) -> Result<Arch, &'a str> {
37 match value {
38 "aarch64" => Ok(Arch::Aarch64),
39 "armv7h" => Ok(Arch::Armv7h),
40 "armv7hmusl" => Ok(Arch::Armv7hMusl),
41 "armh" => Ok(Arch::Armh),
42 "armhmusl" => Ok(Arch::ArmhMusl),
43 "amd64" => Ok(Arch::Amd64),
44 "amd64musl" => Ok(Arch::Amd64Musl),
45 "i686" => Ok(Arch::I686),
46
47 _ => Err(value),
48 }
49 }
50}
51
52#[derive(Clone, Debug)]
53pub enum OS {
54 Linux,
55 Windows,
56 Mac,
57}
58
59pub struct Target {
60 os: OS,
61 arch: Arch,
62 build_name: Option<String>,
63 native_dirs: Vec<String>,
64 environment: HashMap<String, String>,
65}
66
67impl Target {
68 pub fn new(os: OS, arch: Arch, build_name: Option<String>) -> Result<Self, Error> {
69 match (&os, &arch) {
70 (&OS::Linux, &Arch::Aarch64) |
71 (&OS::Linux, &Arch::Armv7h) |
72 (&OS::Linux, &Arch::Armv7hMusl) |
73 (&OS::Linux, &Arch::Armh) |
74 (&OS::Linux, &Arch::ArmhMusl) |
75 (&OS::Linux, &Arch::Amd64) |
76 (&OS::Linux, &Arch::Amd64Musl) |
77 (&OS::Windows, &Arch::Amd64) |
78 (&OS::Windows, &Arch::I686) |
79 (&OS::Mac, &Arch::Amd64) => {
80 Ok(Target {
81 os: os,
82 arch: arch,
83 build_name: build_name,
84 native_dirs: Vec::new(),
85 environment: HashMap::new(),
86 })
87 }
88 _ => Err(Error::InvalidTarget),
89 }
90 }
91
92 pub fn target_str(&self) -> &str {
93 match (&self.os, &self.arch) {
94 (&OS::Linux, &Arch::Aarch64) => "aarch64-unknown-linux-gnu",
95 (&OS::Linux, &Arch::Armv7h) => "armv7-unknown-linux-gnueabihf",
96 (&OS::Linux, &Arch::Armv7hMusl) => "armv7-unknown-linux-musleabihf",
97 (&OS::Linux, &Arch::Armh) => "arm-unknown-linux-gnueabihf",
98 (&OS::Linux, &Arch::ArmhMusl) => "arm-unknown-linux-musleabihf",
99 (&OS::Linux, &Arch::Amd64) => "x86_64-unknown-linux-gnu",
100 (&OS::Linux, &Arch::Amd64Musl) => "x86_64-unknown-linux-musl",
101 (&OS::Windows, &Arch::Amd64) => "x86_64-pc-windows-gnu",
102 (&OS::Windows, &Arch::I686) => "i686-pc-windows-gnu",
103 (&OS::Mac, &Arch::Amd64) => "x86_64-apple-darwin",
104 _ => {
105 debug!("Unkown OS/Arch combination: {:?}, {:?}", self.os, self.arch);
106 "unknown"
107 }
108 }
109 }
110
111 pub fn output_str(&self) -> String {
112 match self.build_name {
113 Some(ref name) => format!("{}-{}", self.target_str(), name),
114 None => self.target_str().into(),
115 }
116 }
117
118 pub fn add_libs(&mut self, libs: &[String]) {
119 self.native_dirs.extend_from_slice(libs);
120 }
121
122 pub fn add_env(&mut self, env: &HashMap<String, String>) {
123 for (key, value) in env {
124 self.environment.insert(key.clone(), value.clone());
125 }
126 }
127
128 pub fn libs(&self) -> String {
129 self.native_dirs
130 .iter()
131 .map(|dir| format!("-L native={}", dir))
132 .collect::<Vec<_>>()
133 .join(" ")
134 }
135
136 pub fn compile(&self, version: &str, status: &mut StatusWrapper) -> Result<ExitStatus, Error> {
138 debug!("Starting compile for {}", self.output_str());
139
140 Command::new("cargo")
141 .args(&["build", "--target", self.target_str(), "--release"])
142 .env(
143 "RUSTFLAGS",
144 &format!("-C target-feature=+crt-static {}", &self.libs()),
145 )
146 .envs(&self.environment)
147 .spawn()
148 .map_err(|e| e.into())
149 .and_then(|mut child| {
150 status.start(self.target_str(), version);
151 let _ = status.write();
152
153 child.wait().map_err(|e| e.into())
154 })
155 .and_then(|exit_status| {
156 if exit_status.success() {
157 status.succeed(self.target_str(), version);
158 } else {
159 status.fail(self.target_str(), version);
160 }
161 let _ = status.write();
162
163 Ok(exit_status)
164 })
165 }
166}
167
168
169impl<'a> TryFrom<&'a str> for OS {
170 type Error = &'a str;
171
172 fn try_from(value: &'a str) -> Result<OS, &'a str> {
173 match value {
174 "Linux" => Ok(OS::Linux),
175 "Windows" => Ok(OS::Windows),
176 "Mac" => Ok(OS::Mac),
177 _ => Err(value),
178 }
179 }
180}