@@ -44,6 +44,87 @@ let base_of_sexp (sexp : Sexp.t) =
4444 | _ -> invalid_sexp sexp
4545;;
4646
47+ type process_info =
48+ { prog : string
49+ ; args : string list
50+ ; dir : string option
51+ ; exit_code : int
52+ ; error : string option
53+ ; stderr : string
54+ }
55+
56+ let parse_process_event (sexp : Sexp.t ) : process_info option =
57+ match base_of_sexp sexp with
58+ | "process" , "finish" , _ts , rest ->
59+ let rec extract_fields prog args dir exit error stderr = function
60+ | [] -> prog, args, dir, exit, error, stderr
61+ | Sexp. List [ Atom " process_args" ; List arg_sexps ] :: rest ->
62+ let args =
63+ List. filter_map arg_sexps ~f: (function
64+ | Sexp. Atom s -> Some s
65+ | _ -> None )
66+ in
67+ extract_fields prog (Some args) dir exit error stderr rest
68+ | Sexp. List [ Atom " prog" ; Atom p ] :: rest ->
69+ extract_fields (Some p) args dir exit error stderr rest
70+ | Sexp. List [ Atom " dir" ; Atom d ] :: rest ->
71+ extract_fields prog args (Some d) exit error stderr rest
72+ | Sexp. List [ Atom " exit" ; Atom e ] :: rest ->
73+ let exit_code =
74+ try int_of_string e with
75+ | Failure _ -> 0
76+ in
77+ extract_fields prog args dir (Some exit_code) error stderr rest
78+ | Sexp. List [ Atom " error" ; Atom err ] :: rest ->
79+ extract_fields prog args dir exit (Some err) stderr rest
80+ | Sexp. List [ Atom " stderr" ; Atom s ] :: rest ->
81+ extract_fields prog args dir exit error (Some s) rest
82+ | _ :: rest -> extract_fields prog args dir exit error stderr rest
83+ in
84+ let prog, args, dir, exit, error, stderr =
85+ extract_fields None None None None None None rest
86+ in
87+ (match prog with
88+ | None -> None
89+ | Some prog ->
90+ Some
91+ { prog
92+ ; args = Option. value args ~default: []
93+ ; dir
94+ ; exit_code = Option. value exit ~default: 0
95+ ; error
96+ ; stderr = Option. value stderr ~default: " "
97+ })
98+ | _ -> None
99+ ;;
100+
101+ let format_shell_command (info : process_info ) : string =
102+ let module Escape = Escape0 in
103+ let dir_str = Option. value info.dir ~default: " ." in
104+ let quoted_dir = Escape. quote_if_needed dir_str in
105+ let quoted_prog = Escape. quote_if_needed info.prog in
106+ let quoted_args = List. map info.args ~f: Escape. quote_if_needed in
107+ let cmd = String. concat ~sep: " " (quoted_prog :: quoted_args) in
108+ Printf. sprintf " (cd %s && %s)" quoted_dir cmd
109+ ;;
110+
111+ let format_output (info : process_info ) : string =
112+ let cmd_line = format_shell_command info in
113+ if info.exit_code = 0
114+ then cmd_line
115+ else (
116+ let error_line =
117+ match info.error with
118+ | Some err -> Printf. sprintf " # %s" err
119+ | None -> Printf. sprintf " # Exit code: %d" info.exit_code
120+ in
121+ let lines = [ cmd_line; error_line ] in
122+ let lines =
123+ if info.stderr <> " " then lines @ [ " # Stderr:" ; info.stderr ] else lines
124+ in
125+ String. concat ~sep: " \n " lines)
126+ ;;
127+
47128let iter_sexps_follow file ~f =
48129 Io.String_path. with_file_in ~binary: true file ~f: (fun chan ->
49130 let rec loop () =
@@ -183,10 +264,40 @@ let cat =
183264 Cmd. v info term
184265;;
185266
267+ let commands =
268+ let info =
269+ let doc = " Display executed processes in shell format" in
270+ Cmd. info " commands" ~doc
271+ in
272+ let term =
273+ let + trace_file =
274+ Arg. (
275+ value
276+ & opt (some string ) None
277+ & info
278+ [ " trace-file" ]
279+ ~docv: " FILE"
280+ ~doc: (Some " Read this trace file (default: _build/trace.json)" ))
281+ in
282+ let trace_file =
283+ match trace_file with
284+ | Some s -> s
285+ | None -> Path.Local. to_string Common. default_trace_file
286+ in
287+ iter_sexps trace_file ~f: (fun sexp ->
288+ match parse_process_event sexp with
289+ | Some info ->
290+ let output = format_output info in
291+ print_endline output
292+ | None -> () )
293+ in
294+ Cmd. v info term
295+ ;;
296+
186297let group =
187298 let info =
188299 let doc = " Commands to view dune's event trace" in
189300 Cmd. info " trace" ~doc
190301 in
191- Cmd. group info [ cat ]
302+ Cmd. group info [ cat; commands ]
192303;;
0 commit comments