hgcommands: integrate with commandserver server

Summary:
Make `start-commandserver` actually starts a server, similar to chgserver.
Unlike chgserver, this server is implemented in Rust and only serves one
client (for now).

Reviewed By: zzl0

Differential Revision: D47071254

fbshipit-source-id: 259ef08f2f72f4c22311e0b3bc9dbbee43fd5298
This commit is contained in:
Jun Wu 2023-07-03 22:36:01 -07:00 committed by Facebook GitHub Bot
parent 1c28a3c13f
commit ad3baf259b
3 changed files with 58 additions and 3 deletions

View File

@ -17,6 +17,7 @@ clidispatch = { version = "0.1.0", path = "../clidispatch" }
cliparser = { version = "0.1.0", path = "../cliparser", features = ["python"] }
clone = { version = "0.1.0", path = "../clone" }
comfy-table = "6.1.4"
commandserver = { version = "0.1.0", path = "../commandserver" }
configloader = { version = "0.1.0", path = "../config/loader" }
configmodel = { version = "0.1.0", path = "../config/model" }
cpython = { version = "0.7.1", default-features = false }

View File

@ -229,6 +229,17 @@ impl HgPython {
1
}
}
/// Pre-import Python modules.
/// Returns after importing the modules.
pub fn pre_import_modules(&self) -> Result<(), cpython_ext::PyErr> {
// cpython_ext::PyErr can render traceback when RUST_BACKTRACE=1.
let gil = Python::acquire_gil();
let py = gil.python();
let dispatch = py.import("edenscm.dispatch")?;
dispatch.call(py, "_preimportmodules", NoArgs, None)?;
Ok(())
}
}
impl Drop for HgPython {

View File

@ -15,6 +15,7 @@ use std::ops::DerefMut;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc;
use std::sync::Weak;
@ -59,10 +60,17 @@ use crate::HgPython;
pub fn run_command(args: Vec<String>, io: &IO) -> i32 {
let start_time = SystemTime::now();
// The pfcserver does not want tracing or blackbox or ctrlc setup,
// The pfcserver or commandserver do not want tracing or blackbox or ctrlc setup,
// or going through the Rust command table. Bypass them.
if args.get(1).map(|s| s.as_ref()) == Some("start-pfc-server") {
return HgPython::new(&args).run_hg(args, io, &ConfigSet::new());
if let Some(arg1) = args.get(1).map(|s| s.as_ref()) {
match arg1 {
"start-pfc-server" => return HgPython::new(&args).run_hg(args, io, &ConfigSet::new()),
"start-commandserver" => {
commandserver_serve(&args, io);
return 0;
}
_ => {}
}
}
// Initialize NodeIpc:
@ -887,3 +895,38 @@ fn setup_nodeipc() {
// Trigger `Lazy` initialization.
let _ = nodeipc::get_singleton();
}
// Useful to prevent a commandserver connecting to another commandserver.
static IS_COMMANDSERVER: AtomicBool = AtomicBool::new(false);
fn commandserver_serve(args: &[String], io: &IO) -> i32 {
IS_COMMANDSERVER.store(true, Ordering::Release);
#[cfg(unix)]
unsafe {
libc::setsid();
}
let _ = setup_tracing_io(io, None);
tracing::debug!("preparing commandserver");
let python = HgPython::new(args);
if let Err(e) = python.pre_import_modules() {
tracing::warn!("cannot pre-import modules:\n{:?}", &e);
return 1;
}
let run_func = |args: Vec<String>| -> i32 {
tracing::debug!("commandserver is about to run command: {:?}", &args);
run_command(args, io)
};
// TODO(quark): We need to route `ui.system` through IPC.
tracing::debug!("commandserver is about to serve");
if let Err(e) = commandserver::server::serve_one_client(&run_func) {
tracing::warn!("cannot serve:\n{:?}", &e);
return 1;
}
tracing::debug!("commandserver is about to exit cleanly");
0
}