You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
3.3 KiB

(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
type target = {name: string; flavors: string list}
let target_of_string target =
match String.split target ~on:'#' with
| [name; flavors_string]
-> let flavors = String.split flavors_string ~on:',' in
{name; flavors}
| [name]
-> {name; flavors= []}
| _
-> failwithf "cannot parse target %s" target
let string_of_target {name; flavors} =
let pp_string fmt s = Format.fprintf fmt "%s" s in
Format.asprintf "%s#%a" name (Pp.comma_seq pp_string) flavors
let is_target_string =
let target_regexp = Str.regexp "[^/]*//[^/]+.*:.*" in
fun s -> Str.string_match target_regexp s 0
let no_targets_found_error_and_exit buck_cmd =
Process.print_error_and_exit
"No targets found in Buck command %s.@\nOnly fully qualified Buck targets are supported. In particular, aliases are not allowed.@."
(String.concat ~sep:" " buck_cmd)
let add_flavor_to_target target =
let add flavor =
if List.mem ~equal:String.equal target.flavors flavor then
(* there's already an infer flavor associated to the target, do nothing *)
target
else {target with flavors= flavor :: target.flavors}
in
match (Config.buck_compilation_database, Config.analyzer) with
| Some _, _
-> add "compilation-database"
| None, CompileOnly
-> target
| None, (BiAbduction | CaptureOnly | Checkers | Linters)
-> add "infer-capture-all"
| None, Crashcontext
-> failwithf "Analyzer %s is Java-only; not supported with Buck flavors"
(Config.string_of_analyzer Config.analyzer)
let add_flavors_to_buck_command build_cmd =
let add_infer_if_target s (cmd, found_one_target) =
if not (is_target_string s) then (s :: cmd, found_one_target)
else (string_of_target (add_flavor_to_target (target_of_string s)) :: cmd, true)
in
let cmd', found_one_target =
List.fold_right build_cmd ~f:add_infer_if_target ~init:([], false)
in
if not found_one_target then no_targets_found_error_and_exit build_cmd ;
cmd'
let call_buck_query_for_dependencies targets =
let build_deps_string targets =
List.map targets ~f:(fun target -> Printf.sprintf "deps('%s')" target)
|> String.concat ~sep:" union "
in
let buck_query =
[ "buck"
; "query"
; ( "\"kind('(apple_binary|apple_library|apple_test|cxx_binary|cxx_library|cxx_test)', "
^ build_deps_string targets ^ ")\"" ) ]
in
let buck_query_cmd = String.concat buck_query ~sep:" " in
let output, exit_or_signal = Utils.with_process_in buck_query_cmd In_channel.input_lines in
match exit_or_signal with
| Error _ as status
-> Logging.(die ExternalError)
"*** command failed:@\n*** %s@\n*** %s@." buck_query_cmd
(Unix.Exit_or_signal.to_string_hum status)
| Ok ()
-> List.map ~f:(fun name -> string_of_target {name; flavors= Config.append_buck_flavors}) output
let get_dependency_targets args =
let targets, no_targets = List.partition_tf ~f:is_target_string args in
let targets = call_buck_query_for_dependencies targets in
(targets, no_targets)