diff --git a/infer/src/backend/CommandLineOption.ml b/infer/src/backend/CommandLineOption.ml index a44bffae8..f01402181 100644 --- a/infer/src/backend/CommandLineOption.ml +++ b/infer/src/backend/CommandLineOption.ml @@ -308,7 +308,7 @@ let prefix_before_rest args = prefix_before_rest_ [] args -let parse env_var exe_usage = +let parse ?(incomplete=false) env_var exe_usage = let curr_speclist = ref [] and full_speclist = ref [] in @@ -368,11 +368,17 @@ let parse env_var exe_usage = let env_args = c_args @ env_args in (* end transitional support for INFERCLANG_ARGS *) let exe_name, env_cl_args = prepend_to_argv env_args in - Unix.putenv env_var (encode_argv_to_env (prefix_before_rest env_cl_args)) ; - (try - Arg.parse_argv (Array.of_list (exe_name :: env_cl_args)) !curr_speclist !anon_fun usage_msg - with - | Arg.Bad usage_msg -> Pervasives.prerr_string usage_msg; exit 2 - | Arg.Help usage_msg -> Pervasives.print_string usage_msg; exit 0 - ); + let current = ref 0 in + let rec parse_loop () = + try + Arg.parse_argv_dynamic ~current (Array.of_list (exe_name :: env_cl_args)) + curr_speclist !anon_fun usage_msg + with + | Arg.Bad _ when incomplete -> parse_loop () + | Arg.Bad usage_msg -> Pervasives.prerr_string usage_msg; exit 2 + | Arg.Help usage_msg -> Pervasives.print_string usage_msg; exit 0 + in + parse_loop () ; + if not incomplete then + Unix.putenv env_var (encode_argv_to_env (prefix_before_rest env_cl_args)) ; curr_usage diff --git a/infer/src/backend/CommandLineOption.mli b/infer/src/backend/CommandLineOption.mli index 10dfcc0b8..7ec992200 100644 --- a/infer/src/backend/CommandLineOption.mli +++ b/infer/src/backend/CommandLineOption.mli @@ -93,4 +93,4 @@ val mk_anon : Therefore arguments passed on the command line supercede those specified in the environment variable. WARNING: If an argument appears both in the environment variable and on the command line, it will be interpreted twice. *) -val parse : string -> (exe -> Arg.usage_msg) -> (int -> 'a) +val parse : ?incomplete:bool -> string -> (exe -> Arg.usage_msg) -> (int -> 'a) diff --git a/infer/src/backend/config.ml b/infer/src/backend/config.ml index 5668f46ed..ea696c672 100644 --- a/infer/src/backend/config.ml +++ b/infer/src/backend/config.ml @@ -191,6 +191,34 @@ let os_type = match Sys.os_type with (** Command Line options *) +(* Declare the phase 1 options *) + +let inferconfig_home = + CLOpt.mk_string_opt ~deprecated:["inferconfig_home"] ~long:"inferconfig-home" + ~exes:CLOpt.[A] ~meta:"dir" "Path to the .inferconfig file" + +and project_root = + CLOpt.mk_string_opt ~deprecated:["project_root"] ~long:"project-root" ~short:"pr" + ?default:(if CLOpt.(current_exe = P) then Some (Sys.getcwd ()) else None) + ~f:filename_to_absolute + ~exes:CLOpt.[A;C;J;L;P] ~meta:"dir" "Specify the root directory of the project" + +(* Parse the phase 1 options, ignoring the rest *) + +let _ = CLOpt.parse ~incomplete:true "INFER_ARGS" (fun _ -> "") + +(* Define the values that depend on phase 1 options *) + +let inferconfig_home = !inferconfig_home +and project_root = !project_root + +let inferconfig_path = + match inferconfig_home, project_root with + | Some dir, _ | _, Some dir -> Filename.concat dir inferconfig_file + | None, None -> inferconfig_file + +(* Proceed to declare and parse the remaining options *) + (** The references representing the command line options are defined in a single simultaneous let...and...and... binding in order to allow the type-checker to catch uses of one reference in code for another. This avoids being sensitive to @@ -391,10 +419,6 @@ and infer_cache = ~f:filename_to_absolute ~meta:"dir" "Select a directory to contain the infer cache" -and inferconfig_home = - CLOpt.mk_string_opt ~deprecated:["inferconfig_home"] ~long:"inferconfig-home" - ~exes:CLOpt.[A] ~meta:"dir" "Path to the .inferconfig file" - (** Set the timeout values in seconds and symops, computed as a multiple of the integer parameter *) and iterations = @@ -529,12 +553,6 @@ and progress_bar = CLOpt.mk_bool ~deprecated_no:["no_progress_bar"] ~long:"progress-bar" ~short:"pb" ~default:true "Show a progress bar" -and project_root = - CLOpt.mk_string_opt ~deprecated:["project_root"] ~long:"project-root" ~short:"pr" - ?default:(if CLOpt.(current_exe = P) then Some (Sys.getcwd ()) else None) - ~f:filename_to_absolute - ~exes:CLOpt.[A;C;J;L;P] ~meta:"dir" "Specify the root directory of the project" - (** command line flag: if true, do not print the spec to standard output *) and quiet = CLOpt.mk_bool ~long:"quiet" ~short:"q" @@ -994,7 +1012,6 @@ and print_types = !print_types and print_using_diff = !print_using_diff and procs_csv = !procs_csv and procs_xml = !procs_xml -and project_root = !project_root and quiet = !quiet and reactive_mode = !reactive and report = !report @@ -1029,10 +1046,6 @@ and xml_specs = !xml_specs and zip_libraries = !zip_libraries let inferconfig_json = - let inferconfig_path = - match !inferconfig_home, project_root with - | Some dir, _ | _, Some dir -> Filename.concat dir inferconfig_file - | None, None -> inferconfig_file in lazy ( match read_optional_json_file inferconfig_path with | Ok json -> json