Support remote server updates from Windows
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
This commit is contained in:
+153
-40
@@ -301,7 +301,7 @@ async fn main() -> Result<()> {
|
||||
return run_file_cat_command(&args);
|
||||
}
|
||||
if args.server.as_deref() == Some("update") {
|
||||
return run_update(&config, parse_update_options(&args.command)?);
|
||||
return run_update(&config, &args, parse_update_options(&args.command)?);
|
||||
}
|
||||
if args.server.as_deref() == Some("trace") {
|
||||
return run_trace_command(&args);
|
||||
@@ -4097,16 +4097,18 @@ impl UpdateRole {
|
||||
}
|
||||
}
|
||||
|
||||
fn installer_arg_for_os(self, os: &str) -> Result<&'static str> {
|
||||
fn local_installer_arg_for_os(self, os: &str) -> Option<&'static str> {
|
||||
if os == "windows" {
|
||||
return match self {
|
||||
UpdateRole::Auto | UpdateRole::Client => Ok("client"),
|
||||
UpdateRole::Server | UpdateRole::Both => {
|
||||
Err(anyhow!("Windows installs support client updates only"))
|
||||
}
|
||||
UpdateRole::Auto | UpdateRole::Client | UpdateRole::Both => Some("client"),
|
||||
UpdateRole::Server => None,
|
||||
};
|
||||
}
|
||||
Ok(self.installer_arg())
|
||||
Some(self.installer_arg())
|
||||
}
|
||||
|
||||
fn updates_remote_server_from_os(self, os: &str) -> bool {
|
||||
os == "windows" && matches!(self, UpdateRole::Server | UpdateRole::Both)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4423,7 +4425,11 @@ fn url_reachable(url: &str) -> Result<bool> {
|
||||
Ok(status.success())
|
||||
}
|
||||
|
||||
fn run_update(config: &dosh::config::ClientConfig, options: UpdateOptions) -> Result<()> {
|
||||
fn run_update(
|
||||
config: &dosh::config::ClientConfig,
|
||||
args: &Args,
|
||||
options: UpdateOptions,
|
||||
) -> Result<()> {
|
||||
let repo = config
|
||||
.update_repo
|
||||
.clone()
|
||||
@@ -4432,14 +4438,24 @@ fn run_update(config: &dosh::config::ClientConfig, options: UpdateOptions) -> Re
|
||||
let os = std::env::consts::OS;
|
||||
let installer = update_installer_url(&raw_base, os);
|
||||
let artifact = release_artifact_name();
|
||||
let installer_role = options.role.installer_arg_for_os(os)?;
|
||||
let local_installer_role = options.role.local_installer_arg_for_os(os);
|
||||
let update_remote_server = options.role.updates_remote_server_from_os(os);
|
||||
if options.check_only {
|
||||
let local_version = env!("CARGO_PKG_VERSION");
|
||||
let latest_tag = latest_release_tag(&repo)?;
|
||||
println!("dosh {local_version}");
|
||||
println!("repo: {repo}");
|
||||
if let Some(local_installer_role) = local_installer_role {
|
||||
println!("installer: {installer}");
|
||||
println!("role: {installer_role}");
|
||||
println!("role: {local_installer_role}");
|
||||
}
|
||||
if update_remote_server {
|
||||
println!(
|
||||
"remote_installer: {}",
|
||||
update_installer_url(&raw_base, "linux")
|
||||
);
|
||||
println!("remote_server: {}", config.server);
|
||||
}
|
||||
match latest_tag.as_deref() {
|
||||
Some(tag) => {
|
||||
let latest_version = release_version_from_tag(tag);
|
||||
@@ -4450,7 +4466,9 @@ fn run_update(config: &dosh::config::ClientConfig, options: UpdateOptions) -> Re
|
||||
}
|
||||
None => println!("latest: unknown"),
|
||||
}
|
||||
if let Some(latest_url) = latest_release_download_url(&repo, &artifact) {
|
||||
if let Some(latest_url) =
|
||||
local_installer_role.and_then(|_| latest_release_download_url(&repo, &artifact))
|
||||
{
|
||||
let mut status = "missing";
|
||||
let mut display_url = latest_url.clone();
|
||||
if let Some(tag_url) =
|
||||
@@ -4481,15 +4499,27 @@ fn run_update(config: &dosh::config::ClientConfig, options: UpdateOptions) -> Re
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
latest_release_tag(&repo)?.as_deref(),
|
||||
);
|
||||
if update_remote_server {
|
||||
run_remote_server_update(
|
||||
config,
|
||||
args,
|
||||
&repo,
|
||||
&raw_base,
|
||||
&use_prebuilt,
|
||||
binary_version.as_deref(),
|
||||
)?;
|
||||
}
|
||||
if let Some(local_installer_role) = local_installer_role {
|
||||
run_update_installer(
|
||||
config,
|
||||
&repo,
|
||||
&installer,
|
||||
installer_role,
|
||||
local_installer_role,
|
||||
&update_cache.display().to_string(),
|
||||
&use_prebuilt,
|
||||
binary_version.as_deref(),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4546,6 +4576,31 @@ fn run_update_installer(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_remote_server_update(
|
||||
config: &dosh::config::ClientConfig,
|
||||
args: &Args,
|
||||
repo: &str,
|
||||
raw_base: &str,
|
||||
use_prebuilt: &str,
|
||||
binary_version: Option<&str>,
|
||||
) -> Result<()> {
|
||||
anyhow::ensure!(
|
||||
config.server != "user@example.com",
|
||||
"set server in ~/.config/dosh/client.toml before running dosh update --server"
|
||||
);
|
||||
let installer = update_installer_url(raw_base, "linux");
|
||||
let script =
|
||||
remote_unix_server_update_script(config, repo, &installer, use_prebuilt, binary_version);
|
||||
run_remote_script(
|
||||
&config.server,
|
||||
args.ssh_port.or(config.ssh_port),
|
||||
args.ssh_key.as_deref(),
|
||||
args.ssh_known_hosts.as_deref(),
|
||||
&script,
|
||||
"run remote Dosh server update",
|
||||
)
|
||||
}
|
||||
|
||||
fn unix_update_script(
|
||||
config: &dosh::config::ClientConfig,
|
||||
repo: &str,
|
||||
@@ -4580,6 +4635,29 @@ fn unix_update_script(
|
||||
script
|
||||
}
|
||||
|
||||
fn remote_unix_server_update_script(
|
||||
config: &dosh::config::ClientConfig,
|
||||
repo: &str,
|
||||
installer: &str,
|
||||
use_prebuilt: &str,
|
||||
binary_version: Option<&str>,
|
||||
) -> String {
|
||||
let mut env = format!(
|
||||
"DOSH_REPO={} DOSH_PORT={} DOSH_UPDATE_QUIET=1 DOSH_USE_PREBUILT={}",
|
||||
shell_word(repo),
|
||||
config.update_port.unwrap_or(config.dosh_port),
|
||||
shell_word(use_prebuilt)
|
||||
);
|
||||
if let Some(version) = binary_version {
|
||||
env.push_str(&format!(" DOSH_BINARY_VERSION={}", shell_word(version)));
|
||||
}
|
||||
format!(
|
||||
"curl -fsSL {} | {} sh -s -- server",
|
||||
shell_word(installer),
|
||||
env
|
||||
)
|
||||
}
|
||||
|
||||
fn windows_update_script(
|
||||
config: &dosh::config::ClientConfig,
|
||||
repo: &str,
|
||||
@@ -10257,25 +10335,25 @@ mod tests {
|
||||
queue_or_send_stream_data, queue_pending_user_input, queue_stale_pending_user_input,
|
||||
raw_contains_host_table, recv_response_until, refresh_live_addr, release_artifact_name_for,
|
||||
release_tag_download_url, release_tag_from_effective_url, release_version_from_tag,
|
||||
render_frame_bytes, render_status_clear, render_status_overlay, requested_env,
|
||||
resolve_forward_agent_endpoint, resolved_startup_command, retire_stream_state,
|
||||
retransmit_stream_closes, retransmit_stream_eofs, retransmit_stream_opens,
|
||||
retransmit_stream_window_adjusts, rewrite_forward_command, sanitize_trace_name,
|
||||
selected_predict_mode, selected_udp_host, send_stream_eof, server_version_mismatch,
|
||||
should_flush_terminal_input_after_contact, should_health_log_client_start,
|
||||
should_hold_during_startup_gate, should_hold_post_submit_input,
|
||||
should_reconnect_before_input_for_local_sleep, should_repaint_idle_terminal,
|
||||
should_strip_unowned_terminal_reports, split_after_command_submit, split_trace_tokens,
|
||||
ssh_command_target, ssh_config_uses_proxy, ssh_config_word_for_os, ssh_destination_host,
|
||||
ssh_username, ssh_with_user, startup_command, status_ssh_target, strip_stale_mouse_reports,
|
||||
strip_terminal_focus_reports, strip_unowned_terminal_reports, summarize_trace_file,
|
||||
summarize_trace_file_with_mode, terminal_private_mode_transition, toml_bare_key_or_quoted,
|
||||
top_trace_events, trace_report_warnings, unix_update_script,
|
||||
update_binary_version_for_installer, update_installer_url, update_version_status,
|
||||
upsert_managed_block, valid_forward_host, vscode_safe_alias, wake_repaint_retry_deadline,
|
||||
windows_command_word, windows_deferred_update_script, windows_effective_url_script,
|
||||
windows_mode_from_readonly, windows_readonly_from_mode, windows_update_script,
|
||||
windows_url_reachable_script,
|
||||
remote_unix_server_update_script, render_frame_bytes, render_status_clear,
|
||||
render_status_overlay, requested_env, resolve_forward_agent_endpoint,
|
||||
resolved_startup_command, retire_stream_state, retransmit_stream_closes,
|
||||
retransmit_stream_eofs, retransmit_stream_opens, retransmit_stream_window_adjusts,
|
||||
rewrite_forward_command, sanitize_trace_name, selected_predict_mode, selected_udp_host,
|
||||
send_stream_eof, server_version_mismatch, should_flush_terminal_input_after_contact,
|
||||
should_health_log_client_start, should_hold_during_startup_gate,
|
||||
should_hold_post_submit_input, should_reconnect_before_input_for_local_sleep,
|
||||
should_repaint_idle_terminal, should_strip_unowned_terminal_reports,
|
||||
split_after_command_submit, split_trace_tokens, ssh_command_target, ssh_config_uses_proxy,
|
||||
ssh_config_word_for_os, ssh_destination_host, ssh_username, ssh_with_user, startup_command,
|
||||
status_ssh_target, strip_stale_mouse_reports, strip_terminal_focus_reports,
|
||||
strip_unowned_terminal_reports, summarize_trace_file, summarize_trace_file_with_mode,
|
||||
terminal_private_mode_transition, toml_bare_key_or_quoted, top_trace_events,
|
||||
trace_report_warnings, unix_update_script, update_binary_version_for_installer,
|
||||
update_installer_url, update_version_status, upsert_managed_block, valid_forward_host,
|
||||
vscode_safe_alias, wake_repaint_retry_deadline, windows_command_word,
|
||||
windows_deferred_update_script, windows_effective_url_script, windows_mode_from_readonly,
|
||||
windows_readonly_from_mode, windows_update_script, windows_url_reachable_script,
|
||||
};
|
||||
use dosh::config::{ClientConfig, CommandExtension, HostConfig};
|
||||
use dosh::native::EnvVar;
|
||||
@@ -12461,21 +12539,31 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_update_roles_are_client_only() {
|
||||
fn windows_update_roles_split_local_client_and_remote_server() {
|
||||
assert_eq!(
|
||||
UpdateRole::Auto.installer_arg_for_os("windows").unwrap(),
|
||||
"client"
|
||||
UpdateRole::Auto.local_installer_arg_for_os("windows"),
|
||||
Some("client")
|
||||
);
|
||||
assert_eq!(
|
||||
UpdateRole::Client.installer_arg_for_os("windows").unwrap(),
|
||||
"client"
|
||||
UpdateRole::Client.local_installer_arg_for_os("windows"),
|
||||
Some("client")
|
||||
);
|
||||
assert!(UpdateRole::Server.installer_arg_for_os("windows").is_err());
|
||||
assert!(UpdateRole::Both.installer_arg_for_os("windows").is_err());
|
||||
assert_eq!(
|
||||
UpdateRole::Both.installer_arg_for_os("linux").unwrap(),
|
||||
"both"
|
||||
UpdateRole::Server.local_installer_arg_for_os("windows"),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
UpdateRole::Both.local_installer_arg_for_os("windows"),
|
||||
Some("client")
|
||||
);
|
||||
assert!(UpdateRole::Server.updates_remote_server_from_os("windows"));
|
||||
assert!(UpdateRole::Both.updates_remote_server_from_os("windows"));
|
||||
assert!(!UpdateRole::Client.updates_remote_server_from_os("windows"));
|
||||
assert_eq!(
|
||||
UpdateRole::Both.local_installer_arg_for_os("linux"),
|
||||
Some("both")
|
||||
);
|
||||
assert!(!UpdateRole::Both.updates_remote_server_from_os("linux"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -12523,6 +12611,31 @@ mod tests {
|
||||
assert!(!windows.contains(" sh -s "));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_server_update_uses_remote_unix_installer_script() {
|
||||
let config = ClientConfig {
|
||||
server: "palav".to_string(),
|
||||
dosh_port: 50000,
|
||||
update_port: Some(50001),
|
||||
..ClientConfig::default()
|
||||
};
|
||||
let script = remote_unix_server_update_script(
|
||||
&config,
|
||||
"https://git.palav.dev/Palav/dosh.git",
|
||||
"https://git.palav.dev/Palav/dosh/raw/branch/main/install.sh",
|
||||
"1",
|
||||
Some("v1.0.0-rc41"),
|
||||
);
|
||||
assert!(script.contains("curl -fsSL"));
|
||||
assert!(script.contains("install.sh"));
|
||||
assert!(script.contains("DOSH_REPO='https://git.palav.dev/Palav/dosh.git'"));
|
||||
assert!(script.contains("DOSH_PORT=50001"));
|
||||
assert!(script.contains("DOSH_BINARY_VERSION='v1.0.0-rc41'"));
|
||||
assert!(script.contains(" sh -s -- server"));
|
||||
assert!(!script.contains("install.ps1"));
|
||||
assert!(!script.contains("DOSH_ROLE='client'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_update_script_waits_for_parent_before_replacing_locked_exe() {
|
||||
let installer = windows_update_script(
|
||||
|
||||
Reference in New Issue
Block a user