Skip to content

Commit 4b570ee

Browse files
committed
Add Build::try_build method that returns error instead of panic
1 parent ac1cd59 commit 4b570ee

File tree

1 file changed

+72
-42
lines changed

1 file changed

+72
-42
lines changed

src/lib.rs

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use std::env;
2-
use std::fs;
1+
use std::error::Error;
32
use std::path::{Path, PathBuf};
43
use std::process::Command;
4+
use std::{env, fs, io};
5+
6+
type DynError = Box<dyn Error + Send + Sync>;
57

68
/// Represents the configuration for building LuaJIT artifacts.
79
pub struct Build {
@@ -87,6 +89,13 @@ impl Build {
8789

8890
/// Builds the LuaJIT artifacts.
8991
pub fn build(&mut self) -> Artifacts {
92+
self.try_build().expect("LuaJIT build failed")
93+
}
94+
95+
/// Attempts to build the LuaJIT artifacts.
96+
///
97+
/// Returns an error if the build fails.
98+
pub fn try_build(&mut self) -> Result<Artifacts, DynError> {
9099
let target = &self.target.as_ref().expect("TARGET is not set")[..];
91100

92101
if target.contains("msvc") {
@@ -96,7 +105,7 @@ impl Build {
96105
self.build_unix()
97106
}
98107

99-
fn build_unix(&mut self) -> Artifacts {
108+
fn build_unix(&mut self) -> Result<Artifacts, DynError> {
100109
let target = &self.target.as_ref().expect("TARGET is not set")[..];
101110
let host = &self.host.as_ref().expect("HOST is not set")[..];
102111
let out_dir = self.out_dir.as_ref().expect("OUT_DIR is not set");
@@ -109,22 +118,23 @@ impl Build {
109118
// Cleanup
110119
for dir in [&build_dir, &lib_dir, &include_dir] {
111120
if dir.exists() {
112-
fs::remove_dir_all(dir)
113-
.unwrap_or_else(|e| panic!("cannot remove {}: {e}", dir.display()));
121+
fs::remove_dir_all(dir).context(|| format!("Cannot remove {}", dir.display()))?;
114122
}
115-
fs::create_dir_all(dir)
116-
.unwrap_or_else(|e| panic!("cannot create {}: {e}", dir.display()));
123+
fs::create_dir_all(dir).context(|| format!("Cannot create {}", dir.display()))?;
117124
}
118-
cp_r(&source_dir, &build_dir);
125+
cp_r(&source_dir, &build_dir)?;
119126

120127
// Copy release version file
121128
let relver = build_dir.join(".relver");
122-
fs::copy(manifest_dir.join("luajit_relver.txt"), &relver).unwrap();
129+
fs::copy(manifest_dir.join("luajit_relver.txt"), &relver)
130+
.context(|| format!("Cannot copy 'luajit_relver.txt'"))?;
123131

124132
// Fix permissions for certain build situations
125-
let mut perms = fs::metadata(&relver).unwrap().permissions();
133+
let mut perms = (fs::metadata(&relver).map(|md| md.permissions()))
134+
.context(|| format!("Cannot read permissions for '{}'", relver.display()))?;
126135
perms.set_readonly(false);
127-
fs::set_permissions(relver, perms).unwrap();
136+
fs::set_permissions(&relver, perms)
137+
.context(|| format!("Cannot set permissions for '{}'", relver.display()))?;
128138

129139
let mut cc = cc::Build::new();
130140
cc.warnings(false);
@@ -170,7 +180,7 @@ impl Build {
170180
};
171181

172182
let compiler_path =
173-
which::which(compiler_path).unwrap_or_else(|_| panic!("cannot find {compiler_path}"));
183+
which::which(compiler_path).context(|| format!("Cannot find {compiler_path}"))?;
174184
let bindir = compiler_path.parent().unwrap();
175185
let compiler_path = compiler_path.to_str().unwrap();
176186
let compiler_args = compiler.cflags_env();
@@ -229,12 +239,13 @@ impl Build {
229239

230240
make.env("BUILDMODE", "static");
231241
make.env("XCFLAGS", xcflags.join(" "));
232-
self.run_command(make, "building LuaJIT");
242+
self.run_command(&mut make)
243+
.context(|| format!("Error running '{make:?}'"))?;
233244

234245
Artifacts::make(&build_dir, &include_dir, &lib_dir, false)
235246
}
236247

237-
fn build_msvc(&mut self) -> Artifacts {
248+
fn build_msvc(&mut self) -> Result<Artifacts, DynError> {
238249
let target = &self.target.as_ref().expect("TARGET is not set")[..];
239250
let out_dir = self.out_dir.as_ref().expect("OUT_DIR is not set");
240251
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
@@ -246,17 +257,16 @@ impl Build {
246257
// Cleanup
247258
for dir in [&build_dir, &lib_dir, &include_dir] {
248259
if dir.exists() {
249-
fs::remove_dir_all(dir)
250-
.unwrap_or_else(|e| panic!("cannot remove {}: {e}", dir.display()));
260+
fs::remove_dir_all(dir).context(|| format!("Cannot remove {}", dir.display()))?;
251261
}
252-
fs::create_dir_all(dir)
253-
.unwrap_or_else(|e| panic!("cannot create {}: {e}", dir.display()));
262+
fs::create_dir_all(dir).context(|| format!("Cannot create {}", dir.display()))?;
254263
}
255-
cp_r(&source_dir, &build_dir);
264+
cp_r(&source_dir, &build_dir)?;
256265

257266
// Copy release version file
258-
#[rustfmt::skip]
259-
fs::copy(manifest_dir.join("luajit_relver.txt"), build_dir.join(".relver")).unwrap();
267+
let relver = build_dir.join(".relver");
268+
fs::copy(manifest_dir.join("luajit_relver.txt"), &relver)
269+
.context(|| format!("Cannot copy 'luajit_relver.txt'"))?;
260270

261271
let mut msvcbuild = Command::new(build_dir.join("src").join("msvcbuild.bat"));
262272
msvcbuild.current_dir(build_dir.join("src"));
@@ -270,28 +280,24 @@ impl Build {
270280
msvcbuild.env(k, v);
271281
}
272282

273-
self.run_command(msvcbuild, "building LuaJIT");
283+
self.run_command(&mut msvcbuild)
284+
.context(|| format!("Error running'{msvcbuild:?}'"))?;
274285

275286
Artifacts::make(&build_dir, &include_dir, &lib_dir, true)
276287
}
277288

278-
fn run_command(&self, mut command: Command, desc: &str) {
279-
let status = command.status().unwrap();
289+
fn run_command(&self, command: &mut Command) -> io::Result<()> {
290+
let status = command.status()?;
280291
if !status.success() {
281-
panic!(
282-
"
283-
Error {desc}:
284-
Command: {command:?}
285-
Exit status: {status}
286-
"
287-
);
292+
return Err(io::Error::other(format!("exited with status {status}")));
288293
}
294+
Ok(())
289295
}
290296
}
291297

292-
fn cp_r(src: &Path, dst: &Path) {
293-
for f in fs::read_dir(src).unwrap() {
294-
let f = f.unwrap();
298+
fn cp_r(src: &Path, dst: &Path) -> Result<(), DynError> {
299+
for f in fs::read_dir(src).context(|| format!("Cannot read directory '{}'", src.display()))? {
300+
let f = f.context(|| format!("Cannot read entry in '{}'", src.display()))?;
295301
let path = f.path();
296302
let name = path.file_name().unwrap();
297303

@@ -302,13 +308,16 @@ fn cp_r(src: &Path, dst: &Path) {
302308

303309
let dst = dst.join(name);
304310
if f.file_type().unwrap().is_dir() {
305-
fs::create_dir_all(&dst).unwrap();
306-
cp_r(&path, &dst);
311+
fs::create_dir_all(&dst)
312+
.context(|| format!("Cannot create directory '{}'", dst.display()))?;
313+
cp_r(&path, &dst)?;
307314
} else {
308315
let _ = fs::remove_file(&dst);
309-
fs::copy(&path, &dst).unwrap();
316+
fs::copy(&path, &dst)
317+
.context(|| format!("Cannot copy '{}' to '{}'", path.display(), dst.display()))?;
310318
}
311319
}
320+
Ok(())
312321
}
313322

314323
impl Artifacts {
@@ -345,21 +354,42 @@ impl Artifacts {
345354
}
346355
}
347356

348-
fn make(build_dir: &Path, include_dir: &Path, lib_dir: &Path, is_msvc: bool) -> Self {
357+
fn make(
358+
build_dir: &Path,
359+
include_dir: &Path,
360+
lib_dir: &Path,
361+
is_msvc: bool,
362+
) -> Result<Self, DynError> {
349363
for f in &["lauxlib.h", "lua.h", "luaconf.h", "luajit.h", "lualib.h"] {
350-
fs::copy(build_dir.join("src").join(f), include_dir.join(f)).unwrap();
364+
let from = build_dir.join("src").join(f);
365+
let to = include_dir.join(f);
366+
fs::copy(&from, &to)
367+
.context(|| format!("Cannot copy '{}' to '{}'", from.display(), to.display()))?;
351368
}
352369

353370
let lib_name = if !is_msvc { "luajit" } else { "lua51" };
354371
let lib_file = if !is_msvc { "libluajit.a" } else { "lua51.lib" };
355372
if build_dir.join("src").join(lib_file).exists() {
356-
fs::copy(build_dir.join("src").join(lib_file), lib_dir.join(lib_file)).unwrap();
373+
let from = build_dir.join("src").join(lib_file);
374+
let to = lib_dir.join(lib_file);
375+
fs::copy(&from, &to)
376+
.context(|| format!("Cannot copy '{}' to '{}'", from.display(), to.display()))?;
357377
}
358378

359-
Artifacts {
379+
Ok(Artifacts {
360380
lib_dir: lib_dir.to_path_buf(),
361381
include_dir: include_dir.to_path_buf(),
362382
libs: vec![lib_name.to_string()],
363-
}
383+
})
384+
}
385+
}
386+
387+
trait ErrorContext<T> {
388+
fn context(self, f: impl FnOnce() -> String) -> Result<T, DynError>;
389+
}
390+
391+
impl<T, E: Error> ErrorContext<T> for Result<T, E> {
392+
fn context(self, f: impl FnOnce() -> String) -> Result<T, DynError> {
393+
self.map_err(|e| format!("{}: {e}", f()).into())
364394
}
365395
}

0 commit comments

Comments
 (0)