release_manager/
target.rs

1// This file is part of Release Manager
2
3// Release Manager is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7
8// Release Manager is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12
13// You should have received a copy of the GNU General Public License
14// along with Release Manager  If not, see <http://www.gnu.org/licenses/>.
15
16use 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    // Make env a table so it has key-value pairs
137    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}