Files
objdiff/objdiff-core/src/jobs/objdiff.rs
T

195 lines
5.9 KiB
Rust
Raw Normal View History

2025-02-07 00:10:49 -07:00
use std::{sync::mpsc::Receiver, task::Waker};
2024-10-11 18:37:14 -06:00
2025-02-09 11:11:09 -07:00
use anyhow::{bail, Error, Result};
2024-10-11 18:37:14 -06:00
use time::OffsetDateTime;
2025-02-07 00:10:49 -07:00
use typed_path::Utf8PlatformPathBuf;
2024-10-11 18:37:14 -06:00
use crate::{
build::{run_make, BuildConfig, BuildStatus},
2025-02-20 17:48:00 -07:00
diff::{diff_objs, DiffObjConfig, MappingConfig, ObjectDiff},
2024-10-11 18:37:14 -06:00
jobs::{start_job, update_status, Job, JobContext, JobResult, JobState},
2025-02-20 17:48:00 -07:00
obj::{read, Object},
2024-10-11 18:37:14 -06:00
};
pub struct ObjDiffConfig {
pub build_config: BuildConfig,
pub build_base: bool,
pub build_target: bool,
2025-02-07 00:10:49 -07:00
pub target_path: Option<Utf8PlatformPathBuf>,
pub base_path: Option<Utf8PlatformPathBuf>,
2024-10-11 18:37:14 -06:00
pub diff_obj_config: DiffObjConfig,
2024-12-29 16:57:18 -07:00
pub mapping_config: MappingConfig,
2024-10-11 18:37:14 -06:00
}
pub struct ObjDiffResult {
pub first_status: BuildStatus,
pub second_status: BuildStatus,
2025-02-20 17:48:00 -07:00
pub first_obj: Option<(Object, ObjectDiff)>,
pub second_obj: Option<(Object, ObjectDiff)>,
2024-10-11 18:37:14 -06:00
pub time: OffsetDateTime,
}
fn run_build(
context: &JobContext,
cancel: Receiver<()>,
2024-12-29 16:57:18 -07:00
config: ObjDiffConfig,
2024-10-11 18:37:14 -06:00
) -> Result<Box<ObjDiffResult>> {
let mut target_path_rel = None;
let mut base_path_rel = None;
if config.build_target || config.build_base {
let project_dir = config
.build_config
.project_dir
.as_ref()
.ok_or_else(|| Error::msg("Missing project dir"))?;
if let Some(target_path) = &config.target_path {
2025-02-09 11:11:09 -07:00
target_path_rel = match target_path.strip_prefix(project_dir) {
Ok(p) => Some(p.with_unix_encoding()),
Err(_) => {
bail!("Target path '{}' doesn't begin with '{}'", target_path, project_dir);
}
};
2024-10-11 18:37:14 -06:00
}
if let Some(base_path) = &config.base_path {
2025-02-09 11:11:09 -07:00
base_path_rel = match base_path.strip_prefix(project_dir) {
Ok(p) => Some(p.with_unix_encoding()),
Err(_) => {
bail!("Base path '{}' doesn't begin with '{}'", base_path, project_dir);
}
};
2024-10-11 18:37:14 -06:00
};
}
let mut total = 1;
if config.build_target && target_path_rel.is_some() {
total += 1;
}
if config.build_base && base_path_rel.is_some() {
total += 1;
}
if config.target_path.is_some() {
total += 1;
}
if config.base_path.is_some() {
total += 1;
}
let mut step_idx = 0;
let mut first_status = match target_path_rel {
Some(target_path_rel) if config.build_target => {
update_status(
context,
2025-02-07 00:10:49 -07:00
format!("Building target {}", target_path_rel),
2024-10-11 18:37:14 -06:00
step_idx,
total,
&cancel,
)?;
step_idx += 1;
2025-02-07 00:10:49 -07:00
run_make(&config.build_config, target_path_rel.as_ref())
2024-10-11 18:37:14 -06:00
}
_ => BuildStatus::default(),
};
let mut second_status = match base_path_rel {
Some(base_path_rel) if config.build_base => {
update_status(
context,
2025-02-07 00:10:49 -07:00
format!("Building base {}", base_path_rel),
2024-10-11 18:37:14 -06:00
step_idx,
total,
&cancel,
)?;
step_idx += 1;
2025-02-07 00:10:49 -07:00
run_make(&config.build_config, base_path_rel.as_ref())
2024-10-11 18:37:14 -06:00
}
_ => BuildStatus::default(),
};
let time = OffsetDateTime::now_utc();
let first_obj = match &config.target_path {
Some(target_path) if first_status.success => {
update_status(
context,
2025-02-07 00:10:49 -07:00
format!("Loading target {}", target_path),
2024-10-11 18:37:14 -06:00
step_idx,
total,
&cancel,
)?;
step_idx += 1;
2025-02-07 00:10:49 -07:00
match read::read(target_path.as_ref(), &config.diff_obj_config) {
2024-10-11 18:37:14 -06:00
Ok(obj) => Some(obj),
Err(e) => {
first_status = BuildStatus {
success: false,
2025-02-07 00:10:49 -07:00
stdout: format!("Loading object '{}'", target_path),
2024-10-11 18:37:14 -06:00
stderr: format!("{:#}", e),
..Default::default()
};
None
}
}
}
Some(_) => {
step_idx += 1;
None
}
_ => None,
};
let second_obj = match &config.base_path {
Some(base_path) if second_status.success => {
update_status(
context,
2025-02-07 00:10:49 -07:00
format!("Loading base {}", base_path),
2024-10-11 18:37:14 -06:00
step_idx,
total,
&cancel,
)?;
step_idx += 1;
2025-02-07 00:10:49 -07:00
match read::read(base_path.as_ref(), &config.diff_obj_config) {
2024-10-11 18:37:14 -06:00
Ok(obj) => Some(obj),
Err(e) => {
second_status = BuildStatus {
success: false,
2025-02-07 00:10:49 -07:00
stdout: format!("Loading object '{}'", base_path),
2024-10-11 18:37:14 -06:00
stderr: format!("{:#}", e),
..Default::default()
};
None
}
}
}
Some(_) => {
step_idx += 1;
None
}
_ => None,
};
update_status(context, "Performing diff".to_string(), step_idx, total, &cancel)?;
step_idx += 1;
2024-12-29 16:57:18 -07:00
let result = diff_objs(
first_obj.as_ref(),
second_obj.as_ref(),
None,
2025-02-20 17:48:00 -07:00
&config.diff_obj_config,
&config.mapping_config,
2024-12-29 16:57:18 -07:00
)?;
2024-10-11 18:37:14 -06:00
update_status(context, "Complete".to_string(), step_idx, total, &cancel)?;
Ok(Box::new(ObjDiffResult {
first_status,
second_status,
first_obj: first_obj.and_then(|o| result.left.map(|d| (o, d))),
second_obj: second_obj.and_then(|o| result.right.map(|d| (o, d))),
time,
}))
}
pub fn start_build(waker: Waker, config: ObjDiffConfig) -> JobState {
start_job(waker, "Build", Job::ObjDiff, move |context, cancel| {
run_build(&context, cancel, config).map(|result| JobResult::ObjDiff(Some(result)))
})
}