-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild.rs
More file actions
236 lines (196 loc) · 8.42 KB
/
Copy pathbuild.rs
File metadata and controls
236 lines (196 loc) · 8.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use sha1::Digest;
use tar::Archive;
use zip::ZipArchive;
static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
const GIT_REPO_ESPTOOL: &str = "https://github.com/espressif/esptool/releases/download";
const PREFIX_ESPTOOL: &str = "esptool";
// The version of the tools to download
// Updating this version means new `esptools` patch release
const VERSION_ESPTOOL: &str = "v4.8.1";
const GIT_REPO_ESPIDFNVS: &str =
"https://github.com/ivmarkov/esp-idf-nvs-partition-gen/releases/download";
const PREFIX_ESPIDFNVS: &str = "espidfnvs";
// Ditto for the `espidfnvs` tool which is a separate ZIP file
const VERSION_ESPIDFNVS: &str = "v0.0.1";
const SUFFIX_WIN64: &str = "win64";
const SUFFIX_MACOS: &str = "macos";
const SUFFIX_LINUX_AMD64: &str = "linux-amd64";
const SUFFIX_LINUX_ARM64: &str = "linux-arm64";
const SUFFIX_LINUX_ARM32: &str = "linux-arm32";
const SUFFIX_ESPIDFNVS_WIN64: &str = SUFFIX_WIN64;
const SUFFIX_ESPIDFNVS_LINUX_AMD64: &str = SUFFIX_LINUX_AMD64;
const SUFFIX_ESPIDFNVS_LINUX_ARM64: &str = "aarch64"; // TODO: Fix this in `esp-idf-nvs-partition-gen`
const SUFFIX_ESPIDFNVS_LINUX_ARM32: &str = "armv7"; // TODO: Fix this in `esp-idf-nvs-partition-gen`
const SUFFIX_ESPIDFNVS_MACOS_AMD64: &str = "macos-amd64";
const SUFFIX_ESPIDFNVS_MACOS_ARM64: &str = "macos-arm64";
/// Download the `esptools` & `espidfnvs` archive files and bundle
/// the executables inside those with this crate using `include_bytes!`
fn main() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap();
let windows = target_os.as_str() == "windows";
let esptool = std::env::var("CARGO_FEATURE_ESPTOOL").is_ok();
let espsecure = std::env::var("CARGO_FEATURE_ESPSECURE").is_ok();
let espefuse = std::env::var("CARGO_FEATURE_ESPEFUSE").is_ok();
let espidfnvs = std::env::var("CARGO_FEATURE_ESPIDFNVS").is_ok();
let out = PathBuf::from(std::env::var("OUT_DIR").unwrap());
if esptool || espsecure || espefuse {
let image = match target_os.as_str() {
"windows" => (target_arch == "x86_64").then_some(SUFFIX_WIN64),
"macos" => {
(target_arch == "x86_64" || target_arch == "aarch64").then_some(SUFFIX_MACOS)
}
"linux" => (target_env == "gnu")
.then_some(match target_arch.as_str() {
"x86_64" => Some(SUFFIX_LINUX_AMD64),
"aarch64" => Some(SUFFIX_LINUX_ARM64),
"arm" => Some(SUFFIX_LINUX_ARM32),
_ => None,
})
.flatten(),
_ => None,
};
let Some(image) = image else {
panic!("Unsupported target: os={target_os}, arch={target_arch}, env={target_env}");
};
process_archive(
&out,
&format!(
"{GIT_REPO_ESPTOOL}/{VERSION_ESPTOOL}/{PREFIX_ESPTOOL}-{VERSION_ESPTOOL}-{image}.zip"
),
&format!("{PREFIX_ESPTOOL}-{image}"),
windows,
esptool
.then_some("esptool")
.into_iter()
.chain(espsecure.then_some("espsecure"))
.chain(espefuse.then_some("espefuse"))
.collect::<Vec<_>>()
.as_slice(),
);
}
if espidfnvs {
let image = match target_os.as_str() {
"windows" => (target_arch == "x86_64").then_some(SUFFIX_ESPIDFNVS_WIN64),
"macos" if target_arch == "x86_64" => Some(SUFFIX_ESPIDFNVS_MACOS_AMD64),
"macos" if target_arch == "aarch64" => Some(SUFFIX_ESPIDFNVS_MACOS_ARM64),
"linux" => (target_env == "gnu")
.then_some(match target_arch.as_str() {
"x86_64" => Some(SUFFIX_ESPIDFNVS_LINUX_AMD64),
"aarch64" => Some(SUFFIX_ESPIDFNVS_LINUX_ARM64),
"arm" => Some(SUFFIX_ESPIDFNVS_LINUX_ARM32),
_ => None,
})
.flatten(),
_ => None,
};
let Some(image) = image else {
panic!("Unsupported target: os={target_os}, arch={target_arch}, env={target_env}");
};
process_archive(
&out,
&format!("{GIT_REPO_ESPIDFNVS}/{VERSION_ESPIDFNVS}/{PREFIX_ESPIDFNVS}-{VERSION_ESPIDFNVS}-{image}{}", if windows { ".zip" } else { ".tar.gz" }),
&format!("{PREFIX_ESPIDFNVS}-{image}"),
windows,
&["espidfnvs"],
);
}
#[allow(clippy::too_many_arguments)]
fn process_archive(
out: &Path,
archive_url: &str,
archive_name: &str,
windows: bool,
appl_tools: &[&str],
) {
fn encode<R, W>(mut read: R, write: W) -> String
where
R: Read,
W: Write,
{
let mut write = GzEncoder::new(write, flate2::Compression::default());
let mut sha1 = sha1::Sha1::new();
let mut buf = [0; 32768];
loop {
let n = read.read(&mut buf).unwrap();
if n == 0 {
break;
}
write.write_all(&buf[..n]).unwrap();
sha1.update(&buf[..n]);
}
hex::encode(sha1.finalize().as_slice())
}
let tool_name = |tool: &str| {
if windows {
format!("{tool}.exe")
} else {
tool.to_string()
}
};
let client = reqwest::blocking::Client::builder()
.user_agent(APP_USER_AGENT)
.build()
.unwrap();
let mut response = client.get(archive_url).send().unwrap();
let archive_process_path = out.join(archive_name);
fs::create_dir_all(&archive_process_path).unwrap();
let archive_path = archive_process_path.join("archive");
io::copy(&mut response, &mut File::create(&archive_path).unwrap()).unwrap();
let tools_path = archive_process_path.join("tools");
fs::create_dir_all(&tools_path).unwrap();
if archive_url.ends_with(".zip") {
let mut zip = ZipArchive::new(File::open(&archive_path).unwrap()).unwrap();
for tool in appl_tools {
let mut entry = zip
.by_name(&format!("{archive_name}/{}", tool_name(tool)))
.unwrap();
let tool_path = tools_path.join(tool_name(tool));
let mut file = fs::File::create(&tool_path).unwrap();
let sha1 = encode(&mut entry, &mut file);
println!(
"cargo:rustc-env=TOOL_{}={}",
tool.to_ascii_uppercase(),
tool_path.display()
);
println!(
"cargo:rustc-env=TOOL_{}_SHA1={sha1}",
tool.to_ascii_uppercase()
);
}
} else if archive_url.ends_with(".tar.gz") {
let mut archive = Archive::new(GzDecoder::new(File::open(&archive_path).unwrap()));
for entry in archive.entries().unwrap() {
let mut entry = entry.unwrap();
let entry_path = entry.path().unwrap().to_path_buf();
if let Some(filename) = entry_path
.file_name()
.and_then(|filename| filename.to_str())
{
if let Some(tool) = appl_tools.iter().find(|tool| tool_name(tool) == filename) {
let tool_path = tools_path.join(filename);
let mut file = fs::File::create(&tool_path).unwrap();
let sha1 = encode(&mut entry, &mut file);
println!(
"cargo:rustc-env=TOOL_{}={}",
tool.to_ascii_uppercase(),
tool_path.display()
);
println!(
"cargo:rustc-env=TOOL_{}_SHA1={sha1}",
tool.to_ascii_uppercase()
);
}
}
}
} else {
panic!("Unsupported archive format: {}", archive_name);
}
}
}