Summary: Use the JSON build report to figure out where each build output is instead of parsing the output of buck. Reviewed By: da319 Differential Revision: D29935374 fbshipit-source-id: f08f68889master
parent
bc99e3b38d
commit
95d25bd7c5
@ -0,0 +1,142 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
module L = Logging
|
||||
|
||||
(* example build report json output
|
||||
[
|
||||
{
|
||||
"success" : true,
|
||||
"results" : {
|
||||
"//annotations:annotations_infer" : {
|
||||
"success" : true,
|
||||
"type" : "BUILT_LOCALLY",
|
||||
"output" : "buck-out/gen/annotations/annotations_infer/infer_out"
|
||||
},
|
||||
"//module2:module2_infer" : {
|
||||
"success" : true,
|
||||
"type" : "BUILT_LOCALLY",
|
||||
"output" : "buck-out/gen/module2/module2_infer/infer_out"
|
||||
},
|
||||
"//module1:module1_infer" : {
|
||||
"success" : true,
|
||||
"type" : "BUILT_LOCALLY",
|
||||
"output" : "buck-out/gen/module1/module1_infer/infer_out"
|
||||
},
|
||||
"//module3:module1_infer" : {
|
||||
"success" : "SUCCESS",
|
||||
"type" : "BUILT_LOCALLY",
|
||||
"outputs" : {
|
||||
"DEFAULT" : [ "buck-out/gen/module1/module3_infer/infer_out" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"failures" : { }
|
||||
}%
|
||||
]
|
||||
*)
|
||||
|
||||
(** Read the build report json file buck produced, and parse into a list of pairs
|
||||
[(target, output-path)]. NB contrary to what buck documentation says, the output path is always
|
||||
present even when the target is locally cached. *)
|
||||
let read_and_parse_report build_report =
|
||||
let get_json_field fieldname = function
|
||||
| `Assoc fields ->
|
||||
List.Assoc.find fields ~equal:String.equal fieldname
|
||||
| _ ->
|
||||
None
|
||||
in
|
||||
let parse_target (target, json) =
|
||||
let path_opt =
|
||||
match get_json_field "output" json with
|
||||
| Some (`String str) ->
|
||||
Some str
|
||||
| _ -> (
|
||||
match get_json_field "outputs" json |> Option.bind ~f:(get_json_field "DEFAULT") with
|
||||
| Some (`List [`String str]) ->
|
||||
Some str
|
||||
| _ ->
|
||||
None )
|
||||
in
|
||||
match path_opt with
|
||||
| None ->
|
||||
L.internal_error "Could not parse target json: %s@." (Yojson.Basic.to_string json) ;
|
||||
None
|
||||
| Some path ->
|
||||
Some (target, path)
|
||||
in
|
||||
let parse_results = function
|
||||
| `Assoc results ->
|
||||
(* NB this will simply skip unparseable targets *)
|
||||
List.filter_map results ~f:parse_target |> Option.some
|
||||
| _ ->
|
||||
None
|
||||
in
|
||||
Yojson.Basic.from_file build_report |> get_json_field "results" |> Option.bind ~f:parse_results
|
||||
|
||||
|
||||
(** Function for processing paths in a buck build report and generating an [infer-deps.txt] file.
|
||||
Given a pair [(buck_target, output_path)],
|
||||
|
||||
- if [output_path] contains a capture DB, then generate the appropriate deps line;
|
||||
- if [output_path] contains an [infer-deps.txt] file, expand and inline it;
|
||||
- if [output_path] is a dummy target used in the combined genrule integration for clang targets,
|
||||
read its contents, parse them as an output directory path and apply the above two tests to
|
||||
that *)
|
||||
let expand_target acc (target, target_path) =
|
||||
let inline acc path =
|
||||
Utils.with_file_in path ~f:(In_channel.fold_lines ~init:acc ~f:(fun acc line -> line :: acc))
|
||||
in
|
||||
let expand_dir acc (target, target_path) =
|
||||
(* invariant: [target_path] is absolute *)
|
||||
let db_file = ResultsDirEntryName.get_path ~results_dir:target_path CaptureDB in
|
||||
if ISys.file_exists db_file then
|
||||
(* we found a capture DB so add this as a target line *)
|
||||
Printf.sprintf "%s\t-\t%s" target target_path :: acc
|
||||
else
|
||||
let infer_deps_file =
|
||||
ResultsDirEntryName.get_path ~results_dir:target_path CaptureDependencies
|
||||
in
|
||||
if ISys.file_exists infer_deps_file then
|
||||
(* we found an [infer_deps.txt] file so inline in *)
|
||||
inline acc infer_deps_file
|
||||
else (
|
||||
(* don't know what to do with this directory *)
|
||||
L.internal_error "Didn't find capture DB or infer-deps file in path %s.@\n" target_path ;
|
||||
acc )
|
||||
in
|
||||
let target_path =
|
||||
if Filename.is_absolute target_path then target_path else Config.project_root ^/ target_path
|
||||
in
|
||||
match Sys.is_directory target_path with
|
||||
| `Yes ->
|
||||
expand_dir acc (target, target_path)
|
||||
| _ when String.is_suffix target_path ~suffix:ResultsDirEntryName.buck_infer_deps_file_name ->
|
||||
(* direct path of an [infer-deps.txt] file, inline *)
|
||||
inline acc target_path
|
||||
| _ -> (
|
||||
(* assume path is an intermediate genrule output containing the
|
||||
output path of the underlying capture target *)
|
||||
match Utils.read_file target_path with
|
||||
| Ok [new_target_path] ->
|
||||
expand_dir acc (target, new_target_path)
|
||||
| Ok _ ->
|
||||
L.internal_error "Couldn't parse intermediate deps file %s@." target_path ;
|
||||
acc
|
||||
| Error error ->
|
||||
L.internal_error "Error %s@\nCouldn't read intermediate deps file %s@." error target_path ;
|
||||
acc )
|
||||
|
||||
|
||||
let parse_infer_deps ~build_report_file =
|
||||
match read_and_parse_report build_report_file with
|
||||
| None ->
|
||||
L.die InternalError "Couldn't parse buck build report: %s@." build_report_file
|
||||
| Some target_path_list ->
|
||||
List.fold target_path_list ~init:[] ~f:expand_target
|
||||
|> List.dedup_and_sort ~compare:String.compare
|
@ -0,0 +1,12 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
val parse_infer_deps : build_report_file:string -> string list
|
||||
(** parse a JSON build report by buck and return all capture DBs found in the [infer_deps.txt]
|
||||
format *)
|
Loading…
Reference in new issue