source/command/commandStartup.ml (175 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 (* These configurations are essential in setting up global states and triggering full type checking. *) module BaseConfiguration = struct type t = { (* Source file discovery *) source_paths: Configuration.SourcePaths.t; search_paths: SearchPath.t list; excludes: string list; checked_directory_allowlist: PyrePath.t list; checked_directory_blocklist: PyrePath.t list; extensions: Configuration.Extension.t list; (* Auxiliary paths *) log_path: PyrePath.t; global_root: PyrePath.t; local_root: PyrePath.t option; (* Type checking controls *) debug: bool; enable_type_comments: bool; python_version: Configuration.PythonVersion.t; (* Parallelism controls *) parallel: bool; number_of_workers: int; (* Memory controls *) shared_memory: Configuration.SharedMemory.t; (* Logging controls *) remote_logging: Configuration.RemoteLogging.t option; profiling_output: string option; memory_profiling_output: string option; } [@@deriving sexp, compare, hash] let of_yojson json = let open Yojson.Safe.Util in let open JsonParsing in (* Parsing logic *) try let source_paths = json |> member "source_paths" |> Configuration.SourcePaths.of_yojson |> Result.ok_or_failwith in let search_paths = json |> list_member "search_paths" ~f:(fun element -> to_string element |> SearchPath.create) ~default:[] in let excludes = json |> string_list_member "excludes" ~default:[] in let checked_directory_allowlist = json |> path_list_member "checked_directory_allowlist" ~default:[] in let checked_directory_blocklist = json |> path_list_member "checked_directory_blocklist" ~default:[] in let extensions = json |> string_list_member "extensions" ~default:[] |> List.map ~f:Configuration.Extension.create_extension in let log_path = json |> path_member "log_path" in let global_root = json |> path_member "global_root" in let local_root = json |> optional_path_member "local_root" in let debug = json |> bool_member "debug" ~default:false in let enable_type_comments = json |> bool_member "enable_type_comments" ~default:true in let python_version = json |> member "python_version" |> function | `Null -> Configuration.PythonVersion.default | _ as json -> Configuration.PythonVersion.of_yojson json |> Result.ok_or_failwith in let parallel = json |> bool_member "parallel" ~default:false in let number_of_workers = json |> int_member "number_of_workers" ~default:1 in let shared_memory = json |> member "shared_memory" |> function | `Null -> Configuration.SharedMemory.default | _ as json -> Configuration.SharedMemory.of_yojson json |> Result.ok_or_failwith in let remote_logging = json |> member "remote_logging" |> function | `Null -> None | _ as json -> Configuration.RemoteLogging.of_yojson json |> Result.ok_or_failwith |> Option.some in let profiling_output = json |> optional_string_member "profiling_output" in let memory_profiling_output = json |> optional_string_member "memory_profiling_output" in Result.Ok { source_paths; search_paths; excludes; checked_directory_allowlist; checked_directory_blocklist; extensions; log_path; global_root; local_root; debug; enable_type_comments; python_version; parallel; number_of_workers; shared_memory; remote_logging; profiling_output; memory_profiling_output; } with | Type_error (message, _) | Undefined (message, _) -> Result.Error message | other_exception -> Result.Error (Exn.to_string other_exception) end (* Read a JSON file from the given path. Return [Result.Ok json] if both file read and JSON parsing succeeds, and [Result.Error error_message] otherwise. *) let read_json file_path = try Result.Ok (Yojson.Safe.from_file file_path) with | Yojson.Json_error message | Sys_error message -> Result.Error message | other_exception -> Result.Error (Exn.to_string other_exception) (* [read_and_parse_json ~f file_path] reads a JSON out of [file_path] using {! read_json}, and invoke [f] on the result JSON. *) let read_and_parse_json ~f file_path = match read_json file_path with | Result.Error message -> let message = Format.sprintf "Cannot read JSON file. %s" message in Result.Error message | Result.Ok json -> ( match f json with | Result.Error message -> let message = Format.sprintf "Malformed server specification JSON. %s" message in Result.Error message | Result.Ok _ as result -> result) (* A convenient wrapper to set up all relevant global states for a Pyre command. *) let setup_global_states ~global_root ~local_root ~debug ~additional_logging_sections ~remote_logging ~profiling_output ~memory_profiling_output () = Log.GlobalState.initialize ~debug ~sections:additional_logging_sections; let logger, log_identifier = match remote_logging with | None -> None, "" | Some { Configuration.RemoteLogging.logger; identifier } -> Some logger, identifier in let relative_local_root = match local_root with | None -> "" | Some local_root -> PyrePath.get_relative_to_root ~root:global_root ~path:local_root |> Option.value ~default:"" in Statistics.GlobalState.initialize ~log_identifier ?logger ~project_root:(PyrePath.absolute global_root) ~project_name:relative_local_root (); Profiling.GlobalState.initialize ?profiling_output ?memory_profiling_output ()