diff --git a/Cargo.lock b/Cargo.lock index c55faa9..c3144b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2861,7 +2861,7 @@ dependencies = [ [[package]] name = "objdiff-cli" -version = "2.2.0" +version = "2.2.1" dependencies = [ "anyhow", "argp", @@ -2883,7 +2883,7 @@ dependencies = [ [[package]] name = "objdiff-core" -version = "2.2.0" +version = "2.2.1" dependencies = [ "anyhow", "arm-attr", @@ -2922,7 +2922,7 @@ dependencies = [ [[package]] name = "objdiff-gui" -version = "2.2.0" +version = "2.2.1" dependencies = [ "anyhow", "bytes", diff --git a/Cargo.toml b/Cargo.toml index cd1b3dc..c46832c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ strip = "debuginfo" codegen-units = 1 [workspace.package] -version = "2.2.0" +version = "2.2.1" authors = ["Luke Street "] edition = "2021" license = "MIT OR Apache-2.0" diff --git a/objdiff-cli/src/cmd/report.rs b/objdiff-cli/src/cmd/report.rs index 4bda109..169e3da 100644 --- a/objdiff-cli/src/cmd/report.rs +++ b/objdiff-cli/src/cmd/report.rs @@ -199,7 +199,7 @@ fn report_object( .unwrap_or_default(), auto_generated: object.metadata.as_ref().and_then(|m| m.auto_generated), }; - let mut measures = Measures::default(); + let mut measures = Measures { total_units: 1, ..Default::default() }; let mut sections = vec![]; let mut functions = vec![]; @@ -280,6 +280,7 @@ fn report_object( if metadata.complete.unwrap_or(false) { measures.complete_code = measures.total_code; measures.complete_data = measures.total_data; + measures.complete_units = 1; } measures.calc_fuzzy_match_percent(); measures.calc_matched_percent(); diff --git a/objdiff-core/protos/proto_descriptor.bin b/objdiff-core/protos/proto_descriptor.bin index 4551eea..88b01fd 100644 Binary files a/objdiff-core/protos/proto_descriptor.bin and b/objdiff-core/protos/proto_descriptor.bin differ diff --git a/objdiff-core/protos/report.proto b/objdiff-core/protos/report.proto index 3a4bbe7..ed7ebb8 100644 --- a/objdiff-core/protos/report.proto +++ b/objdiff-core/protos/report.proto @@ -32,6 +32,10 @@ message Measures { uint64 complete_data = 13; // Completed (or "linked") data percent float complete_data_percent = 14; + // Total number of units + uint32 total_units = 15; + // Completed (or "linked") units + uint32 complete_units = 16; } // Project progress report diff --git a/objdiff-core/src/bindings/report.rs b/objdiff-core/src/bindings/report.rs index f8e4962..7f2f561 100644 --- a/objdiff-core/src/bindings/report.rs +++ b/objdiff-core/src/bindings/report.rs @@ -8,9 +8,10 @@ use serde_json::error::Category; include!(concat!(env!("OUT_DIR"), "/objdiff.report.rs")); include!(concat!(env!("OUT_DIR"), "/objdiff.report.serde.rs")); -pub const REPORT_VERSION: u32 = 1; +pub const REPORT_VERSION: u32 = 2; impl Report { + /// Attempts to parse the report as binary protobuf or JSON. pub fn parse(data: &[u8]) -> Result { if data.is_empty() { bail!(std::io::Error::from(std::io::ErrorKind::UnexpectedEof)); @@ -25,6 +26,7 @@ impl Report { Ok(report) } + /// Attempts to parse the report as JSON, migrating from the legacy report format if necessary. fn from_json(bytes: &[u8]) -> Result { match serde_json::from_slice::(bytes) { Ok(report) => Ok(report), @@ -43,16 +45,23 @@ impl Report { } } + /// Migrates the report to the latest version. + /// Fails if the report version is newer than supported. pub fn migrate(&mut self) -> Result<()> { if self.version == 0 { self.migrate_v0()?; } + if self.version == 1 { + self.migrate_v1()?; + } if self.version != REPORT_VERSION { bail!("Unsupported report version: {}", self.version); } Ok(()) } + /// Adds `complete_code`, `complete_data`, `complete_code_percent`, and `complete_data_percent` + /// to measures, and sets `progress_categories` in unit metadata. fn migrate_v0(&mut self) -> Result<()> { let Some(measures) = &mut self.measures else { bail!("Missing measures in report"); @@ -61,15 +70,16 @@ impl Report { let Some(unit_measures) = &mut unit.measures else { bail!("Missing measures in report unit"); }; - let Some(metadata) = &mut unit.metadata else { - bail!("Missing metadata in report unit"); + let mut complete = false; + if let Some(metadata) = &mut unit.metadata { + if metadata.module_name.is_some() || metadata.module_id.is_some() { + metadata.progress_categories = vec!["modules".to_string()]; + } else { + metadata.progress_categories = vec!["dol".to_string()]; + } + complete = metadata.complete.unwrap_or(false); }; - if metadata.module_name.is_some() || metadata.module_id.is_some() { - metadata.progress_categories = vec!["modules".to_string()]; - } else { - metadata.progress_categories = vec!["dol".to_string()]; - } - if metadata.complete.unwrap_or(false) { + if complete { unit_measures.complete_code = unit_measures.total_code; unit_measures.complete_data = unit_measures.total_data; unit_measures.complete_code_percent = 100.0; @@ -84,10 +94,42 @@ impl Report { measures.complete_data += unit_measures.complete_data; } measures.calc_matched_percent(); + self.calculate_progress_categories(); self.version = 1; Ok(()) } + /// Adds `total_units` and `complete_units` to measures. + fn migrate_v1(&mut self) -> Result<()> { + let Some(total_measures) = &mut self.measures else { + bail!("Missing measures in report"); + }; + for unit in &mut self.units { + let Some(measures) = &mut unit.measures else { + bail!("Missing measures in report unit"); + }; + let complete = unit.metadata.as_ref().and_then(|m| m.complete).unwrap_or(false) as u32; + let progress_categories = + unit.metadata.as_ref().map(|m| m.progress_categories.as_slice()).unwrap_or(&[]); + measures.total_units = 1; + measures.complete_units = complete; + total_measures.total_units += 1; + total_measures.complete_units += complete; + for id in progress_categories { + if let Some(category) = self.categories.iter_mut().find(|c| &c.id == id) { + let Some(measures) = &mut category.measures else { + bail!("Missing measures in category"); + }; + measures.total_units += 1; + measures.complete_units += complete; + } + } + } + self.version = 2; + Ok(()) + } + + /// Calculate progress categories based on unit metadata. pub fn calculate_progress_categories(&mut self) { for unit in &self.units { let Some(metadata) = unit.metadata.as_ref() else { @@ -242,6 +284,8 @@ impl AddAssign for Measures { self.matched_functions += other.matched_functions; self.complete_code += other.complete_code; self.complete_data += other.complete_data; + self.total_units += other.total_units; + self.complete_units += other.complete_units; } }