|
1 | 1 | use std::env; |
| 2 | +use std::error::Error; |
2 | 3 | use std::fs; |
3 | 4 | use std::path::{Path, PathBuf}; |
4 | 5 |
|
@@ -92,14 +93,25 @@ impl Build { |
92 | 93 |
|
93 | 94 | /// Builds the Lua artifacts for the specified version. |
94 | 95 | pub fn build(&self, version: Version) -> Artifacts { |
95 | | - let target = &self.target.as_ref().expect("TARGET is not set")[..]; |
96 | | - let out_dir = self.out_dir.as_ref().expect("OUT_DIR is not set"); |
| 96 | + match self.try_build(version) { |
| 97 | + Ok(artifacts) => artifacts, |
| 98 | + Err(err) => panic!("{err}"), |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + /// Attempts to build the Lua artifacts for the specified version. |
| 103 | + /// |
| 104 | + /// Returns an error if the build fails. |
| 105 | + pub fn try_build(&self, version: Version) -> Result<Artifacts, Box<dyn Error>> { |
| 106 | + let target = self.target.as_ref().ok_or("TARGET is not set")?; |
| 107 | + let out_dir = self.out_dir.as_ref().ok_or("OUT_DIR is not set")?; |
97 | 108 | let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); |
98 | 109 | let mut source_dir = manifest_dir.join(version.source_dir()); |
99 | 110 | let include_dir = out_dir.join("include"); |
100 | 111 |
|
101 | 112 | if !include_dir.exists() { |
102 | | - fs::create_dir_all(&include_dir).unwrap(); |
| 113 | + fs::create_dir_all(&include_dir) |
| 114 | + .context(|| format!("Cannot create '{}'", include_dir.display()))?; |
103 | 115 | } |
104 | 116 |
|
105 | 117 | let mut config = cc::Build::new(); |
@@ -148,27 +160,33 @@ impl Build { |
148 | 160 |
|
149 | 161 | let cpp_source_dir = out_dir.join("cpp_source"); |
150 | 162 | if cpp_source_dir.exists() { |
151 | | - fs::remove_dir_all(&cpp_source_dir).unwrap(); |
| 163 | + fs::remove_dir_all(&cpp_source_dir) |
| 164 | + .context(|| format!("Cannot remove '{}'", cpp_source_dir.display()))?; |
152 | 165 | } |
153 | | - fs::create_dir_all(&cpp_source_dir).unwrap(); |
| 166 | + fs::create_dir_all(&cpp_source_dir) |
| 167 | + .context(|| format!("Cannot create '{}'", cpp_source_dir.display()))?; |
154 | 168 |
|
155 | | - for file in fs::read_dir(&source_dir).unwrap() { |
156 | | - let file = file.unwrap(); |
| 169 | + for file in fs::read_dir(&source_dir) |
| 170 | + .context(|| format!("Cannot read '{}'", source_dir.display()))? |
| 171 | + { |
| 172 | + let file = file?; |
157 | 173 | let filename = file.file_name(); |
158 | | - let filename = filename.to_str().unwrap(); |
| 174 | + let filename = &*filename.to_string_lossy(); |
159 | 175 | let src_file = source_dir.join(file.file_name()); |
160 | 176 | let dst_file = cpp_source_dir.join(file.file_name()); |
161 | 177 |
|
162 | | - let mut content = fs::read(src_file).unwrap(); |
| 178 | + let mut content = fs::read(&src_file) |
| 179 | + .context(|| format!("Cannot read '{}'", src_file.display()))?; |
163 | 180 | if ["lauxlib.h", "lua.h", "lualib.h"].contains(&filename) { |
164 | 181 | content.splice(0..0, b"extern \"C\" {\n".to_vec()); |
165 | 182 | content.extend(b"\n}".to_vec()) |
166 | 183 | } |
167 | | - fs::write(dst_file, content).unwrap(); |
| 184 | + fs::write(&dst_file, content) |
| 185 | + .context(|| format!("Cannot write to '{}'", dst_file.display()))?; |
168 | 186 | } |
169 | 187 | source_dir = cpp_source_dir |
170 | 188 | } |
171 | | - _ => panic!("don't know how to build Lua for {target}"), |
| 189 | + _ => Err(format!("don't know how to build Lua for {target}"))?, |
172 | 190 | } |
173 | 191 |
|
174 | 192 | if let Lua54 = version { |
@@ -199,19 +217,22 @@ impl Build { |
199 | 217 | .include(&source_dir) |
200 | 218 | .flag("-w") // Suppress all warnings |
201 | 219 | .flag_if_supported("-fno-common") // Compile common globals like normal definitions |
202 | | - .add_files_by_ext(&source_dir, "c") |
| 220 | + .add_files_by_ext(&source_dir, "c")? |
203 | 221 | .out_dir(out_dir) |
204 | | - .compile(version.lib_name()); |
| 222 | + .try_compile(version.lib_name())?; |
205 | 223 |
|
206 | 224 | for f in &["lauxlib.h", "lua.h", "luaconf.h", "lualib.h"] { |
207 | | - fs::copy(source_dir.join(f), include_dir.join(f)).unwrap(); |
| 225 | + let from = source_dir.join(f); |
| 226 | + let to = include_dir.join(f); |
| 227 | + fs::copy(&from, &to) |
| 228 | + .context(|| format!("Cannot copy '{}' to '{}'", from.display(), to.display()))?; |
208 | 229 | } |
209 | 230 |
|
210 | | - Artifacts { |
| 231 | + Ok(Artifacts { |
211 | 232 | include_dir, |
212 | 233 | lib_dir: out_dir.clone(), |
213 | 234 | libs: vec![version.lib_name().to_string()], |
214 | | - } |
| 235 | + }) |
215 | 236 | } |
216 | 237 | } |
217 | 238 |
|
@@ -263,19 +284,29 @@ impl Artifacts { |
263 | 284 | } |
264 | 285 | } |
265 | 286 |
|
| 287 | +trait ErrorContext<T> { |
| 288 | + fn context(self, f: impl FnOnce() -> String) -> Result<T, Box<dyn Error>>; |
| 289 | +} |
| 290 | + |
| 291 | +impl<T, E: Error> ErrorContext<T> for Result<T, E> { |
| 292 | + fn context(self, f: impl FnOnce() -> String) -> Result<T, Box<dyn Error>> { |
| 293 | + self.map_err(|e| format!("{}: {e}", f()).into()) |
| 294 | + } |
| 295 | +} |
| 296 | + |
266 | 297 | trait AddFilesByExt { |
267 | | - fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> &mut Self; |
| 298 | + fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> Result<&mut Self, Box<dyn Error>>; |
268 | 299 | } |
269 | 300 |
|
270 | 301 | impl AddFilesByExt for cc::Build { |
271 | | - fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> &mut Self { |
| 302 | + fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> Result<&mut Self, Box<dyn Error>> { |
272 | 303 | for entry in fs::read_dir(dir) |
273 | | - .unwrap() |
| 304 | + .context(|| format!("Cannot read '{}'", dir.display()))? |
274 | 305 | .filter_map(|e| e.ok()) |
275 | 306 | .filter(|e| e.path().extension() == Some(ext.as_ref())) |
276 | 307 | { |
277 | 308 | self.file(entry.path()); |
278 | 309 | } |
279 | | - self |
| 310 | + Ok(self) |
280 | 311 | } |
281 | 312 | } |
0 commit comments