[buck] split flavor handling/capture into own module

Summary:
- Move code out of Buck that is specific to infer flavors.
- Move capture function and sundry from Driver to the new module.

Reviewed By: jvillard

Differential Revision: D21592276

fbshipit-source-id: 9bef89e8f
master
Nikos Gorogiannis 5 years ago committed by Facebook GitHub Bot
parent e9118afccd
commit 4af4cdfbdb

@ -340,20 +340,6 @@ let parse_command_and_targets (buck_mode : BuckMode.t) ~filter_kind original_buc
(command, parsed_args.rev_not_targets', targets)
type flavored_arguments = {command: string; rev_not_targets: string list; targets: string list}
let add_flavors_to_buck_arguments buck_mode ~filter_kind ~extra_flavors original_buck_args =
let command, rev_not_targets, targets =
parse_command_and_targets buck_mode ~filter_kind original_buck_args
in
let targets =
List.rev_map targets ~f:(fun t ->
Target.(t |> of_string |> add_flavor ~extra_flavors buck_mode Config.command |> to_string)
)
in
{command; rev_not_targets; targets}
let rec exceed_length ~max = function
| _ when max < 0 ->
true
@ -380,109 +366,3 @@ let filter_compatible subcommand args =
List.filter args ~f:(fun arg -> not (String.equal blacklist arg))
| _ ->
args
let capture_buck_args =
let clang_path =
List.fold ["clang"; "install"; "bin"; "clang"] ~init:Config.fcp_dir ~f:Filename.concat
in
List.append
[ "--show-output"
; "--config"
; "client.id=infer.clang"
; "--config"
; Printf.sprintf "*//infer.infer_bin=%s" Config.bin_dir
; "--config"
; Printf.sprintf "*//infer.clang_compiler=%s" clang_path
; "--config"
; Printf.sprintf "*//infer.clang_plugin=%s" Config.clang_plugin_path
; "--config"
; "*//cxx.pch_enabled=false"
; "--config"
; (* Infer doesn't support C++ modules yet (T35656509) *)
"*//cxx.modules_default=false"
; "--config"
; "*//cxx.modules=false" ]
( ( match Config.xcode_developer_dir with
| Some d ->
["--config"; Printf.sprintf "apple.xcode_developer_dir=%s" d]
| None ->
[] )
@ (if Config.keep_going then ["--keep-going"] else [])
@ ["-j"; Int.to_string Config.jobs]
@ (match Config.load_average with Some l -> ["-L"; Float.to_string l] | None -> [])
@ List.rev_append Config.buck_build_args
( if not (List.is_empty Config.buck_blacklist) then
[ "--config"
; Printf.sprintf "*//infer.blacklist_regex=(%s)"
(String.concat ~sep:")|(" Config.buck_blacklist) ]
else [] ) )
let run_buck_build prog buck_build_args =
L.debug Capture Verbose "%s %s@." prog (List.to_string ~f:Fn.id buck_build_args) ;
let infer_args =
Option.fold (Sys.getenv CommandLineOption.args_env_var) ~init:"--fcp-syntax-only"
~f:(fun acc arg -> Printf.sprintf "%s%c%s" acc CommandLineOption.env_var_sep arg)
in
let extend_env = [(CommandLineOption.args_env_var, infer_args)] in
let lines = wrap_buck_call ~extend_env ~label:"build" (prog :: buck_build_args) in
(* Process a line of buck stdout output, in this case the result of '--show-output'
These paths (may) contain a 'infer-deps.txt' file, which we will later merge
*)
let process_buck_line acc line =
L.debug Capture Verbose "BUCK OUT: %s@." line ;
match String.split ~on:' ' line with
| [_; target_path] ->
let filename =
ResultsDirEntryName.get_path
~results_dir:(Config.project_root ^/ target_path)
BuckDependencies
in
if PolyVariantEqual.(Sys.file_exists filename = `Yes) then filename :: acc else acc
| _ ->
L.internal_error "Couldn't parse buck target output: %s" line ;
acc
in
List.fold lines ~init:[] ~f:process_buck_line
let merge_deps_files depsfiles =
let buck_out = Config.project_root ^/ Config.buck_out_gen in
let depslines, depsfiles =
match depsfiles with
| [] when Config.keep_going || Config.buck_merge_all_deps ->
let infouts =
Utils.fold_folders ~init:[] ~path:buck_out ~f:(fun acc dir ->
if
String.is_substring dir ~substring:"infer-out"
&& PolyVariantEqual.(
Sys.file_exists (ResultsDirEntryName.get_path ~results_dir:dir CaptureDB)
= `Yes)
then Printf.sprintf "\t\t%s" dir :: acc
else acc )
in
(infouts, [])
| [] when Config.buck_merge_all_deps ->
let files =
Utils.find_files ~path:buck_out ~extension:ResultsDirEntryName.buck_infer_deps_file_name
in
([], files)
| _ ->
([], depsfiles)
in
depslines
@ List.fold depsfiles ~init:[] ~f:(fun acc file ->
List.rev_append acc (Utils.with_file_in file ~f:In_channel.input_lines) )
|> List.dedup_and_sort ~compare:String.compare
let clang_flavor_capture ~prog ~buck_build_cmd =
if Config.keep_going && not Config.continue_capture then
Process.create_process_and_wait ~prog ~args:["clean"] ;
let depsfiles = run_buck_build prog (buck_build_cmd @ capture_buck_args) in
let deplines = merge_deps_files depsfiles in
let infer_out_depsfile = ResultsDir.get_path BuckDependencies in
Utils.with_file_out infer_out_depsfile ~f:(fun out_chan ->
Out_channel.output_lines out_chan deplines ) ;
()

@ -7,6 +7,16 @@
open! IStd
module Target : sig
type t
val of_string : string -> t
val to_string : t -> string
val add_flavor : BuckMode.t -> InferCommand.t -> extra_flavors:string list -> t -> t
end
val wrap_buck_call :
?extend_env:(string * string) list -> label:string -> string list -> string list
(** Wrap a call to buck while (i) logging standard error to our standard error in real time; (ii)
@ -27,23 +37,8 @@ val parse_command_and_targets :
-> string list
-> string * string list * string list
type flavored_arguments = {command: string; rev_not_targets: string list; targets: string list}
val add_flavors_to_buck_arguments :
BuckMode.t
-> filter_kind:[< `Yes | `No | `Auto]
-> extra_flavors:string list
-> string list
-> flavored_arguments
(** Add infer flavors to the targets in the given buck arguments, depending on the infer analyzer.
For instance, in capture mode, the buck command: build //foo/bar:baz#some,flavor becomes: build
//foo/bar:baz#infer-capture-all,some,flavor *)
val store_args_in_file : string list -> string list
(** Given a list of arguments, stores them in a file if needed and returns the new command line *)
val filter_compatible : [> `Targets] -> string list -> string list
(** keep only the options compatible with the given Buck subcommand *)
val clang_flavor_capture : prog:string -> buck_build_cmd:string list -> unit
(** do a buck/clang flavor capture given the prog and build command (buck args) *)

@ -0,0 +1,154 @@
(*
* 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 CLOpt = CommandLineOption
module L = Logging
module F = Format
type flavored_arguments = {command: string; rev_not_targets: string list; targets: string list}
let add_flavors_to_buck_arguments buck_mode ~filter_kind ~extra_flavors original_buck_args =
let command, rev_not_targets, targets =
Buck.parse_command_and_targets buck_mode ~filter_kind original_buck_args
in
let targets =
List.rev_map targets ~f:(fun t ->
Buck.Target.(
t |> of_string |> add_flavor ~extra_flavors buck_mode Config.command |> to_string) )
in
{command; rev_not_targets; targets}
let capture_buck_args =
let clang_path =
List.fold ["clang"; "install"; "bin"; "clang"] ~init:Config.fcp_dir ~f:Filename.concat
in
List.append
[ "--show-output"
; "--config"
; "client.id=infer.clang"
; "--config"
; Printf.sprintf "*//infer.infer_bin=%s" Config.bin_dir
; "--config"
; Printf.sprintf "*//infer.clang_compiler=%s" clang_path
; "--config"
; Printf.sprintf "*//infer.clang_plugin=%s" Config.clang_plugin_path
; "--config"
; "*//cxx.pch_enabled=false"
; "--config"
; (* Infer doesn't support C++ modules yet (T35656509) *)
"*//cxx.modules_default=false"
; "--config"
; "*//cxx.modules=false" ]
( ( match Config.xcode_developer_dir with
| Some d ->
["--config"; Printf.sprintf "apple.xcode_developer_dir=%s" d]
| None ->
[] )
@ (if Config.keep_going then ["--keep-going"] else [])
@ ["-j"; Int.to_string Config.jobs]
@ (match Config.load_average with Some l -> ["-L"; Float.to_string l] | None -> [])
@ List.rev_append Config.buck_build_args
( if not (List.is_empty Config.buck_blacklist) then
[ "--config"
; Printf.sprintf "*//infer.blacklist_regex=(%s)"
(String.concat ~sep:")|(" Config.buck_blacklist) ]
else [] ) )
let run_buck_build prog buck_build_args =
L.debug Capture Verbose "%s %s@." prog (List.to_string ~f:Fn.id buck_build_args) ;
let infer_args =
Option.fold (Sys.getenv CommandLineOption.args_env_var) ~init:"--fcp-syntax-only"
~f:(fun acc arg -> Printf.sprintf "%s%c%s" acc CommandLineOption.env_var_sep arg)
in
let extend_env = [(CommandLineOption.args_env_var, infer_args)] in
let lines = Buck.wrap_buck_call ~extend_env ~label:"build" (prog :: buck_build_args) in
(* Process a line of buck stdout output, in this case the result of '--show-output'
These paths (may) contain a 'infer-deps.txt' file, which we will later merge
*)
let process_buck_line acc line =
L.debug Capture Verbose "BUCK OUT: %s@." line ;
match String.split ~on:' ' line with
| [_; target_path] ->
let filename =
ResultsDirEntryName.get_path
~results_dir:(Config.project_root ^/ target_path)
BuckDependencies
in
if PolyVariantEqual.(Sys.file_exists filename = `Yes) then filename :: acc else acc
| _ ->
L.internal_error "Couldn't parse buck target output: %s" line ;
acc
in
List.fold lines ~init:[] ~f:process_buck_line
let merge_deps_files depsfiles =
let buck_out = Config.project_root ^/ Config.buck_out_gen in
let depslines, depsfiles =
match depsfiles with
| [] when Config.keep_going || Config.buck_merge_all_deps ->
let infouts =
Utils.fold_folders ~init:[] ~path:buck_out ~f:(fun acc dir ->
if
String.is_substring dir ~substring:"infer-out"
&& PolyVariantEqual.(
Sys.file_exists (ResultsDirEntryName.get_path ~results_dir:dir CaptureDB)
= `Yes)
then Printf.sprintf "\t\t%s" dir :: acc
else acc )
in
(infouts, [])
| [] when Config.buck_merge_all_deps ->
let files =
Utils.find_files ~path:buck_out ~extension:ResultsDirEntryName.buck_infer_deps_file_name
in
([], files)
| _ ->
([], depsfiles)
in
depslines
@ List.fold depsfiles ~init:[] ~f:(fun acc file ->
List.rev_append acc (Utils.with_file_in file ~f:In_channel.input_lines) )
|> List.dedup_and_sort ~compare:String.compare
let clang_flavor_capture ~prog ~buck_build_cmd =
if Config.keep_going && not Config.continue_capture then
Process.create_process_and_wait ~prog ~args:["clean"] ;
let depsfiles = run_buck_build prog (buck_build_cmd @ capture_buck_args) in
let deplines = merge_deps_files depsfiles in
let infer_out_depsfile = ResultsDir.get_path BuckDependencies in
Utils.with_file_out infer_out_depsfile ~f:(fun out_chan ->
Out_channel.output_lines out_chan deplines ) ;
()
let capture build_cmd =
let prog, buck_args = (List.hd_exn build_cmd, List.tl_exn build_cmd) in
(* let children infer processes know that they are inside Buck *)
let infer_args_with_buck =
String.concat
~sep:(String.of_char CLOpt.env_var_sep)
(Option.to_list (Sys.getenv CLOpt.args_env_var) @ ["--buck"])
in
Unix.putenv ~key:CLOpt.args_env_var ~data:infer_args_with_buck ;
let {command; rev_not_targets; targets} =
add_flavors_to_buck_arguments ClangFlavors ~filter_kind:`Auto ~extra_flavors:[] buck_args
in
if List.is_empty targets then ()
else
let all_args = List.rev_append rev_not_targets targets in
let updated_buck_cmd =
command :: List.rev_append Config.buck_build_args_no_inline (Buck.store_args_in_file all_args)
in
L.debug Capture Quiet "Processed buck command '%a'@\n" (Pp.seq F.pp_print_string)
updated_buck_cmd ;
let prog, buck_build_cmd = (prog, updated_buck_cmd) in
ResultsDir.RunState.set_merge_capture true ;
clang_flavor_capture ~prog ~buck_build_cmd

@ -0,0 +1,23 @@
(*
* 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
type flavored_arguments = {command: string; rev_not_targets: string list; targets: string list}
val add_flavors_to_buck_arguments :
BuckMode.t
-> filter_kind:[< `Yes | `No | `Auto]
-> extra_flavors:string list
-> string list
-> flavored_arguments
(** Add infer flavors to the targets in the given buck arguments, depending on the infer analyzer.
For instance, in capture mode, the buck command: build //foo/bar:baz#some,flavor becomes: build
//foo/bar:baz#infer-capture-all,some,flavor *)
val capture : string list -> unit
(** do a buck/clang flavor capture given the prog and build command (buck args) *)

@ -70,7 +70,7 @@ let run_compilation_database compilation_database should_capture_file =
(** Computes the compilation database files. *)
let get_compilation_database_files_buck db_deps ~prog ~args =
match
Buck.add_flavors_to_buck_arguments (ClangCompilationDB db_deps) ~filter_kind:`Yes
BuckFlavors.add_flavors_to_buck_arguments (ClangCompilationDB db_deps) ~filter_kind:`Yes
~extra_flavors:Config.append_buck_flavors args
with
| {targets} when List.is_empty targets ->

@ -110,42 +110,6 @@ let capture_with_compilation_database db_files =
CaptureCompilationDatabase.capture_files_in_database compilation_database
let buck_capture build_cmd =
let prog_build_cmd_opt =
let prog, buck_args = (List.hd_exn build_cmd, List.tl_exn build_cmd) in
match Config.buck_mode with
| Some ClangFlavors ->
(* let children infer processes know that they are inside Buck *)
let infer_args_with_buck =
String.concat
~sep:(String.of_char CLOpt.env_var_sep)
(Option.to_list (Sys.getenv CLOpt.args_env_var) @ ["--buck"])
in
Unix.putenv ~key:CLOpt.args_env_var ~data:infer_args_with_buck ;
let {Buck.command; rev_not_targets; targets} =
Buck.add_flavors_to_buck_arguments ClangFlavors ~filter_kind:`Auto ~extra_flavors:[]
buck_args
in
if List.is_empty targets then None
else
let all_args = List.rev_append rev_not_targets targets in
let updated_buck_cmd =
command
:: List.rev_append Config.buck_build_args_no_inline (Buck.store_args_in_file all_args)
in
Logging.(debug Capture Quiet)
"Processed buck command '%a'@\n" (Pp.seq F.pp_print_string) updated_buck_cmd ;
Some (prog, updated_buck_cmd)
| _ ->
Some (prog, build_cmd)
in
Option.iter prog_build_cmd_opt ~f:(fun (prog, buck_build_cmd) ->
L.progress "Capturing in buck mode...@." ;
if Option.exists ~f:BuckMode.is_clang_flavors Config.buck_mode then
ResultsDir.RunState.set_merge_capture true ;
Buck.clang_flavor_capture ~prog ~buck_build_cmd )
let capture ~changed_files = function
| Analyze ->
()
@ -153,7 +117,8 @@ let capture ~changed_files = function
L.progress "Capturing in ant mode...@." ;
Ant.capture ~prog ~args
| BuckClangFlavor {build_cmd} ->
buck_capture build_cmd
L.progress "Capturing in buck mode...@." ;
BuckFlavors.capture build_cmd
| BuckCompilationDB {deps; prog; args} ->
L.progress "Capturing using Buck's compilation database...@." ;
let json_cdb =

Loading…
Cancel
Save