11let tool_name = " api-diff"
22
3- let run (`Main_module main_module ) (`Ref_cmi reference ) (`Current_cmi current ) =
3+ type mode = Unwrapped | Wrapped of string | Cmi
4+
5+ let both_directories reference current =
6+ match (Sys. is_directory reference, Sys. is_directory current) with
7+ | true , true -> Ok true
8+ | false , false -> Ok false
9+ | _ ->
10+ Error
11+ " Arguments must either both be directories or both single .cmi files."
12+
13+ let print_warning main_module unwrapped =
14+ match (main_module, unwrapped) with
15+ | None , false -> ()
16+ | Some _ , false ->
17+ Printf. eprintf
18+ " %s: --main-module is ignored when diffing single .cmi files\n "
19+ tool_name
20+ | None , true ->
21+ Printf. eprintf
22+ " %s: --unwrapped is ignored when diffing single .cmi files\n " tool_name
23+ | Some _ , true ->
24+ Printf. eprintf
25+ " %s: --main-module and --unwrapped are ignored when diffing single \
26+ .cmi files\n "
27+ tool_name
28+
29+ let mode ~reference ~current ~main_module ~unwrapped =
430 let open CCResult.Infix in
5- let * reference_sig, current_sig, module_name =
6- match
7- (Sys. is_directory reference, Sys. is_directory current, main_module)
8- with
9- | true , true , Some main_module ->
31+ let * both_dirs = both_directories reference current in
32+ match (both_dirs, main_module, unwrapped) with
33+ | true , Some main_module , false -> Ok (Wrapped main_module)
34+ | true , None , true -> Ok Unwrapped
35+ | false , main_module , unwrapped ->
36+ print_warning main_module unwrapped;
37+ Ok Cmi
38+ | true , _ , _ ->
39+ Error
40+ " Either --main-module or --unwrapped must be provided when diffing \
41+ entire libraries."
42+
43+ let run (`Main_module main_module ) (`Unwrapped_library unwrapped )
44+ (`Ref_cmi reference ) (`Current_cmi current ) =
45+ let open CCResult.Infix in
46+ let * reference_map, current_map =
47+ let * curr_mode = mode ~reference ~current ~main_module ~unwrapped in
48+ match curr_mode with
49+ | Wrapped main_module ->
1050 let main_module = String. capitalize_ascii main_module in
11- let + reference_sig = Api_watch.Library. load ~main_module reference
12- and + current_sig = Api_watch.Library. load ~main_module current in
13- let module_name = String. capitalize_ascii main_module in
14- (reference_sig, current_sig, module_name)
15- | false , false , main_module ->
16- let () =
17- match main_module with
18- | None -> ()
19- | Some _ ->
20- Printf. eprintf
21- " %s: --main-module ignored when diffing single .cmi files\n "
22- tool_name
23- in
51+ let + reference_map = Api_watch.Library. load ~main_module reference
52+ and + current_map = Api_watch.Library. load ~main_module current in
53+ (reference_map, current_map)
54+ | Unwrapped ->
55+ let + reference_map = Api_watch.Library. load_unwrapped reference
56+ and + current_map = Api_watch.Library. load_unwrapped current in
57+ (reference_map, current_map)
58+ | Cmi ->
2459 let + reference_cmi, _ = Api_watch.Library. load_cmi reference
2560 and + current_cmi, module_name = Api_watch.Library. load_cmi current in
26- (reference_cmi, current_cmi, module_name)
27- | true , false , _ | false , true , _ ->
28- Error
29- " Arguments must either both be directories or both single .cmi files."
30- | true , true , None ->
31- Error " --main-module must be provided when diffing entire libraries."
61+ let reference_map =
62+ Api_watch.String_map. singleton module_name reference_cmi
63+ in
64+ let current_map =
65+ Api_watch.String_map. singleton module_name current_cmi
66+ in
67+ (reference_map, current_map)
3268 in
33- let diff =
34- Api_watch.Diff. interface ~module_name ~reference: reference_sig
35- ~current: current_sig
69+ let diff_map =
70+ Api_watch.Diff. library ~reference: reference_map ~current: current_map
71+ |> Api_watch.String_map. bindings
72+ |> List. filter_map (fun (_ , v ) -> v)
3673 in
37- match diff with
38- | None -> Ok 0
39- | Some diff ->
74+ let has_changes = not ( List. is_empty diff_map) in
75+ List. iter
76+ ( fun diff ->
4077 let text_diff = Api_watch.Text_diff. from_diff diff in
41- Api_watch.Text_diff.With_colors. pp Format. std_formatter text_diff;
42- Ok 1
78+ Api_watch.Text_diff.With_colors. pp Format. std_formatter text_diff)
79+ diff_map;
80+ if has_changes then Ok 1 else Ok 0
4381
4482let named f = Cmdliner.Term. (app (const f))
4583
@@ -54,6 +92,15 @@ let main_module =
5492 Cmdliner.Arg. (
5593 value & opt (some string ) None & info ~doc ~docv [ " main-module" ])
5694
95+ let unwrapped_library =
96+ let doc =
97+ " Loads a library without a main module. Ignored when diffing single \
98+ $(b,.cmi) files."
99+ in
100+ named
101+ (fun x -> `Unwrapped_library x)
102+ Cmdliner.Arg. (value & flag & info ~doc [ " unwrapped" ])
103+
57104let ref_cmi =
58105 let docv = " REF_CMI_FILES" in
59106 let doc =
@@ -79,7 +126,9 @@ let info =
79126 Cmd. info tool_name ~version: " %%VERSION%%" ~exits: Cmd.Exit. defaults
80127 ~doc: " List API changes between two versions of a library"
81128
82- let term = Cmdliner.Term. (const run $ main_module $ ref_cmi $ current_cmi)
129+ let term =
130+ Cmdliner.Term. (
131+ const run $ main_module $ unwrapped_library $ ref_cmi $ current_cmi)
83132
84133let () =
85134 Fmt_tty. setup_std_outputs () ;
0 commit comments