2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
11 * Parses and gathers information from the .hhconfig in the repo.
15 open Config_file.Getters
16 open Reordered_argument_collections
19 version
: string option;
21 load_script
: Path.t
option;
22 load_script_timeout
: int; (* in seconds *)
24 (** Script to call to prefetch a saved state. Expected invocation is:
25 * state_prefetcher_script <svn revision number>
27 * Which is expected to put a saved state into the correct place which the
28 * above load_script will be able to use.
30 state_prefetcher_script
: Path.t
option;
32 (* Configures only the workers. Workers can have more relaxed GC configs as
33 * they are short-lived processes *)
34 gc_control
: Gc.control
;
35 sharedmem_config
: SharedMem.config
;
36 tc_options
: TypecheckerOptions.t
;
37 parser_options
: ParserOptions.t
;
38 formatter_override
: Path.t
option;
39 config_hash
: string option;
40 (* A list of regexps for paths to ignore *)
41 ignored_paths
: string list
;
42 (* A list of extra paths to search for declarations *)
43 extra_paths
: Path.t list
;
45 (* what version of the typechecker is targetted *)
46 forward_compatibility_level
: ForwardCompatibilityLevel.t
;
49 let filename = Relative_path.from_root
Config_file.file_path_relative_to_repo_root
51 let is_compatible c1 c2
=
52 (* This comparison can eventually be made more complex; we may not always
53 * need to restart hh_server, e.g. changing the path to the load script
57 let make_gc_control config
=
58 let {Gc.minor_heap_size
; space_overhead
; _
} = GlobalConfig.gc_control
in
60 int_
"gc_minor_heap_size" ~default
:minor_heap_size config
in
62 int_
"gc_space_overhead" ~default
:space_overhead config
in
63 { GlobalConfig.gc_control
with Gc.minor_heap_size; space_overhead; }
65 let make_sharedmem_config config options local_config
=
71 } = GlobalConfig.default_sharedmem_config
in
72 let shm_dirs = local_config
.ServerLocalConfig.shm_dirs in
74 let global_size = int_
"sharedmem_global_size" ~default
:global_size config
in
75 let heap_size = int_
"sharedmem_heap_size" ~default
:heap_size config
in
76 let dep_table_pow = int_
"sharedmem_dep_table_pow" ~default
:17 config
in
77 let hash_table_pow = int_
"sharedmem_hash_table_pow" ~default
:18 config
in
78 let log_level = int_
"sharedmem_log_level" ~default
:0 config
in
79 let shm_dirs = string_list
80 ~delim
:(Str.regexp
",")
85 int_
"sharedmem_minimum_available" ~default
:shm_min_avail config
in
87 let global_size, heap_size, dep_table_pow, hash_table_pow =
88 match ServerArgs.ai_mode options
with
89 | None
-> global_size, heap_size, dep_table_pow, hash_table_pow
91 Ai.modify_shared_mem_sizes
108 let config_list_regexp = (Str.regexp
"[, \t]+")
110 let config_user_attributes config
=
111 match SMap.get config
"user_attributes" with
114 let custom_attrs = Str.split
config_list_regexp s
in
115 Some
(List.fold_left
custom_attrs ~f
:SSet.add ~init
:SSet.empty
)
117 let process_experimental sl
=
118 match List.map sl
String.lowercase_ascii
with
119 | ["false"] -> SSet.empty
120 | ["true"] -> TypecheckerOptions.experimental_all
121 | features
-> List.fold_left features ~f
:SSet.add ~init
:SSet.empty
123 let config_experimental_tc_features config
=
124 match SMap.get config
"enable_experimental_tc_features" with
127 let sl = Str.split
config_list_regexp s
in
128 process_experimental sl
130 let process_migration_flags sl =
132 | ["false"] -> SSet.empty
133 | ["true"] -> TypecheckerOptions.migration_flags_all
136 List.iter flags ~f
:(fun s
->
137 if not
(SSet.mem
TypecheckerOptions.migration_flags_all s
)
138 then failwith
("invalid migration flag: " ^ s
));
139 List.fold_left flags ~f
:SSet.add ~init
:SSet.empty
142 let config_tc_migration_flags config
=
143 SMap.get config
"enable_tc_migration_flags"
144 |> Option.value_map ~f
:(Str.split
config_list_regexp) ~default
:[]
145 |> List.map ~f
:String.lowercase_ascii
146 |> process_migration_flags
149 let convert_ignored_paths str
=
150 let json = Hh_json.json_of_string ~strict
:true str
in
151 let l = Hh_json.get_array_exn
json in
152 List.filter_map ~f
:(fun s
->
154 | Hh_json.JSON_String path
-> Some path
159 let process_ignored_paths config
=
160 SMap.get config
"ignored_paths"
161 |> Option.value_map ~f
:convert_ignored_paths ~default
:[]
163 let process_forward_compatibility_level config
=
164 SMap.get config
"forward_compatibility_level"
165 |> Option.value_map ~f
:ForwardCompatibilityLevel.from_string ~default
:ForwardCompatibilityLevel.HEAD
167 let maybe_relative_path fn
=
168 (* Note: this is not the same as calling realpath; the cwd is not
169 * necessarily the same as hh_server's root!!! *)
171 if Filename.is_relative fn
172 then Relative_path.(to_absolute
(from_root fn
))
176 let process_extra_paths config
=
177 match SMap.get config
"extra_paths" with
178 | Some s
-> Str.split
config_list_regexp s
|> List.map ~f
:maybe_relative_path
181 let extract_auto_namespace_element ns_map element
=
183 | (source
, Hh_json.JSON_String target
) ->
184 (source
, target
)::ns_map
185 | _
-> ns_map
(* This means the JSON we received is incorrect *)
187 let convert_auto_namespace_to_map map
=
188 let json = Hh_json.json_of_string ~strict
:true map
in
189 let pairs = Hh_json.get_object_exn
json in
190 (* We do a fold instead of a map to filter
191 * out the incorrect entrie as we look at each item *)
192 List.fold_left ~init
:[] ~f
:extract_auto_namespace_element pairs
194 let prepare_auto_namespace_map config
=
196 (SMap.get config
"auto_namespace_map")
198 ~f
:convert_auto_namespace_to_map
200 let prepare_ignored_fixme_codes config
=
201 SMap.get config
"ignored_fixme_codes"
202 |> Option.value_map ~f
:(Str.split
config_list_regexp) ~default
:[]
203 |> List.map ~f
:int_of_string
204 |> List.fold_right ~init
:Errors.default_ignored_fixme_codes ~f
:ISet.add
206 let load config_filename options
=
207 let config_hash, config
= Config_file.parse
(Relative_path.to_absolute config_filename
) in
208 let local_config = ServerLocalConfig.load ~silent
:false in
209 let version = SMap.get config
"version" in
210 let ignored_paths = process_ignored_paths config
in
211 let extra_paths = process_extra_paths config
in
213 Option.map
(SMap.get config
"load_script") maybe_relative_path in
214 (* Since we use the unix alarm() for our timeouts, a timeout value of 0 means
215 * to wait indefinitely *)
216 let load_script_timeout = int_
"load_script_timeout" ~default
:0 config
in
217 let state_prefetcher_script =
218 Option.map
(SMap.get config
"state_prefetcher_script") maybe_relative_path in
219 let formatter_override =
220 Option.map
(SMap.get config
"formatter_override") maybe_relative_path in
221 let forward_compat_level = process_forward_compatibility_level config
in
222 let global_opts = GlobalOptions.make
223 (bool_
"assume_php" ~default
:true config
)
224 (bool_
"safe_array" ~default
:true config
)
225 (bool_
"safe_vector_array" ~default
:true config
)
226 (bool_
"deregister_php_stdlib" ~default
:false config
)
227 (* Although it's locally configured, the use_full_fidelity_parser flag needs
228 * to end up in the parser options to reach all consumers of it.
230 local_config.ServerLocalConfig.use_full_fidelity_parser
231 (config_user_attributes config
)
232 (config_experimental_tc_features config
)
233 (config_tc_migration_flags config
)
234 false (* typechecker dynamic_view option to set Tany as Tdynamic, off by default *)
235 (bool_
"disallow_unsafe_comparisons" ~default
:false config
)
236 (bool_
"disallow_non_arraykey_keys" ~default
:false config
)
237 (bool_
"disallow_array_as_tuple" ~default
:false config
)
238 (prepare_auto_namespace_map config
)
239 (bool_
"disallow_ambiguous_lambda" ~default
:false config
)
240 (bool_
"disallow_array_typehint" ~default
:false config
)
241 (bool_
"disallow_array_literal" ~default
:false config
)
242 (bool_
"disallow_return_by_ref" ~default
:false config
)
243 (bool_
"language_feature_logging" ~default
:false config
)
244 (bool_
"unsafe_rx" ~default
:true config
)
245 (bool_
"disallow_elvis_space" ~default
:false config
)
246 (prepare_ignored_fixme_codes config
)
249 Errors.ignored_fixme_codes
:=
250 (GlobalOptions.ignored_fixme_codes
global_opts);
253 load_script = load_script;
254 load_script_timeout = load_script_timeout;
255 state_prefetcher_script = state_prefetcher_script;
256 gc_control
= make_gc_control config
;
257 sharedmem_config
= make_sharedmem_config config options
local_config;
258 tc_options
= global_opts;
259 parser_options
= global_opts;
260 formatter_override = formatter_override;
261 config_hash = config_hash;
262 ignored_paths = ignored_paths;
263 extra_paths = extra_paths;
264 forward_compatibility_level
= forward_compat_level;
267 (* useful in testing code *)
268 let default_config = {
271 load_script_timeout = 0;
272 state_prefetcher_script = None
;
273 gc_control
= GlobalConfig.gc_control
;
274 sharedmem_config
= GlobalConfig.default_sharedmem_config
;
275 tc_options
= TypecheckerOptions.default
;
276 parser_options
= ParserOptions.default
;
277 formatter_override = None
;
281 forward_compatibility_level
= ForwardCompatibilityLevel.HEAD
;
284 let set_parser_options config popt
= { config
with parser_options
= popt
}
285 let set_tc_options config tcopt
= { config
with tc_options
= tcopt
}
286 let gc_control config
= config
.gc_control
287 let sharedmem_config config
= config
.sharedmem_config
288 let state_prefetcher_script config
= config
.state_prefetcher_script
289 let typechecker_options config
= config
.tc_options
290 let parser_options config
= config
.parser_options
291 let formatter_override config
= config
.formatter_override
292 let config_hash config
= config
.config_hash
293 let ignored_paths config
= config
.ignored_paths
294 let extra_paths config
= config
.extra_paths
295 let version config
= config
.version
296 let forward_compatibility_level config
= config
.forward_compatibility_level