Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 102 additions & 27 deletions ostool/src/bin/cargo-osrun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use clap::{Parser, Subcommand};
use colored::Colorize as _;
use log::debug;
use ostool::{
Tool, ToolConfig, logger, resolve_manifest_context,
ManifestContext, Tool,
invocation::{Invocation, InvocationOptions},
logger,
run::{qemu::RunQemuOptions, uboot::RunUbootOptions},
};

Expand Down Expand Up @@ -108,52 +110,62 @@ async fn try_main() -> anyhow::Result<()> {

let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into();
let manifest = manifest_dir.join("Cargo.toml");
let manifest = resolve_manifest_context(Some(manifest))?;
let parsed_args = format!("{args:#?}");

let RunnerArgs {
elf,
to_bin,
config,
show_output,
no_run,
debug,
command,
dtb_dump,
build_dir,
bin_dir,
..
} = args;
let bin_dir: Option<PathBuf> = bin_dir.map(PathBuf::from);
let build_dir: Option<PathBuf> = build_dir.map(PathBuf::from);

let invocation = Invocation::new(InvocationOptions::new(
Some(manifest),
build_dir,
bin_dir,
debug,
))?;
let manifest = ManifestContext::from_invocation(&invocation);
let log_path = logger::init_file_logger(&manifest.workspace_dir)?;
let _ = LOG_PATH.set(log_path.clone());
debug!(
"Logging initialized at {} for manifest {}",
log_path.display(),
manifest.manifest_path.display()
);
debug!("Parsed arguments: {:#?}", args);
debug!("Parsed arguments: {parsed_args}");

if args.no_run {
if no_run {
exit(0);
}

let bin_dir: Option<PathBuf> = args.bin_dir.map(PathBuf::from);
let build_dir: Option<PathBuf> = args.build_dir.map(PathBuf::from);
let mut tool = Tool::from_invocation(invocation);

let mut tool = Tool::new(ToolConfig {
manifest: Some(manifest.manifest_path),
build_dir,
bin_dir,
debug: args.debug,
disable_someboot_build_config: false,
})?;
tool.prepare_elf_artifact(elf, to_bin).await?;

tool.prepare_elf_artifact(args.elf, args.to_bin).await?;

match args.command {
match command {
Some(SubCommands::Uboot(_)) => {
let config = match args.config.as_deref() {
let config = match config.as_deref() {
Some(path) => tool.read_uboot_config_from_path(path).await?,
None => {
tool.ensure_uboot_config_in_dir(&manifest.workspace_dir)
.await?
}
};
tool.run_uboot(
&config,
RunUbootOptions {
show_output: args.show_output,
},
)
.await?;
tool.run_uboot(&config, RunUbootOptions { show_output })
.await?;
}
None => {
let config = match args.config.as_deref() {
let config = match config.as_deref() {
Some(path) => tool.read_qemu_config_from_path(path).await?,
None => {
tool.ensure_qemu_config_in_dir(&manifest.workspace_dir)
Expand All @@ -163,8 +175,8 @@ async fn try_main() -> anyhow::Result<()> {
tool.run_qemu(
&config,
RunQemuOptions {
dtb_dump: args.dtb_dump,
show_output: args.show_output,
dtb_dump,
show_output,
},
)
.await?;
Expand All @@ -189,3 +201,66 @@ fn report_error(err: &anyhow::Error) {
);
}
}

#[cfg(test)]
mod tests {
use std::path::Path;

use clap::Parser;

use super::{RunnerArgs, SubCommands};

/// Verifies the default runner path parses QEMU-related flags.
#[test]
fn parse_default_qemu_runner_args() {
let args = RunnerArgs::try_parse_from([
"cargo-osrun",
"qemu-system-aarch64",
"target/kernel.elf",
"--to-bin",
"--config",
"qemu.toml",
"--show-output",
"--debug",
"--dtb-dump",
"--build-dir",
"target/custom",
"--bin-dir",
"dist",
])
.unwrap();

assert_eq!(args.program, Path::new("qemu-system-aarch64"));
assert_eq!(args.elf, Path::new("target/kernel.elf"));
assert!(args.to_bin);
assert_eq!(args.config.as_deref(), Some(Path::new("qemu.toml")));
assert!(args.show_output);
assert!(args.debug);
assert!(args.dtb_dump);
assert_eq!(args.build_dir.as_deref(), Some("target/custom"));
assert_eq!(args.bin_dir.as_deref(), Some("dist"));
assert!(args.command.is_none());
}

/// Verifies the U-Boot subcommand owns arguments after `--`.
#[test]
fn parse_uboot_runner_subcommand() {
let args = RunnerArgs::try_parse_from([
"cargo-osrun",
"qemu-system-aarch64",
"target/kernel.elf",
"uboot",
"--",
"bootm",
"${kernel_addr_r}",
])
.unwrap();

match args.command {
Some(SubCommands::Uboot(uboot)) => {
assert_eq!(uboot.runner_args, ["bootm", "${kernel_addr_r}"]);
}
other => panic!("unexpected command: {other:?}"),
}
}
}
49 changes: 28 additions & 21 deletions ostool/src/board/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::{
Tool, board::global_config::BoardGlobalConfig, run::shell_init::normalize_shell_init_config,
board::global_config::BoardGlobalConfig,
project::variables::{self, VariableScope},
run::shell_init::normalize_shell_init_config,
};

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default, PartialEq, Eq)]
Expand Down Expand Up @@ -37,26 +39,26 @@ impl BoardRunConfig {
}

pub(crate) async fn load_or_create(
tool: &Tool,
scope: &VariableScope,
explicit_path: Option<PathBuf>,
) -> anyhow::Result<Self> {
let config_path = Self::default_path(explicit_path)?;
let mut config = jkconfig::run::<Self>(config_path.clone(), false, &[])
.await
.with_context(|| format!("failed to load board config: {}", config_path.display()))?
.ok_or_else(|| anyhow!("No board configuration obtained"))?;
config.replace_strings(tool)?;
config.replace_strings(scope)?;
config.normalize(&format!("board config {}", config_path.display()))?;
Ok(config)
}

pub(crate) fn read_from_path(tool: &Tool, path: PathBuf) -> anyhow::Result<Self> {
pub(crate) fn read_from_path(scope: &VariableScope, path: PathBuf) -> anyhow::Result<Self> {
let mut config: Self = toml::from_str(
&std::fs::read_to_string(&path)
.with_context(|| format!("failed to read board config: {}", path.display()))?,
)
.with_context(|| format!("failed to parse board config: {}", path.display()))?;
config.replace_strings(tool)?;
config.replace_strings(scope)?;
config.normalize(&format!("board config {}", path.display()))?;
Ok(config)
}
Expand All @@ -77,17 +79,17 @@ impl BoardRunConfig {

pub(crate) fn apply_overrides(
&mut self,
tool: &Tool,
scope: &VariableScope,
board_type: Option<&str>,
server: Option<&str>,
port: Option<u16>,
) -> anyhow::Result<()> {
if let Some(board_type) = board_type {
self.board_type = tool.replace_string(board_type)?;
self.board_type = variables::expand_variables(board_type, scope)?;
}

if let Some(server) = server {
let server = tool.replace_string(server)?;
let server = variables::expand_variables(server, scope)?;
let server = server.trim().to_string();
if server.is_empty() {
anyhow::bail!("board server override must not be empty");
Expand All @@ -105,62 +107,62 @@ impl BoardRunConfig {
self.normalize("board run arguments")
}

fn replace_strings(&mut self, tool: &Tool) -> anyhow::Result<()> {
self.board_type = tool.replace_string(&self.board_type)?;
fn replace_strings(&mut self, scope: &VariableScope) -> anyhow::Result<()> {
self.board_type = variables::expand_variables(&self.board_type, scope)?;
self.dtb_file = self
.dtb_file
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.kernel_load_addr = self
.kernel_load_addr
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.fit_load_addr = self
.fit_load_addr
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.bootm_addr = self
.bootm_addr
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.success_regex = self
.success_regex
.iter()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.collect::<anyhow::Result<Vec<_>>>()?;
self.fail_regex = self
.fail_regex
.iter()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.collect::<anyhow::Result<Vec<_>>>()?;
self.uboot_cmd = self
.uboot_cmd
.as_ref()
.map(|values| {
values
.iter()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.collect::<anyhow::Result<Vec<_>>>()
})
.transpose()?;
self.shell_prefix = self
.shell_prefix
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.shell_init_cmd = self
.shell_init_cmd
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
self.server = self
.server
.as_deref()
.map(|value| tool.replace_string(value))
.map(|value| variables::expand_variables(value, scope))
.transpose()?;
Ok(())
}
Expand Down Expand Up @@ -293,7 +295,12 @@ port = 9000
let tool = Tool::new(Default::default()).unwrap();

config
.apply_overrides(&tool, Some(" rk3568 "), Some(" 127.0.0.1 "), Some(7000))
.apply_overrides(
&tool.variable_scope().unwrap(),
Some(" rk3568 "),
Some(" 127.0.0.1 "),
Some(7000),
)
.unwrap();

assert_eq!(config.board_type, "rk3568");
Expand Down
24 changes: 15 additions & 9 deletions ostool/src/board/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::board::{
use crate::{
Tool,
build::config::{BuildConfig, BuildSystem, Cargo},
project::variables,
};

#[derive(Debug, Clone, Default, PartialEq, Eq)]
Expand Down Expand Up @@ -185,8 +186,9 @@ impl Tool {
path: &Path,
) -> anyhow::Result<BoardRunConfig> {
self.sync_cargo_context(cargo);
let path = self.replace_path_variables(path.to_path_buf())?;
BoardRunConfig::read_from_path(self, path)
let scope = self.variable_scope()?;
let path = variables::expand_path_variables(path, &scope)?;
BoardRunConfig::read_from_path(&scope, path)
}

pub async fn ensure_board_run_config_in_dir_for_cargo(
Expand All @@ -195,24 +197,27 @@ impl Tool {
dir: &Path,
) -> anyhow::Result<BoardRunConfig> {
self.sync_cargo_context(cargo);
let dir = self.replace_path_variables(dir.to_path_buf())?;
BoardRunConfig::load_or_create(self, Some(dir.join(".board.toml"))).await
let scope = self.variable_scope()?;
let dir = variables::expand_path_variables(dir, &scope)?;
BoardRunConfig::load_or_create(&scope, Some(dir.join(".board.toml"))).await
}

pub async fn ensure_board_run_config_in_dir(
&mut self,
dir: &Path,
) -> anyhow::Result<BoardRunConfig> {
let dir = self.replace_path_variables(dir.to_path_buf())?;
BoardRunConfig::load_or_create(self, Some(dir.join(".board.toml"))).await
let scope = self.variable_scope()?;
let dir = variables::expand_path_variables(dir, &scope)?;
BoardRunConfig::load_or_create(&scope, Some(dir.join(".board.toml"))).await
}

pub async fn read_board_run_config_from_path(
&mut self,
path: &Path,
) -> anyhow::Result<BoardRunConfig> {
let path = self.replace_path_variables(path.to_path_buf())?;
BoardRunConfig::read_from_path(self, path)
let scope = self.variable_scope()?;
let path = variables::expand_path_variables(path, &scope)?;
BoardRunConfig::read_from_path(&scope, path)
}

pub async fn run_board(
Expand Down Expand Up @@ -259,8 +264,9 @@ impl Tool {
) -> anyhow::Result<()> {
let global_config = load_board_global_config_with_notice()?;
let mut board_config = board_config.clone();
let scope = self.variable_scope()?;
board_config.apply_overrides(
self,
&scope,
options.board_type.as_deref(),
options.server.as_deref(),
options.port,
Expand Down
Loading