Skip to content

Commit 7515dee

Browse files
committed
Add a new bootimage runner subcommand for use as target.runner
1 parent 935dacc commit 7515dee

File tree

6 files changed

+183
-11
lines changed

6 files changed

+183
-11
lines changed

Cargo.lock

Lines changed: 85 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ wait-timeout = "0.2"
1515
xmas-elf = "0.6.2"
1616
llvm-tools = "0.1.1"
1717
locate-cargo-manifest = "0.1.0"
18+
tempdir = "0.3.7"
1819

1920
[dependencies.cargo_metadata]
2021
version = "0.7.4"

src/args.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) fn parse_args() -> Command {
2323
Command::BuildHelp => Command::TestHelp,
2424
cmd => cmd,
2525
},
26+
Some("runner") => parse_runner_args(args),
2627
Some("--help") | Some("-h") => Command::Help,
2728
Some("--version") => Command::Version,
2829
_ => Command::NoSubcommand,
@@ -194,3 +195,41 @@ impl Args {
194195
}
195196
}
196197
}
198+
199+
fn parse_runner_args<A>(args: A) -> Command
200+
where
201+
A: Iterator<Item = String>,
202+
{
203+
let mut arg_iter = args.into_iter().fuse();
204+
let executable = PathBuf::from(arg_iter.next().expect("excepted path to kernel executable as first argument")).canonicalize().expect("Failed to canonicalize executable path");
205+
let mut run_command = None;
206+
207+
loop {
208+
match arg_iter.next().as_ref().map(|s| s.as_str()) {
209+
Some("--command") => {
210+
let old = mem::replace(&mut run_command, Some(arg_iter.collect()));
211+
assert!(old.is_none(), "multiple `--command` arguments");
212+
break;
213+
}
214+
Some("--help") | Some("-h") => {
215+
return Command::RunnerHelp;
216+
}
217+
Some("--version") => {
218+
return Command::Version;
219+
}
220+
None => break,
221+
Some(arg) => panic!("unexpected argument `{}`", arg),
222+
}
223+
}
224+
225+
Command::Runner(RunnerArgs {
226+
executable,
227+
run_command,
228+
})
229+
}
230+
231+
#[derive(Debug, Clone)]
232+
pub struct RunnerArgs {
233+
pub executable: PathBuf,
234+
pub run_command: Option<Vec<String>>,
235+
}

src/main.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use args::Args;
1+
use args::{Args, RunnerArgs};
22
use std::{fmt, process};
33

44
mod args;
@@ -12,17 +12,19 @@ enum Command {
1212
Build(Args),
1313
Run(Args),
1414
Test(Args),
15+
Runner(RunnerArgs),
1516
Help,
1617
BuildHelp,
1718
RunHelp,
1819
TestHelp,
20+
RunnerHelp,
1921
Version,
2022
}
2123

2224
pub fn main() {
2325
if let Err(err) = run() {
24-
eprintln!("Error: {}", err.display());
25-
process::exit(1);
26+
eprintln!("Error: {}", err.message);
27+
process::exit(err.exit_code);
2628
}
2729
}
2830

@@ -32,26 +34,25 @@ fn run() -> Result<(), ErrorString> {
3234
Command::Build(args) => subcommand::build::build(args),
3335
Command::Run(args) => subcommand::run::run(args),
3436
Command::Test(args) => subcommand::test::test(args),
37+
Command::Runner(args) => subcommand::runner::runner(args),
3538
Command::NoSubcommand => help::no_subcommand(),
3639
Command::Help => Ok(help::help()),
3740
Command::BuildHelp => Ok(help::build_help()),
3841
Command::RunHelp => Ok(help::run_help()),
3942
Command::TestHelp => Ok(help::test_help()),
43+
Command::RunnerHelp => unimplemented!(),
4044
Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))),
4145
}
4246
}
4347

44-
struct ErrorString(Box<dyn fmt::Display + Send>);
45-
46-
impl ErrorString {
47-
fn display(&self) -> &dyn fmt::Display {
48-
&self.0
49-
}
48+
struct ErrorString {
49+
pub message: Box<dyn fmt::Display + Send>,
50+
pub exit_code: i32,
5051
}
5152

5253
impl fmt::Debug for ErrorString {
5354
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54-
self.display().fmt(f)
55+
self.message.fmt(f)
5556
}
5657
}
5758

@@ -60,6 +61,9 @@ where
6061
T: fmt::Display + Send + 'static,
6162
{
6263
fn from(err: T) -> Self {
63-
ErrorString(Box::new(err))
64+
ErrorString {
65+
message: Box::new(err),
66+
exit_code: 1,
67+
}
6468
}
6569
}

src/subcommand.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod build;
22
pub mod run;
3+
pub mod runner;
34
pub mod test;

src/subcommand/runner.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use crate::{args::RunnerArgs, ErrorString};
2+
use std::process;
3+
4+
pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> {
5+
let out_dir = tempdir::TempDir::new("bootimage-runner")?;
6+
let bootimage_bin = out_dir.path().join("bootimage.bin");
7+
8+
let builder = bootimage::Builder::new(None)?;
9+
builder.create_bootimage(&args.executable, &bootimage_bin, false)?;
10+
11+
let run_cmd = args.run_command.unwrap_or(vec![
12+
"qemu-system-x86_64".into(),
13+
"-drive".into(),
14+
"format=raw,file={bootimage}".into(),
15+
]);
16+
17+
println!("Running {:?}", run_cmd);
18+
19+
let mut command = process::Command::new(&run_cmd[0]);
20+
for arg in &run_cmd[1..] {
21+
command.arg(arg.replace("{bootimage}", &format!("{}", bootimage_bin.display())));
22+
}
23+
let output = command
24+
.output()
25+
.map_err(|e| format!("Failed to execute `{:?}`: {}", command, e))?;
26+
27+
if !output.status.success() {
28+
return Err(ErrorString {
29+
exit_code: output.status.code().unwrap_or(1),
30+
message: Box::new(format!(
31+
"Command `{:?}` failed:\n{}",
32+
command,
33+
String::from_utf8_lossy(&output.stderr)
34+
)),
35+
});
36+
}
37+
38+
drop(bootimage_bin);
39+
out_dir.close()?;
40+
41+
Ok(())
42+
}

0 commit comments

Comments
 (0)