cli: add new control server messages for wsl (#180438)

* cli: add new control server messages for wsl

* support cwd in spawn
This commit is contained in:
Connor Peet 2023-04-20 15:19:05 -07:00 committed by GitHub
parent fd5ccc856c
commit cedf1eaa25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 108 additions and 11 deletions

View file

@ -21,6 +21,7 @@ use crate::util::http::{
};
use crate::util::io::SilentCopyProgress;
use crate::util::is_integrated_cli;
use crate::util::os::os_release;
use crate::util::sync::{new_barrier, Barrier};
use futures::stream::FuturesUnordered;
@ -47,9 +48,10 @@ use super::paths::prune_stopped_servers;
use super::port_forwarder::{PortForwarding, PortForwardingProcessor};
use super::protocol::{
AcquireCliParams, CallServerHttpParams, CallServerHttpResult, ClientRequestMethod, EmptyObject,
ForwardParams, ForwardResult, GetHostnameResponse, HttpBodyParams, HttpHeadersParams,
ServeParams, ServerLog, ServerMessageParams, SpawnParams, SpawnResult, ToClientRequest,
UnforwardParams, UpdateParams, UpdateResult, VersionParams,
ForwardParams, ForwardResult, FsStatRequest, FsStatResponse, GetEnvResponse,
GetHostnameResponse, HttpBodyParams, HttpHeadersParams, ServeParams, ServerLog,
ServerMessageParams, SpawnParams, SpawnResult, ToClientRequest, UnforwardParams, UpdateParams,
UpdateResult, VersionParams,
};
use super::server_bridge::ServerBridge;
use super::server_multiplexer::ServerMultiplexer;
@ -264,6 +266,8 @@ async fn process_socket(
rpc.register_sync("ping", |_: EmptyObject, _| Ok(EmptyObject {}));
rpc.register_sync("gethostname", |_: EmptyObject, _| handle_get_hostname());
rpc.register_sync("fs_stat", |p: FsStatRequest, _| handle_stat(p.path));
rpc.register_sync("get_env", |_: EmptyObject, _| handle_get_env());
rpc.register_async("serve", move |params: ServeParams, c| async move {
handle_serve(c, params).await
});
@ -672,6 +676,34 @@ fn handle_get_hostname() -> Result<GetHostnameResponse, AnyError> {
})
}
fn handle_stat(path: String) -> Result<FsStatResponse, AnyError> {
Ok(std::fs::metadata(path)
.map(|m| FsStatResponse {
exists: true,
size: Some(m.len()),
kind: Some(match m.file_type() {
t if t.is_dir() => "dir",
t if t.is_file() => "file",
t if t.is_symlink() => "link",
_ => "unknown",
}),
})
.unwrap_or_default())
}
fn handle_get_env() -> Result<GetEnvResponse, AnyError> {
Ok(GetEnvResponse {
env: std::env::vars().collect(),
os_release: os_release().unwrap_or_else(|_| "unknown".to_string()),
#[cfg(windows)]
os_platform: "win32",
#[cfg(target_os = "linux")]
os_platform: "linux",
#[cfg(target_os = "macos")]
os_platform: "darwin",
})
}
async fn handle_forward(
log: &log::Logger,
port_forwarding: &PortForwarding,
@ -804,14 +836,17 @@ where
};
}
let mut p = tokio::process::Command::new(&params.command)
.args(&params.args)
.envs(&params.env)
.stdin(pipe_if_some!(stdin))
.stdout(pipe_if_some!(stdout))
.stderr(pipe_if_some!(stderr))
.spawn()
.map_err(CodeError::ProcessSpawnFailed)?;
let mut p = tokio::process::Command::new(&params.command);
p.args(&params.args);
p.envs(&params.env);
p.stdin(pipe_if_some!(stdin));
p.stdout(pipe_if_some!(stdout));
p.stderr(pipe_if_some!(stderr));
if let Some(cwd) = &params.cwd {
p.current_dir(cwd);
}
let mut p = p.spawn().map_err(CodeError::ProcessSpawnFailed)?;
let futs = FuturesUnordered::new();
if let (Some(mut a), Some(mut b)) = (p.stdout.take(), stdout) {

View file

@ -128,6 +128,26 @@ pub struct GetHostnameResponse {
pub value: String,
}
#[derive(Serialize)]
pub struct GetEnvResponse {
pub env: HashMap<String, String>,
pub os_platform: &'static str,
pub os_release: String,
}
#[derive(Deserialize)]
pub struct FsStatRequest {
pub path: String,
}
#[derive(Serialize, Default)]
pub struct FsStatResponse {
pub exists: bool,
pub size: Option<u64>,
#[serde(rename = "type")]
pub kind: Option<&'static str>,
}
#[derive(Deserialize, Debug)]
pub struct CallServerHttpParams {
pub path: String,
@ -164,6 +184,8 @@ pub struct SpawnParams {
pub command: String,
pub args: Vec<String>,
#[serde(default)]
pub cwd: Option<String>,
#[serde(default)]
pub env: HashMap<String, String>,
}

View file

@ -17,5 +17,6 @@ pub mod sync;
pub use is_integrated::*;
pub mod app_lock;
pub mod file_lock;
pub mod os;
pub mod tar;
pub mod zipper;

39
cli/src/util/os.rs Normal file
View file

@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
#[cfg(windows)]
pub fn os_release() -> Result<String, std::io::Error> {
// The windows API *had* nice GetVersionEx/A APIs, but these were deprecated
// in Winodws 8 and there's no newer win API to get version numbers. So
// instead read the registry.
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
let key = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey(r"SOFTWARE\Microsoft\Windows NT\CurrentVersion")?;
let major: u32 = key.get_value("CurrentMajorVersionNumber")?;
let minor: u32 = key.get_value("CurrentMinorVersionNumber")?;
let build: String = key.get_value("CurrentBuild")?;
Ok(format!("{}.{}.{}", major, minor, build))
}
#[cfg(unix)]
pub fn os_release() -> Result<String, std::io::Error> {
use std::{ffi::CStr, mem};
unsafe {
let mut ret = mem::MaybeUninit::zeroed();
if libc::uname(ret.as_mut_ptr()) != 0 {
return Err(std::io::Error::last_os_error());
}
let ret = ret.assume_init();
let c_str: &CStr = CStr::from_ptr(ret.release.as_ptr());
Ok(c_str.to_string_lossy().into_owned())
}
}