Skip to content

Commit c3e3d17

Browse files
committed
Create schema for diff config properties
1 parent c45f4bb commit c3e3d17

File tree

23 files changed

+1115
-445
lines changed

23 files changed

+1115
-445
lines changed

Cargo.lock

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ strip = "debuginfo"
1313
codegen-units = 1
1414

1515
[workspace.package]
16-
version = "2.5.0"
16+
version = "2.6.0"
1717
authors = ["Luke Street <luke@street.dev>"]
1818
edition = "2021"
1919
license = "MIT OR Apache-2.0"

objdiff-cli/src/cmd/diff.rs

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::{
1212
time::Duration,
1313
};
1414

15-
use anyhow::{bail, Context, Result};
15+
use anyhow::{anyhow, bail, Context, Result};
1616
use argp::FromArgs;
1717
use crossterm::{
1818
event,
@@ -27,9 +27,11 @@ use objdiff_core::{
2727
watcher::{create_watcher, Watcher},
2828
BuildConfig,
2929
},
30-
config::{build_globset, default_watch_patterns, ProjectConfig, ProjectObject},
30+
config::{build_globset, ProjectConfig, ProjectObject},
3131
diff,
32-
diff::ObjDiff,
32+
diff::{
33+
ConfigEnum, ConfigPropertyId, ConfigPropertyKind, DiffObjConfig, MappingConfig, ObjDiff,
34+
},
3335
jobs::{
3436
objdiff::{start_build, ObjDiffConfig},
3537
Job, JobQueue, JobResult,
@@ -63,9 +65,6 @@ pub struct Args {
6365
#[argp(option, short = 'u')]
6466
/// Unit name within project
6567
unit: Option<String>,
66-
#[argp(switch, short = 'x')]
67-
/// Relax relocation diffs
68-
relax_reloc_diffs: bool,
6968
#[argp(option, short = 'o')]
7069
/// Output file (one-shot mode) ("-" for stdout)
7170
output: Option<PathBuf>,
@@ -75,6 +74,18 @@ pub struct Args {
7574
#[argp(positional)]
7675
/// Function symbol to diff
7776
symbol: Option<String>,
77+
#[argp(option, short = 'c')]
78+
/// Configuration property (key=value)
79+
config: Vec<String>,
80+
#[argp(option, short = 'm')]
81+
/// Symbol mapping (target=base)
82+
mapping: Vec<String>,
83+
#[argp(option)]
84+
/// Left symbol name for selection
85+
selecting_left: Option<String>,
86+
#[argp(option)]
87+
/// Right symbol name for selection
88+
selecting_right: Option<String>,
7889
}
7990

8091
pub fn run(args: Args) -> Result<()> {
@@ -84,7 +95,9 @@ pub fn run(args: Args) -> Result<()> {
8495
&args.project,
8596
&args.unit,
8697
) {
87-
(Some(t), Some(b), None, None) => (Some(t.clone()), Some(b.clone()), None),
98+
(Some(_), Some(_), None, None)
99+
| (Some(_), None, None, None)
100+
| (None, Some(_), None, None) => (args.target.clone(), args.base.clone(), None),
88101
(None, None, p, u) => {
89102
let project = match p {
90103
Some(project) => project.clone(),
@@ -193,24 +206,63 @@ pub fn run(args: Args) -> Result<()> {
193206
}
194207
}
195208

209+
fn build_config_from_args(args: &Args) -> Result<(DiffObjConfig, MappingConfig)> {
210+
let mut diff_config = DiffObjConfig::default();
211+
for config in &args.config {
212+
let (key, value) = config.split_once('=').context("--config expects \"key=value\"")?;
213+
let property_id = ConfigPropertyId::from_str(key)
214+
.map_err(|()| anyhow!("Invalid configuration property: {}", key))?;
215+
diff_config.set_property_value_str(property_id, value).map_err(|()| {
216+
let mut options = String::new();
217+
match property_id.kind() {
218+
ConfigPropertyKind::Boolean => {
219+
options = "true, false".to_string();
220+
}
221+
ConfigPropertyKind::Choice(variants) => {
222+
for (i, variant) in variants.iter().enumerate() {
223+
if i > 0 {
224+
options.push_str(", ");
225+
}
226+
options.push_str(variant.value);
227+
}
228+
}
229+
}
230+
anyhow!("Invalid value for {}. Expected one of: {}", property_id.name(), options)
231+
})?;
232+
}
233+
let mut mapping_config = MappingConfig {
234+
mappings: Default::default(),
235+
selecting_left: args.selecting_left.clone(),
236+
selecting_right: args.selecting_right.clone(),
237+
};
238+
for mapping in &args.mapping {
239+
let (target, base) =
240+
mapping.split_once('=').context("--mapping expects \"target=base\"")?;
241+
mapping_config.mappings.insert(target.to_string(), base.to_string());
242+
}
243+
Ok((diff_config, mapping_config))
244+
}
245+
196246
fn run_oneshot(
197247
args: &Args,
198248
output: &Path,
199249
target_path: Option<&Path>,
200250
base_path: Option<&Path>,
201251
) -> Result<()> {
202252
let output_format = OutputFormat::from_option(args.format.as_deref())?;
203-
let config = diff::DiffObjConfig {
204-
relax_reloc_diffs: args.relax_reloc_diffs,
205-
..Default::default() // TODO
206-
};
253+
let (diff_config, mapping_config) = build_config_from_args(args)?;
207254
let target = target_path
208-
.map(|p| obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display())))
255+
.map(|p| {
256+
obj::read::read(p, &diff_config).with_context(|| format!("Loading {}", p.display()))
257+
})
209258
.transpose()?;
210259
let base = base_path
211-
.map(|p| obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display())))
260+
.map(|p| {
261+
obj::read::read(p, &diff_config).with_context(|| format!("Loading {}", p.display()))
262+
})
212263
.transpose()?;
213-
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None)?;
264+
let result =
265+
diff::diff_objs(&diff_config, &mapping_config, target.as_ref(), base.as_ref(), None)?;
214266
let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d)));
215267
let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d)));
216268
write_output(&DiffResult::new(left, right), Some(output), output_format)?;
@@ -229,9 +281,10 @@ pub struct AppState {
229281
pub prev_obj: Option<(ObjInfo, ObjDiff)>,
230282
pub reload_time: Option<time::OffsetDateTime>,
231283
pub time_format: Vec<time::format_description::FormatItem<'static>>,
232-
pub relax_reloc_diffs: bool,
233284
pub watcher: Option<Watcher>,
234285
pub modified: Arc<AtomicBool>,
286+
pub diff_obj_config: DiffObjConfig,
287+
pub mapping_config: MappingConfig,
235288
}
236289

237290
fn create_objdiff_config(state: &AppState) -> ObjDiffConfig {
@@ -257,13 +310,8 @@ fn create_objdiff_config(state: &AppState) -> ObjDiffConfig {
257310
.is_some_and(|p| p.build_target.unwrap_or(false)),
258311
target_path: state.target_path.clone(),
259312
base_path: state.base_path.clone(),
260-
diff_obj_config: diff::DiffObjConfig {
261-
relax_reloc_diffs: state.relax_reloc_diffs,
262-
..Default::default() // TODO
263-
},
264-
symbol_mappings: Default::default(),
265-
selecting_left: None,
266-
selecting_right: None,
313+
diff_obj_config: state.diff_obj_config.clone(),
314+
mapping_config: state.mapping_config.clone(),
267315
}
268316
}
269317

@@ -314,6 +362,7 @@ fn run_interactive(
314362
let Some(symbol_name) = &args.symbol else { bail!("Interactive mode requires a symbol name") };
315363
let time_format = time::format_description::parse_borrowed::<2>("[hour]:[minute]:[second]")
316364
.context("Failed to parse time format")?;
365+
let (diff_obj_config, mapping_config) = build_config_from_args(&args)?;
317366
let mut state = AppState {
318367
jobs: Default::default(),
319368
waker: Default::default(),
@@ -326,17 +375,13 @@ fn run_interactive(
326375
prev_obj: None,
327376
reload_time: None,
328377
time_format,
329-
relax_reloc_diffs: args.relax_reloc_diffs,
330378
watcher: None,
331379
modified: Default::default(),
380+
diff_obj_config,
381+
mapping_config,
332382
};
333-
if let Some(project_dir) = &state.project_dir {
334-
let watch_patterns = state
335-
.project_config
336-
.as_ref()
337-
.and_then(|c| c.watch_patterns.as_ref())
338-
.cloned()
339-
.unwrap_or_else(default_watch_patterns);
383+
if let (Some(project_dir), Some(project_config)) = (&state.project_dir, &state.project_config) {
384+
let watch_patterns = project_config.build_watch_patterns()?;
340385
state.watcher = Some(create_watcher(
341386
state.modified.clone(),
342387
project_dir,

objdiff-cli/src/cmd/report.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,26 @@ fn report_object(
169169
}
170170
_ => {}
171171
}
172-
let config = diff::DiffObjConfig { relax_reloc_diffs: true, ..Default::default() };
172+
let diff_config = diff::DiffObjConfig { relax_reloc_diffs: true, ..Default::default() };
173+
let mapping_config = diff::MappingConfig::default();
173174
let target = object
174175
.target_path
175176
.as_ref()
176177
.map(|p| {
177-
obj::read::read(p, &config).with_context(|| format!("Failed to open {}", p.display()))
178+
obj::read::read(p, &diff_config)
179+
.with_context(|| format!("Failed to open {}", p.display()))
178180
})
179181
.transpose()?;
180182
let base = object
181183
.base_path
182184
.as_ref()
183185
.map(|p| {
184-
obj::read::read(p, &config).with_context(|| format!("Failed to open {}", p.display()))
186+
obj::read::read(p, &diff_config)
187+
.with_context(|| format!("Failed to open {}", p.display()))
185188
})
186189
.transpose()?;
187-
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None)?;
190+
let result =
191+
diff::diff_objs(&diff_config, &mapping_config, target.as_ref(), base.as_ref(), None)?;
188192

189193
let metadata = ReportUnitMetadata {
190194
complete: object.complete(),

objdiff-cli/src/views/function_diff.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ impl UiView for FunctionDiffUi {
370370
}
371371
// Toggle relax relocation diffs
372372
KeyCode::Char('x') => {
373-
state.relax_reloc_diffs = !state.relax_reloc_diffs;
373+
state.diff_obj_config.relax_reloc_diffs =
374+
!state.diff_obj_config.relax_reloc_diffs;
374375
result.redraw = true;
375376
return EventControlFlow::Reload;
376377
}

0 commit comments

Comments
 (0)