diff options
Diffstat (limited to 'src/remote.rs')
| -rw-r--r-- | src/remote.rs | 88 |
1 files changed, 76 insertions, 12 deletions
diff --git a/src/remote.rs b/src/remote.rs index 990ffb7b..9a4cc774 100644 --- a/src/remote.rs +++ b/src/remote.rs @@ -54,6 +54,7 @@ impl RemoteKeybindings { pub(crate) struct RemoteLaunch { pub(crate) target: String, pub(crate) keybindings: RemoteKeybindings, + pub(crate) live_handoff: bool, } pub(crate) fn extract_remote_args( @@ -67,9 +68,15 @@ pub(crate) fn extract_remote_args( let mut remote_target = None; let mut keybindings = RemoteKeybindings::Local; let mut keybindings_seen = false; + let mut live_handoff = false; let mut index = 1; while index < args.len() { let arg = &args[index]; + if arg == "--handoff" { + live_handoff = true; + index += 1; + continue; + } if arg == "--remote" { if remote_target.is_some() { return Err("--remote can only be specified once".to_string()); @@ -118,10 +125,14 @@ pub(crate) fn extract_remote_args( let remote = remote_target.map(|target| RemoteLaunch { target, keybindings, + live_handoff, }); if remote.is_none() && keybindings_seen { return Err("--remote-keybindings requires --remote".to_string()); } + if remote.is_none() && live_handoff { + cleaned.push("--handoff".to_string()); + } Ok((cleaned, remote)) } @@ -143,13 +154,19 @@ pub(crate) fn run_remote(remote: RemoteLaunch) -> io::Result<()> { let program = std::env::args() .next() .unwrap_or_else(|| "herdr".to_string()); - let reattach_command = - reattach_command(&program, &remote.target, &session_name, remote.keybindings); - let prepared_remote = prepare_remote_herdr(&remote.target)?; + let reattach_command = reattach_command( + &program, + &remote.target, + &session_name, + remote.keybindings, + remote.live_handoff, + ); + let prepared_remote = prepare_remote_herdr(&remote.target, remote.live_handoff)?; ensure_remote_server_ready( &remote.target, &prepared_remote.remote_herdr, prepared_remote.installed_or_replaced, + remote.live_handoff, )?; let _bridge = SshStdioBridge::start( @@ -318,7 +335,10 @@ impl InstallSource { } } -fn prepare_remote_herdr(target: &str) -> io::Result<PreparedRemoteHerdr> { +fn prepare_remote_herdr( + target: &str, + live_handoff_enabled: bool, +) -> io::Result<PreparedRemoteHerdr> { let platform = detect_remote_platform(target)?; let remote_herdr = RemoteHerdr::for_platform(platform); let override_binary = remote_binary_override_path()?; @@ -347,7 +367,11 @@ fn prepare_remote_herdr(target: &str) -> io::Result<PreparedRemoteHerdr> { .ok() .and_then(|exists| exists.then_some(&remote_herdr)) }) { - confirm_remote_install_with_running_server(target, status_probe_herdr)?; + confirm_remote_install_with_running_server( + target, + status_probe_herdr, + live_handoff_enabled, + )?; } confirm_remote_install( target, @@ -552,6 +576,7 @@ fn ensure_remote_server_ready( target: &str, remote_herdr: &RemoteHerdr, remote_binary_changed: bool, + live_handoff_enabled: bool, ) -> io::Result<()> { let status = remote_server_status(target, remote_herdr)?; let RemoteServerStatus::Running { @@ -569,7 +594,9 @@ fn ensure_remote_server_ready( return Ok(()); }; - if live_handoff && confirm_remote_server_handoff(target, version.as_deref(), protocol, reason)? + if live_handoff_enabled + && live_handoff + && confirm_remote_server_handoff(target, version.as_deref(), protocol, reason)? { match live_handoff_remote_server(target, remote_herdr) { Ok(()) => return Ok(()), @@ -606,6 +633,7 @@ fn remote_server_restart_reason( fn confirm_remote_install_with_running_server( target: &str, remote_herdr: &RemoteHerdr, + live_handoff_enabled: bool, ) -> io::Result<()> { let status = match remote_server_status(target, remote_herdr) { Ok(status) => status, @@ -641,13 +669,13 @@ fn confirm_remote_install_with_running_server( else { return Ok(()); }; - if live_handoff { + if live_handoff_enabled && live_handoff { return Ok(()); } if !io::stdin().is_terminal() { return Err(io::Error::other(format!( - "remote herdr server on {target} is running v{} protocol {}, but it does not advertise live handoff; run from an interactive terminal to approve updating the remote binary", + "remote herdr server on {target} is running v{} protocol {}; run from an interactive terminal to approve updating the remote binary", version_label(version.as_deref()), protocol_label(protocol) ))); @@ -660,10 +688,7 @@ fn confirm_remote_install_with_running_server( protocol_label(protocol) ); eprintln!( - "this server does not advertise live handoff, so this attach cannot preserve its running panes during the update." - ); - eprintln!( - "future remote updates can preserve panes after the remote server has run a handoff-capable version once." + "this attach will not preserve running panes unless you pass --handoff and the remote server supports live handoff." ); eprintln!(); eprint!("continue installing the remote herdr binary? [Y/n] "); @@ -1118,6 +1143,7 @@ fn reattach_command( target: &str, session_name: &str, keybindings: RemoteKeybindings, + live_handoff: bool, ) -> String { let program = if program.is_empty() { "herdr" } else { program }; let mut command = format!("{} --remote {}", shell_quote(program), shell_quote(target)); @@ -1125,6 +1151,9 @@ fn reattach_command( command.push_str(" --remote-keybindings "); command.push_str(keybindings.as_str()); } + if live_handoff { + command.push_str(" --handoff"); + } if session_name != crate::session::DEFAULT_SESSION_NAME { command.push_str(" --session "); command.push_str(&shell_quote(session_name)); @@ -1471,6 +1500,28 @@ mod tests { } #[test] + fn extract_remote_args_accepts_explicit_handoff() { + let args = vec!["herdr".into(), "--remote=dev".into(), "--handoff".into()]; + + let (cleaned, remote) = extract_remote_args(&args).unwrap(); + + assert_eq!(cleaned, vec!["herdr"]); + let remote = remote.unwrap(); + assert_eq!(remote.target, "dev"); + assert!(remote.live_handoff); + } + + #[test] + fn extract_remote_args_preserves_handoff_without_remote() { + let args = vec!["herdr".into(), "update".into(), "--handoff".into()]; + + let (cleaned, remote) = extract_remote_args(&args).unwrap(); + + assert_eq!(cleaned, args); + assert!(remote.is_none()); + } + + #[test] fn extract_remote_args_rejects_remote_keybindings_without_remote() { let args = vec!["herdr".into(), "--remote-keybindings=server".into()]; let err = extract_remote_args(&args).unwrap_err(); @@ -1551,6 +1602,7 @@ mod tests { "user@host", "work", RemoteKeybindings::Local, + false, ), "target/release/herdr --remote user@host --session work" ); @@ -1560,6 +1612,7 @@ mod tests { "host name", crate::session::DEFAULT_SESSION_NAME, RemoteKeybindings::Local, + false, ), "herdr --remote 'host name'" ); @@ -1569,9 +1622,20 @@ mod tests { "host", crate::session::DEFAULT_SESSION_NAME, RemoteKeybindings::Server, + false, ), "herdr --remote host --remote-keybindings server" ); + assert_eq!( + reattach_command( + "herdr", + "host", + crate::session::DEFAULT_SESSION_NAME, + RemoteKeybindings::Local, + true, + ), + "herdr --remote host --handoff" + ); } #[test] |
