source/command/inferCommand.ml (171 lines of code) (raw):
(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open Core
open Pyre
(* Infer command uses the same exit code scheme as check command. *)
module ExitStatus = CheckCommand.ExitStatus
module InferConfiguration = struct
type path_list = PyrePath.t list [@@deriving sexp, compare, hash]
let path_list_of_raw raw_paths = List.map raw_paths ~f:PyrePath.create_absolute
type t = {
base: CommandStartup.BaseConfiguration.t;
paths_to_modify: path_list option;
}
[@@deriving sexp, compare, hash]
let of_yojson json =
let open Yojson.Safe.Util in
(* Parsing logic *)
try
match CommandStartup.BaseConfiguration.of_yojson json with
| Result.Error _ as error -> error
| Result.Ok base ->
let paths_to_modify =
json
|> member "paths_to_modify"
|> [%of_yojson: string list option]
|> Result.ok_or_failwith
>>| path_list_of_raw
in
Result.Ok { base; paths_to_modify }
with
| Type_error (message, _)
| Undefined (message, _) ->
Result.Error message
| other_exception -> Result.Error (Exn.to_string other_exception)
let analysis_configuration_of
{
base =
{
CommandStartup.BaseConfiguration.source_paths;
search_paths;
excludes;
checked_directory_allowlist;
checked_directory_blocklist;
extensions;
log_path;
global_root;
local_root;
debug;
enable_type_comments;
python_version = { Configuration.PythonVersion.major; minor; micro };
parallel;
number_of_workers;
shared_memory =
{ Configuration.SharedMemory.heap_size; dependency_table_power; hash_table_power };
remote_logging = _;
profiling_output = _;
memory_profiling_output = _;
};
_;
}
=
Configuration.Analysis.create
~parallel
~analyze_external_sources:false
~filter_directories:checked_directory_allowlist
~ignore_all_errors:checked_directory_blocklist
~number_of_workers
~local_root:(Option.value local_root ~default:global_root)
~project_root:global_root
~search_paths:(List.map search_paths ~f:SearchPath.normalize)
~strict:false
~debug
~show_error_traces:false
~excludes
~extensions
~incremental_style:Configuration.Analysis.Shallow
~log_directory:(PyrePath.absolute log_path)
~python_major_version:major
~python_minor_version:minor
~python_micro_version:micro
~shared_memory_heap_size:heap_size
~shared_memory_dependency_table_power:dependency_table_power
~shared_memory_hash_table_power:hash_table_power
~enable_type_comments
~source_paths:(Configuration.SourcePaths.to_search_paths source_paths)
()
end
let run_infer_local ~configuration ~build_system ~paths_to_modify () =
let result =
Scheduler.with_scheduler ~configuration ~f:(fun scheduler ->
let ({ Service.Infer.global_environment; _ } as environment_data) =
Service.Infer.build_environment_data ~configuration ~scheduler ()
in
let filename_lookup qualifier =
let ast_environment =
Analysis.AnnotatedGlobalEnvironment.ReadOnly.ast_environment global_environment
in
Server.RequestHandler.instantiate_path
~build_system
~configuration
~ast_environment
qualifier
in
Service.Infer.run_infer
~configuration
~scheduler
~filename_lookup
~paths_to_modify
environment_data)
in
if configuration.debug then
Memory.report_statistics ();
Yojson.Safe.pretty_to_string (`List [TypeInference.Data.GlobalResult.to_yojson result])
|> Log.print "%s";
Lwt.return ExitStatus.Ok
let run_infer infer_configuration =
let {
InferConfiguration.base = { CommandStartup.BaseConfiguration.source_paths; _ };
paths_to_modify;
}
=
infer_configuration
in
Server.BuildSystem.with_build_system source_paths ~f:(fun build_system ->
let configuration = InferConfiguration.analysis_configuration_of infer_configuration in
run_infer_local ~configuration ~build_system ~paths_to_modify ())
let run_infer configuration_file =
let exit_status =
match CommandStartup.read_and_parse_json configuration_file ~f:InferConfiguration.of_yojson with
| Result.Error message ->
Log.error "%s" message;
ExitStatus.PyreError
| Result.Ok
({
InferConfiguration.base =
{
CommandStartup.BaseConfiguration.global_root;
local_root;
debug;
remote_logging;
profiling_output;
memory_profiling_output;
_;
};
_;
} as infer_configuration) ->
CommandStartup.setup_global_states
~global_root
~local_root
~debug
~additional_logging_sections:[]
~remote_logging
~profiling_output
~memory_profiling_output
();
Lwt_main.run
(Lwt.catch
(fun () -> run_infer infer_configuration)
(fun exn -> Lwt.return (CheckCommand.on_exception exn)))
in
Statistics.flush ();
exit (ExitStatus.exit_code exit_status)
let command =
let filename_argument = Command.Param.(anon ("filename" %: Filename.arg_type)) in
Command.basic
~summary:"Runs type inference"
(Command.Param.map filename_argument ~f:(fun filename () -> run_infer filename))