@@ -12,7 +12,7 @@ use std::{
12
12
time:: Duration ,
13
13
} ;
14
14
15
- use anyhow:: { bail, Context , Result } ;
15
+ use anyhow:: { anyhow , bail, Context , Result } ;
16
16
use argp:: FromArgs ;
17
17
use crossterm:: {
18
18
event,
@@ -27,9 +27,11 @@ use objdiff_core::{
27
27
watcher:: { create_watcher, Watcher } ,
28
28
BuildConfig ,
29
29
} ,
30
- config:: { build_globset, default_watch_patterns , ProjectConfig , ProjectObject } ,
30
+ config:: { build_globset, ProjectConfig , ProjectObject } ,
31
31
diff,
32
- diff:: ObjDiff ,
32
+ diff:: {
33
+ ConfigEnum , ConfigPropertyId , ConfigPropertyKind , DiffObjConfig , MappingConfig , ObjDiff ,
34
+ } ,
33
35
jobs:: {
34
36
objdiff:: { start_build, ObjDiffConfig } ,
35
37
Job , JobQueue , JobResult ,
@@ -63,9 +65,6 @@ pub struct Args {
63
65
#[ argp( option, short = 'u' ) ]
64
66
/// Unit name within project
65
67
unit : Option < String > ,
66
- #[ argp( switch, short = 'x' ) ]
67
- /// Relax relocation diffs
68
- relax_reloc_diffs : bool ,
69
68
#[ argp( option, short = 'o' ) ]
70
69
/// Output file (one-shot mode) ("-" for stdout)
71
70
output : Option < PathBuf > ,
@@ -75,6 +74,18 @@ pub struct Args {
75
74
#[ argp( positional) ]
76
75
/// Function symbol to diff
77
76
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 > ,
78
89
}
79
90
80
91
pub fn run ( args : Args ) -> Result < ( ) > {
@@ -84,7 +95,9 @@ pub fn run(args: Args) -> Result<()> {
84
95
& args. project ,
85
96
& args. unit ,
86
97
) {
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 ) ,
88
101
( None , None , p, u) => {
89
102
let project = match p {
90
103
Some ( project) => project. clone ( ) ,
@@ -193,24 +206,63 @@ pub fn run(args: Args) -> Result<()> {
193
206
}
194
207
}
195
208
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
+
196
246
fn run_oneshot (
197
247
args : & Args ,
198
248
output : & Path ,
199
249
target_path : Option < & Path > ,
200
250
base_path : Option < & Path > ,
201
251
) -> Result < ( ) > {
202
252
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) ?;
207
254
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
+ } )
209
258
. transpose ( ) ?;
210
259
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
+ } )
212
263
. 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 ) ?;
214
266
let left = target. as_ref ( ) . and_then ( |o| result. left . as_ref ( ) . map ( |d| ( o, d) ) ) ;
215
267
let right = base. as_ref ( ) . and_then ( |o| result. right . as_ref ( ) . map ( |d| ( o, d) ) ) ;
216
268
write_output ( & DiffResult :: new ( left, right) , Some ( output) , output_format) ?;
@@ -229,9 +281,10 @@ pub struct AppState {
229
281
pub prev_obj : Option < ( ObjInfo , ObjDiff ) > ,
230
282
pub reload_time : Option < time:: OffsetDateTime > ,
231
283
pub time_format : Vec < time:: format_description:: FormatItem < ' static > > ,
232
- pub relax_reloc_diffs : bool ,
233
284
pub watcher : Option < Watcher > ,
234
285
pub modified : Arc < AtomicBool > ,
286
+ pub diff_obj_config : DiffObjConfig ,
287
+ pub mapping_config : MappingConfig ,
235
288
}
236
289
237
290
fn create_objdiff_config ( state : & AppState ) -> ObjDiffConfig {
@@ -257,13 +310,8 @@ fn create_objdiff_config(state: &AppState) -> ObjDiffConfig {
257
310
. is_some_and ( |p| p. build_target . unwrap_or ( false ) ) ,
258
311
target_path : state. target_path . clone ( ) ,
259
312
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 ( ) ,
267
315
}
268
316
}
269
317
@@ -314,6 +362,7 @@ fn run_interactive(
314
362
let Some ( symbol_name) = & args. symbol else { bail ! ( "Interactive mode requires a symbol name" ) } ;
315
363
let time_format = time:: format_description:: parse_borrowed :: < 2 > ( "[hour]:[minute]:[second]" )
316
364
. context ( "Failed to parse time format" ) ?;
365
+ let ( diff_obj_config, mapping_config) = build_config_from_args ( & args) ?;
317
366
let mut state = AppState {
318
367
jobs : Default :: default ( ) ,
319
368
waker : Default :: default ( ) ,
@@ -326,17 +375,13 @@ fn run_interactive(
326
375
prev_obj : None ,
327
376
reload_time : None ,
328
377
time_format,
329
- relax_reloc_diffs : args. relax_reloc_diffs ,
330
378
watcher : None ,
331
379
modified : Default :: default ( ) ,
380
+ diff_obj_config,
381
+ mapping_config,
332
382
} ;
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 ( ) ?;
340
385
state. watcher = Some ( create_watcher (
341
386
state. modified . clone ( ) ,
342
387
project_dir,
0 commit comments