diff --git a/infer/src/backend/InferAnalyze.ml b/infer/src/backend/InferAnalyze.ml index 4f6830a96..eed1961fe 100644 --- a/infer/src/backend/InferAnalyze.ml +++ b/infer/src/backend/InferAnalyze.ml @@ -182,7 +182,7 @@ let invalidate_changed_procedures changed_files = ScubaLogging.log_count ~label:"incremental_analysis.invalidated_nodes" ~value:invalidated_nodes ; (* save some memory *) CallGraph.reset reverse_callgraph ; - ResultsDir.delete_capture_and_results_data () ) + ResultsDir.scrub_for_incremental () ) let main ~changed_files = diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index b1d329c89..3c1e48db6 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -228,8 +228,6 @@ let starvation_issues_dir_name = "starvation_issues" let test_determinator_results = "test_determinator_results" -let temp_dir_name = "tmp" - (** Enable detailed tracing information during array abstraction *) let trace_absarray = false @@ -3104,8 +3102,6 @@ let is_checker_enabled c = let captured_dir = results_dir ^/ captured_dir_name -let temp_dir = results_dir ^/ temp_dir_name - let clang_frontend_action_string = let text = if capture then ["translating"] else [] in let text = if is_checker_enabled Linters then "linting" :: text else text in diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 19447587e..7276f0cdc 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -165,8 +165,6 @@ val specs_files_suffix : string val starvation_issues_dir_name : string -val temp_dir_name : string - val test_determinator_results : string val trace_absarray : bool @@ -661,9 +659,6 @@ val captured_dir : string val procnames_locks_dir : string -val temp_dir : string -(** directory inside {!results_dir} to put temporary files *) - val toplevel_results_dir : string (** In some integrations, eg Buck, infer subprocesses started by the build system (started by the toplevel infer process) will have their own results directory; this points to the results diff --git a/infer/src/base/ResultsDir.ml b/infer/src/base/ResultsDir.ml index e555b0a63..8fb151ada 100644 --- a/infer/src/base/ResultsDir.ml +++ b/infer/src/base/ResultsDir.ml @@ -8,6 +8,8 @@ open! IStd open PolyVariantEqual module L = Logging +let get_path entry = ResultsDirEntryName.get_path ~results_dir:Config.results_dir entry + module RunState = struct let run_time_string = Time.now () |> Time.to_string @@ -135,7 +137,7 @@ let create_results_dir () = L.die UserError "ERROR: %s@\nPlease remove '%s' and try again" error Config.results_dir ) ; Unix.mkdir_p Config.results_dir ; - Unix.mkdir_p Config.temp_dir ; + Unix.mkdir_p (get_path Temporary) ; List.iter ~f:Unix.mkdir_p results_dir_dir_markers ; prepare_logging_and_db () ; () @@ -152,7 +154,7 @@ let assert_results_dir advice = () -let delete_capture_and_results_data () = +let scrub_for_incremental () = DBWriter.reset_capture_tables () ; let dirs_to_delete = List.map @@ -160,6 +162,9 @@ let delete_capture_and_results_data () = (Config.[classnames_dir_name] @ FileLevelAnalysisIssueDirs.get_registered_dir_names ()) in List.iter ~f:Utils.rmtree dirs_to_delete ; + List.iter ~f:Utils.rmtree + (ResultsDirEntryName.to_delete_before_incremental_capture_and_analysis + ~results_dir:Config.results_dir) ; () @@ -173,10 +178,7 @@ let scrub_for_caching () = let should_delete_dir = let dirs_to_delete = Config. - [ captured_dir_name (* debug only *) - ; classnames_dir_name (* a cache for the Java frontend *) - ; temp_dir_name - (* debug only *) ] + [captured_dir_name (* debug only *); classnames_dir_name (* a cache for the Java frontend *)] @ (* temporarily needed to build report.json, safe to delete *) FileLevelAnalysisIssueDirs.get_registered_dir_names () in @@ -227,4 +229,6 @@ let scrub_for_caching () = | exception Unix.Unix_error (Unix.ENOENT, _, _) -> () in - delete_temp_results Config.results_dir + delete_temp_results Config.results_dir ; + List.iter ~f:Utils.rmtree + (ResultsDirEntryName.to_delete_before_caching_capture ~results_dir:Config.results_dir) diff --git a/infer/src/base/ResultsDir.mli b/infer/src/base/ResultsDir.mli index 4b9236c17..fb449a571 100644 --- a/infer/src/base/ResultsDir.mli +++ b/infer/src/base/ResultsDir.mli @@ -18,6 +18,11 @@ module RunState : sig (** fetch the value of the 'merge after capture' smart option *) end +val get_path : ResultsDirEntryName.id -> string +(** Wrapper around {!ResultsDirEntryName.get_path} that implicitly applies to the current results + directory {!Config.results_dir}. If you need to specify another results directory use + {!ResultsDirEntryName} directly. *) + val assert_results_dir : string -> unit (** Check that the results dir exists and sets up logging, the database, etc. *) @@ -27,8 +32,8 @@ val remove_results_dir : unit -> unit val create_results_dir : unit -> unit (** Create the results dir and sets up logging, the database, etc. *) -val delete_capture_and_results_data : unit -> unit -(** delete capture and results data in the results directory *) +val scrub_for_incremental : unit -> unit +(** scrub capture data in preparation of an incremental capture + analysis *) val scrub_for_caching : unit -> unit (** Clean up the results dir to keep only what's relevant to go in a cache (e.g., the distributed diff --git a/infer/src/base/ResultsDirEntryName.ml b/infer/src/base/ResultsDirEntryName.ml new file mode 100644 index 000000000..589f9e410 --- /dev/null +++ b/infer/src/base/ResultsDirEntryName.ml @@ -0,0 +1,49 @@ +(* + * 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 id = Temporary [@@deriving enumerate] + +type cleanup_action = Delete | Keep [@@deriving equal] + +type entry_kind = Directory + +type t = + { rel_path: string (** path inside infer-out/ *) + ; kind: entry_kind + ; before_incremental_analysis: cleanup_action + (** whether this should be deleted before an incremental analysis *) + ; before_caching_capture: cleanup_action + (** whether this should be deleted before sending to a remote cache for the capture phase, + e.g., a distributed Buck cache. *) } + +let of_id = function + | Temporary -> + { rel_path= "tmp" + ; kind= Directory + ; before_incremental_analysis= Keep + ; before_caching_capture= Delete } + + +let path_of_entry ~results_dir {rel_path; _} = results_dir ^/ rel_path + +let get_path ~results_dir id = path_of_entry ~results_dir (of_id id) + +let get_filtered_paths ~results_dir ~f = + List.filter_map all_of_id ~f:(fun id -> + let entry = of_id id in + if f entry then Some (path_of_entry ~results_dir entry) else None ) + + +let to_delete_before_incremental_capture_and_analysis ~results_dir = + get_filtered_paths ~results_dir ~f:(fun {before_incremental_analysis; _} -> + equal_cleanup_action before_incremental_analysis Delete ) + + +let to_delete_before_caching_capture ~results_dir = + get_filtered_paths ~results_dir ~f:(fun {before_caching_capture; _} -> + equal_cleanup_action before_caching_capture Delete ) diff --git a/infer/src/base/ResultsDirEntryName.mli b/infer/src/base/ResultsDirEntryName.mli new file mode 100644 index 000000000..004cab723 --- /dev/null +++ b/infer/src/base/ResultsDirEntryName.mli @@ -0,0 +1,21 @@ +(* + * 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 + +(** Entries in the results directory (infer-out/). Unless you want to specify a custom results + directory you probably want to use {!ResultsDir.Entry} instead of this module. *) + +type id = Temporary (** directory containing temp files *) + +val get_path : results_dir:string -> id -> string +(** the absolute path for the given entry *) + +val to_delete_before_incremental_capture_and_analysis : results_dir:string -> string list +(** utility for {!ResultsDir.scrub_for_incremental}, you probably want to use that instead *) + +val to_delete_before_caching_capture : results_dir:string -> string list +(** utility for {!ResultsDir.scrub_for_caching}, you probably want to use that instead *) diff --git a/infer/src/integration/Buck.ml b/infer/src/integration/Buck.ml index e5112e367..bbeb99d91 100644 --- a/infer/src/integration/Buck.ml +++ b/infer/src/integration/Buck.ml @@ -325,7 +325,7 @@ let rec exceed_length ~max = function let store_args_in_file args = if exceed_length ~max:max_command_line_length args then ( - let file = Filename.temp_file ~in_dir:Config.temp_dir "buck_targets" ".txt" in + let file = Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "buck_targets" ".txt" in let write_args outc = Out_channel.output_string outc (String.concat ~sep:"\n" args) in let () = Utils.with_file_out file ~f:write_args in L.(debug Capture Quiet) "Buck targets options stored in file '%s'@\n" file ; @@ -381,7 +381,9 @@ let capture_buck_args = 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 buck_output_file = Filename.temp_file ~in_dir:Config.temp_dir "buck_output" ".log" in + let buck_output_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "buck_output" ".log" + in 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) diff --git a/infer/src/integration/BuckGenrule.ml b/infer/src/integration/BuckGenrule.ml index 51943414d..2fa1958dc 100644 --- a/infer/src/integration/BuckGenrule.ml +++ b/infer/src/integration/BuckGenrule.ml @@ -133,7 +133,9 @@ let capture build_cmd = L.progress "Found %d genrule capture targets in %a.@." (List.length targets) Mtime.Span.pp (Mtime_clock.count time0) ; let all_args = List.rev_append args targets in - let build_report_file = Filename.temp_file ~in_dir:Config.temp_dir "buck_build_report" ".json" in + let build_report_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "buck_build_report" ".json" + in let updated_buck_cmd = (* make buck tell us where in buck-out are the capture directories for merging *) (prog :: command :: "--build-report" :: build_report_file :: Buck.buck_config JavaGenruleMaster) diff --git a/infer/src/integration/CaptureCompilationDatabase.ml b/infer/src/integration/CaptureCompilationDatabase.ml index 2dfca678f..af15236a5 100644 --- a/infer/src/integration/CaptureCompilationDatabase.ml +++ b/infer/src/integration/CaptureCompilationDatabase.ml @@ -125,7 +125,7 @@ let get_compilation_database_files_buck db_deps ~prog ~args = (** Compute the compilation database files. *) let get_compilation_database_files_xcodebuild ~prog ~args = - let tmp_file = Filename.temp_file ~in_dir:Config.temp_dir "cdb" ".json" in + let tmp_file = Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "cdb" ".json" in let xcodebuild_prog, xcodebuild_args = (prog, prog :: args) in let xcpretty_prog = "xcpretty" in let xcpretty_args = diff --git a/infer/src/integration/ClangQuotes.ml b/infer/src/integration/ClangQuotes.ml index 4c0c39c0e..8bd96d187 100644 --- a/infer/src/integration/ClangQuotes.ml +++ b/infer/src/integration/ClangQuotes.ml @@ -28,7 +28,7 @@ let quote style = let mk_arg_file prefix style args = - let file = Filename.temp_file prefix ~in_dir:Config.temp_dir ".txt" in + let file = Filename.temp_file prefix ~in_dir:(ResultsDir.get_path Temporary) ".txt" in let write_args outc = List.iter ~f:(fun arg -> diff --git a/infer/src/integration/Gradle.ml b/infer/src/integration/Gradle.ml index 5a1744f3e..814097bc6 100644 --- a/infer/src/integration/Gradle.ml +++ b/infer/src/integration/Gradle.ml @@ -59,7 +59,7 @@ let capture ~prog ~args = else let javac_data = parse_gradle_line ~line:content in let tmpfile, oc = - Core.Filename.open_temp_file ~in_dir:Config.temp_dir "gradle_files" "" + Core.Filename.open_temp_file ~in_dir:(ResultsDir.get_path Temporary) "gradle_files" "" in List.iter javac_data.files ~f:(fun file -> Out_channel.output_string oc (normalize file ^ "\n") ) ; @@ -69,7 +69,9 @@ let capture ~prog ~args = | None -> seen in - let gradle_output_file = Filename.temp_file ~in_dir:Config.temp_dir "gradle_output" ".log" in + let gradle_output_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "gradle_output" ".log" + in let shell_cmd = List.map ~f:Escape.escape_shell (prog :: "--debug" :: args) |> String.concat ~sep:" " diff --git a/infer/src/integration/Javac.ml b/infer/src/integration/Javac.ml index bc1342adc..edddfb0c5 100644 --- a/infer/src/integration/Javac.ml +++ b/infer/src/integration/Javac.ml @@ -30,7 +30,7 @@ let compile compiler build_prog build_args = in (* Pass non-special args via a file to avoid exceeding the command line size limit. *) let args_file = - let file = Filename.temp_file ~in_dir:Config.temp_dir "javac_args" "" in + let file = Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "javac_args" "" in let quoted_file_args = List.map file_args ~f:(fun arg -> if String.contains arg '\'' then arg else F.sprintf "'%s'" arg ) @@ -41,7 +41,9 @@ let compile compiler build_prog build_args = let cli_file_args = cli_args @ ["@" ^ args_file] in let args = prog_args @ cli_file_args in L.(debug Capture Quiet) "Current working directory: '%s'@." (Sys.getcwd ()) ; - let verbose_out_file = Filename.temp_file ~in_dir:Config.temp_dir "javac" ".out" in + let verbose_out_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "javac" ".out" + in let try_run cmd error_k = let shell_cmd = List.map ~f:Escape.escape_shell cmd |> String.concat ~sep:" " in let shell_cmd_redirected = Printf.sprintf "%s 2>'%s'" shell_cmd verbose_out_file in