opentitanlib/test_utils/
init.rs1use anyhow::Result;
6use clap::Args;
7use directories::ProjectDirs;
8use log::LevelFilter;
9use std::env::ArgsOs;
10use std::ffi::OsString;
11use std::io::ErrorKind;
12use std::iter::Iterator;
13use std::path::PathBuf;
14use std::str::FromStr;
15
16use super::bootstrap::Bootstrap;
17use super::load_bitstream::LoadBitstream;
18use crate::app::TransportWrapper;
19use crate::backend;
20
21#[derive(Debug, Args)]
22pub struct InitializeTest {
23 #[arg(long, value_parser = PathBuf::from_str, default_value = "config")]
25 pub rcfile: PathBuf,
26
27 #[arg(long, default_value = "off")]
28 pub logging: LevelFilter,
29
30 #[command(flatten)]
31 pub backend_opts: backend::BackendOpts,
32
33 #[command(flatten)]
34 pub load_bitstream: LoadBitstream,
35
36 #[command(flatten)]
37 pub bootstrap: Bootstrap,
38}
39
40impl InitializeTest {
41 pub fn init_logging(&self) {
42 let level = self.logging;
43 if level != LevelFilter::Off {
46 env_logger::Builder::from_default_env()
47 .format_target(true)
48 .format_module_path(false)
49 .format_timestamp_millis()
50 .filter(None, level)
51 .init();
52 }
53 }
54
55 pub fn parse_command_line(&self, mut args: ArgsOs) -> Result<Vec<OsString>> {
58 self.init_logging();
60 if self.rcfile.as_os_str().is_empty() {
61 return Ok(Vec::new());
63 }
64
65 let rcfile = if let Some(base) = ProjectDirs::from("org", "opentitan", "opentitantool") {
68 base.config_dir().join(&self.rcfile)
69 } else {
70 self.rcfile.clone()
71 };
72
73 let mut arguments = vec![args.next().unwrap()];
75
76 match std::fs::read_to_string(&rcfile) {
78 Ok(content) => {
79 for line in content.split('\n') {
80 let (line, _) = line.split_once('#').unwrap_or((line, ""));
82 arguments.extend(shellwords::split(line)?.iter().map(OsString::from));
83 }
84 Ok(())
85 }
86 Err(e) if e.kind() == ErrorKind::NotFound => {
87 log::warn!("Could not read {:?}. Ignoring.", rcfile);
88 Ok(())
89 }
90 Err(e) => Err(anyhow::Error::new(e).context(format!("Reading file {:?}", rcfile))),
91 }?;
92
93 arguments.extend(args);
95 Ok(arguments)
96 }
97
98 pub fn print_result(
101 operation: &str,
102 result: Result<Option<Box<dyn erased_serde::Serialize>>>,
103 ) -> Result<()> {
104 match result {
105 Ok(Some(value)) => {
106 log::info!("{}: success.", operation);
107 println!(
108 "\"{}\": {}",
109 operation,
110 serde_json::to_string_pretty(&value)?
111 );
112 Ok(())
113 }
114 Ok(None) => {
115 log::info!("{}: success.", operation);
116 println!("\"{}\": true", operation);
117 Ok(())
118 }
119 Err(e) => {
120 log::info!("{}: {:?}.", operation, e);
121 println!("\"{}\": false", operation);
122 Err(e)
123 }
124 }
125 }
126
127 pub fn init_target(&self) -> Result<TransportWrapper> {
128 let transport = backend::create(&self.backend_opts)?;
130
131 transport.apply_default_configuration(None)?;
133
134 let _uart = self.bootstrap.options.uart_params.create(&transport)?;
136
137 Self::print_result(
139 "load_bitstream",
140 self.load_bitstream.init(&transport).map(|_| None),
141 )?;
142
143 Self::print_result("bootstrap", self.bootstrap.init(&transport))?;
145 Ok(transport)
146 }
147}