diff --git a/infer/src/IR/DotCfg.ml b/infer/src/IR/DotCfg.ml index fa7019973..7ef246642 100644 --- a/infer/src/IR/DotCfg.ml +++ b/infer/src/IR/DotCfg.ml @@ -108,7 +108,7 @@ let print_pdesc source fmt pdesc = let with_dot_file fname ~pp = - let chan = Out_channel.create fname in + let chan = Utils.out_channel_create_with_dir fname in let fmt = Format.formatter_of_out_channel chan in (* avoid phabricator thinking this file was generated by substituting substring with %s *) F.fprintf fmt "@[/* %@%s */@\ndigraph cfg {@\n%t}@]@." "generated" pp ; diff --git a/infer/src/base/Utils.ml b/infer/src/base/Utils.ml index 8b8ac076d..25d4ec344 100644 --- a/infer/src/base/Utils.ml +++ b/infer/src/base/Utils.ml @@ -265,13 +265,13 @@ let with_process_lines ~(debug : ('a, F.formatter, unit) format -> 'a) ~cmd ~tmp shell_cmd output -(** Create a directory if it does not exist already. *) +(** Recursively create a directory if it does not exist already. *) let create_dir dir = try if (Unix.stat dir).Unix.st_kind <> Unix.S_DIR then L.(die ExternalError) "file '%s' already exists and is not a directory" dir with Unix.Unix_error _ -> ( - try Unix.mkdir dir ~perm:0o700 + try Unix.mkdir_p dir ~perm:0o700 with Unix.Unix_error _ -> let created_concurrently = (* check if another process created it meanwhile *) @@ -280,6 +280,13 @@ let create_dir dir = if not created_concurrently then L.(die ExternalError) "cannot create directory '%s'" dir ) +let out_channel_create_with_dir fname = + try Out_channel.create fname + with Sys_error _ -> + Unix.mkdir_p ~perm:0o700 (Filename.dirname fname) ; + Out_channel.create fname + + let realpath_cache = Hashtbl.create 1023 let realpath ?(warn_on_error = true) path = diff --git a/infer/src/base/Utils.mli b/infer/src/base/Utils.mli index 05d594846..1109fac9d 100644 --- a/infer/src/base/Utils.mli +++ b/infer/src/base/Utils.mli @@ -94,7 +94,10 @@ val with_process_lines : information, and [tmp_prefix] as a prefix for temporary files. *) val create_dir : string -> unit -(** create a directory if it does not exist already *) +(** recursively create a directory if it does not exist already *) + +val out_channel_create_with_dir : Filename.t -> Out_channel.t +(** create an out channel with creating missing directories *) val realpath : ?warn_on_error:bool -> string -> string (** [realpath warn_on_error path] returns path with all symbolic links resolved. It caches results