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 * Hack for HipHop: type checker's client code.
13 * This code gets called in various different ways:
14 * - from emacs, where the output is asynchronous
15 * - from vim, where vim is blocked until this code exits
16 * - from arc diff, our linter
17 * - from arc land, our commit hook
18 * - from check trunk, our irc bot which checks the state of trunk
19 * - manually, from the command line
21 * Usage: hh_client [OPTION]... [WWW DIRECTORY] [FILE]...
27 let () = Random.self_init
()
30 (* no-op, needed at entry-point for Daemon hookup *)
31 Daemon.check_entry_point
();
33 (* Ignore SIGPIPE since we might get a server hangup and don't care (can
34 * detect and handle better than a signal). Ignore SIGUSR1 since we sometimes
35 * use that for the server to tell us when it's done initializing, but if we
36 * aren't explicitly listening we don't care. *)
37 Sys_utils.set_signal
Sys.sigpipe
Sys.Signal_ignore
;
40 (Sys.Signal_handle
(fun _
-> raise
Exit_status.(Exit_with Interrupted
)));
41 let init_id = Random_id.short_string
() in
42 let command = ClientArgs.parse_args ~
init_id in
45 | ClientCommand.CCheck _
-> "Check"
46 | ClientCommand.CStart _
-> "Start"
47 | ClientCommand.CStop _
-> "Stop"
48 | ClientCommand.CRestart _
-> "Restart"
49 | ClientCommand.CLsp _
-> "Lsp"
50 | ClientCommand.CDebug _
-> "Debug"
51 | ClientCommand.CDownloadSavedState _
-> "DownloadSavedState"
52 | ClientCommand.CRage _
-> "Rage"
56 let root = ClientArgs.root command in
57 HackEventLogger.client_init
59 (Option.value root ~default
:Path.dummy_path
);
60 Hh_logger.Level.set_min_level_file
Hh_logger.Level.Info
;
61 Hh_logger.Level.set_min_level_stderr
Hh_logger.Level.Error
;
62 Hh_logger.set_id
(Printf.sprintf
"%s#%s" command_name init_id);
67 let client_log_fn = ServerFiles.client_log
root in
69 (* For irritating reasons T67177821 we might not have permissions
70 to write to the file. Pending a fix, let's only set up Hh_logger
71 to write to the file if we can indeed safely write to it. *)
73 (Sys_utils.Touch_existing_or_create_new
74 { mkdir_if_new
= false; perm_if_new
= 0o666
})
76 Hh_logger.set_log
client_log_fn
81 (String.concat ~sep
:" " (Array.to_list
Sys.argv
));
86 | ClientCommand.CCheck check_env
->
87 Lwt_main.run
(ClientCheck.main check_env
)
88 | ClientCommand.CStart env
-> Lwt_main.run
(ClientStart.main env
)
89 | ClientCommand.CStop env
-> Lwt_main.run
(ClientStop.main env
)
90 | ClientCommand.CRestart env
-> Lwt_main.run
(ClientRestart.main env
)
91 | ClientCommand.CLsp env
-> Lwt_main.run
(ClientLsp.main env
)
92 | ClientCommand.CDebug env
-> Lwt_main.run
(ClientDebug.main env
)
93 | ClientCommand.CRage env
-> Lwt_main.run
(ClientRage.main env
)
94 | ClientCommand.CDownloadSavedState env
->
95 Lwt_main.run
(ClientDownloadSavedState.main env
)
97 Exit_status.exit
exit_status
99 let e = Exception.wrap exn
in
100 (* We trust that if someone raised Exit_with then they had the decency to print
101 out a user-facing message; we will only print out a user-facing message here
102 for uncaught exceptions: lvl=Error gets sent to stderr, but lvl=Info doesn't. *)
105 | Exit_status.Exit_with es
-> (es
, Hh_logger.Level.Info
)
106 | _
-> (Exit_status.Uncaught_exception
, Hh_logger.Level.Error
)
110 "hh_client bad exit: %s - %s\n%s"
111 (Exit_status.show es
)
112 (Exception.get_ctor_string
e)
113 (Exception.get_backtrace_string
e |> Exception.clean_stack
);
114 HackEventLogger.client_bad_exit ~
command_name es
e;