new: CSV output

This commit is contained in:
Wataru Otsubo 2024-07-14 11:12:01 +09:00
parent a14eb4ea48
commit eff62d7f09
5 changed files with 368 additions and 36 deletions

View file

@ -1,10 +1,9 @@
use core::{panic, str};
use std::{
collections::HashMap,
env,
fmt::Display,
fs::File,
io::{BufRead, BufReader, Write},
io::{BufRead, BufReader},
path::{self, PathBuf},
str::FromStr,
};
@ -15,17 +14,8 @@ use clap::Parser;
use log::{debug, error, info, trace, warn};
use regex::Regex;
use semver::Version;
fn get_default_output_path() -> PathBuf {
PathBuf::from_str("outpu.csv").expect("Error")
}
fn get_default_log_path() -> PathBuf {
let mut path = env::current_exe().unwrap();
path.pop();
path.push("log");
path.push("debug.log");
path
}
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
/// Parse master jathub logfile for PS Board QAQC and write out to CSV.
#[derive(Parser, Debug)]
@ -145,7 +135,7 @@ impl FromStr for PsbId {
/// Temporary stores raw values.
/// TODO: specify each filed types.(maybe multi values)
#[derive(Debug)]
struct BoardResult {
struct MasterBoardResult {
id: PsbId,
qspif: u8,
qspip: u8,
@ -158,11 +148,12 @@ struct BoardResult {
/// Full result for a single QAQC run from a log file on JATHub master.
#[derive(Debug)]
struct MasterLogResult {
pub struct MasterLogResult {
version: Version,
datetime: DateTime<Utc>,
shifter: String,
board_results: HashMap<Position, BoardResult>,
board_results: HashMap<Position, MasterBoardResult>,
filename: String,
}
/// Get version of shift script.
@ -193,7 +184,7 @@ fn extract_position_id(line: &str) -> Result<(Position, PsbId)> {
impl MasterLogResult {
/// Parse log file on master jathub.
fn parse_file(file: impl BufRead) -> Result<MasterLogResult> {
fn parse_file(file: impl BufRead, filename: String) -> Result<MasterLogResult> {
let mut lines = file.lines();
let version = {
@ -322,7 +313,7 @@ impl MasterLogResult {
.context(format!("No board on pos {}", pos))?
.clone();
let result = BoardResult {
let result = MasterBoardResult {
id: psbid,
qspif: parts
.get(1)
@ -370,17 +361,70 @@ impl MasterLogResult {
datetime,
shifter,
board_results,
filename,
})
}
fn write(&self, f: impl Write) -> Result<()> {
todo!()
}
}
fn check_csv_header(f: impl BufRead) -> Result<()> {
// f.lines()
todo!()
/// All information on QAQC stored in the database.
///
/// Everything without `Option` is available from master log.
///
/// TODO: use pos? shifter? version?
#[serde_as]
#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct PsbQaqcResult {
motherboard_id: u32,
daughterboard_id: Option<u32>,
#[serde_as(as = "DisplayFromStr")]
position: Position,
qspif: u8,
qspip: u8,
recov: u8,
clock: u8,
regac: u8,
asdtp: u8,
qaqc_result: u32,
lvds_tx_skew: Option<u32>,
ppl_lock_reset_count: Option<i32>,
timestamp: DateTime<Utc>,
qaqc_log_file: String,
firmware_ver: Option<Version>,
parameter_ver: Option<Version>,
fpga_dna: Option<u64>,
comment: String,
}
impl PsbQaqcResult {
/// Expand [`MasterLogResult`] to [`PsbQaqcResult`].
/// Filling unavailable fileds with [`None`]s.
pub fn from_masterlogresult(result: MasterLogResult) -> Vec<Self> {
let mut converted = vec![];
for (pos, boardresult) in result.board_results {
let new = PsbQaqcResult {
motherboard_id: boardresult.id.id,
daughterboard_id: None,
position: pos,
qspif: boardresult.qspif,
qspip: boardresult.qspip,
recov: boardresult.recov,
clock: boardresult.clock,
regac: boardresult.regac,
asdtp: boardresult.asdtp,
qaqc_result: boardresult.done.into(),
lvds_tx_skew: None,
ppl_lock_reset_count: None,
timestamp: result.datetime,
qaqc_log_file: result.filename.clone(),
firmware_ver: None,
parameter_ver: None,
fpga_dna: None,
comment: "".to_string(),
};
converted.push(new);
}
converted
}
}
fn main() -> Result<()> {
@ -397,9 +441,17 @@ fn main() -> Result<()> {
);
let result = {
let file = File::open(args.master_log)?;
let file = File::open(args.master_log.clone())?;
let reader = BufReader::new(file);
MasterLogResult::parse_file(reader)?
MasterLogResult::parse_file(
reader,
args.master_log
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string(),
)?
};
debug!("{:?}", result);
@ -407,8 +459,36 @@ fn main() -> Result<()> {
// let file = File::options()
// .read(true)
// .open(args.outfile)?;
// }
//
// let mut rdr = csv::Reader::from_reader(file);
// rdr.records();
// }
let expanded_results = PsbQaqcResult::from_masterlogresult(result);
let mut wtr = match args.outfile.exists() {
true => {
let file = File::options().read(true).append(true).open(args.outfile)?;
csv::WriterBuilder::new()
.has_headers(false)
.from_writer(file)
}
false => {
println!("Creating new file: {}", args.outfile.display());
let file = File::options()
.create_new(true)
.write(true)
.open(args.outfile)?;
csv::WriterBuilder::new()
.has_headers(true)
.from_writer(file)
}
};
for result in expanded_results {
wtr.serialize(result)?;
}
wtr.flush()?;
Ok(())
}
@ -417,8 +497,11 @@ mod test {
use std::str::FromStr;
use chrono::{DateTime, Utc};
use semver::Version;
use crate::{extract_position_id, extract_shifter_line, Position, PositionLayer, PsbId};
use crate::{
extract_position_id, extract_shifter_line, extract_version, Position, PositionLayer, PsbId,
};
#[test]
fn parse_position() {
@ -454,6 +537,14 @@ mod test {
assert!(DateTime::parse_from_str("Date: 2024-06-20T08:42:01+0000", "Date: %+").is_ok());
}
#[test]
fn parse_version() {
assert_eq!(
extract_version("Shift script: 1.0.0").unwrap(),
Version::new(1, 0, 0)
)
}
#[test]
fn parse_shifter_line() {
assert_eq!(extract_shifter_line("Shifters: foo").unwrap(), "foo");