huskies: merge 1138 story In-container huskies self-update — huskies upgrade pulls a fresh binary without docker rebuild
This commit is contained in:
+85
-2
@@ -27,6 +27,14 @@ pub(crate) struct CliArgs {
|
||||
/// forwards all `prompt_permission` tool calls to the gateway over a WebSocket.
|
||||
/// Also readable from the `HUSKIES_UPSTREAM_GATEWAY` env var.
|
||||
pub(crate) upstream_gateway: Option<String>,
|
||||
/// Whether the `upgrade` subcommand was given.
|
||||
pub(crate) upgrade: bool,
|
||||
/// Source URL for the `upgrade` subcommand (`--source <URL>`).
|
||||
///
|
||||
/// If omitted, the upgrade subcommand falls back to
|
||||
/// `HUSKIES_BINARY_SOURCE` env var, then derives the URL from
|
||||
/// `HUSKIES_UPSTREAM_GATEWAY`.
|
||||
pub(crate) upgrade_source: Option<String>,
|
||||
}
|
||||
|
||||
/// Parse CLI arguments into `CliArgs`, or exit early for `--help` / `--version`.
|
||||
@@ -41,6 +49,8 @@ pub(crate) fn parse_cli_args(args: &[String]) -> Result<CliArgs, String> {
|
||||
let mut join_token: Option<String> = None;
|
||||
let mut gateway_url: Option<String> = None;
|
||||
let mut upstream_gateway: Option<String> = None;
|
||||
let mut upgrade = false;
|
||||
let mut upgrade_source: Option<String> = None;
|
||||
let mut i = 0;
|
||||
|
||||
while i < args.len() {
|
||||
@@ -120,6 +130,19 @@ pub(crate) fn parse_cli_args(args: &[String]) -> Result<CliArgs, String> {
|
||||
"agent" => {
|
||||
agent = true;
|
||||
}
|
||||
"upgrade" => {
|
||||
upgrade = true;
|
||||
}
|
||||
"--source" => {
|
||||
i += 1;
|
||||
if i >= args.len() {
|
||||
return Err("--source requires a value".to_string());
|
||||
}
|
||||
upgrade_source = Some(args[i].clone());
|
||||
}
|
||||
a if a.starts_with("--source=") => {
|
||||
upgrade_source = Some(a["--source=".len()..].to_string());
|
||||
}
|
||||
a if a.starts_with('-') => {
|
||||
return Err(format!("unknown option: {a}"));
|
||||
}
|
||||
@@ -147,6 +170,8 @@ pub(crate) fn parse_cli_args(args: &[String]) -> Result<CliArgs, String> {
|
||||
join_token,
|
||||
gateway_url,
|
||||
upstream_gateway,
|
||||
upgrade,
|
||||
upgrade_source,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -155,12 +180,16 @@ pub(crate) fn print_help() {
|
||||
println!("huskies init [OPTIONS] [PATH]");
|
||||
println!("huskies agent --rendezvous <URL> [OPTIONS] [PATH]");
|
||||
println!("huskies --gateway [OPTIONS] [PATH]");
|
||||
println!("huskies upgrade [--source <URL>]");
|
||||
println!();
|
||||
println!("Serve a huskies project.");
|
||||
println!();
|
||||
println!("COMMANDS:");
|
||||
println!(" init Scaffold a new .huskies/ project and start the interactive setup wizard.");
|
||||
println!(" agent Run as a headless build agent — syncs CRDT state, claims and runs work.");
|
||||
println!(" init Scaffold a new .huskies/ project and start the interactive setup wizard.");
|
||||
println!(" agent Run as a headless build agent — syncs CRDT state, claims and runs work.");
|
||||
println!(
|
||||
" upgrade Fetch a new huskies binary from SOURCE and atomically replace the current"
|
||||
);
|
||||
println!();
|
||||
println!("ARGS:");
|
||||
println!(
|
||||
@@ -190,6 +219,8 @@ pub(crate) fn print_help() {
|
||||
println!(" sled connects to WS URL and forwards all");
|
||||
println!(" prompt_permission calls via the uplink protocol.");
|
||||
println!(" Also readable from HUSKIES_UPSTREAM_GATEWAY env var.");
|
||||
println!(" --source <URL> Binary source URL for the `upgrade` subcommand.");
|
||||
println!(" Falls back to HUSKIES_BINARY_SOURCE env var.");
|
||||
}
|
||||
|
||||
/// Resolve the optional positional path argument into an absolute `PathBuf`.
|
||||
@@ -399,6 +430,58 @@ mod tests {
|
||||
assert!(parse_cli_args(&args).is_err());
|
||||
}
|
||||
|
||||
// ── upgrade subcommand ──────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn parse_upgrade_subcommand() {
|
||||
let args = vec!["upgrade".to_string()];
|
||||
let result = parse_cli_args(&args).unwrap();
|
||||
assert!(result.upgrade);
|
||||
assert_eq!(result.upgrade_source, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_upgrade_with_source_flag() {
|
||||
let args = vec![
|
||||
"upgrade".to_string(),
|
||||
"--source".to_string(),
|
||||
"http://gateway:3000/api/huskies-binary".to_string(),
|
||||
];
|
||||
let result = parse_cli_args(&args).unwrap();
|
||||
assert!(result.upgrade);
|
||||
assert_eq!(
|
||||
result.upgrade_source,
|
||||
Some("http://gateway:3000/api/huskies-binary".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_upgrade_with_source_equals_syntax() {
|
||||
let args = vec![
|
||||
"upgrade".to_string(),
|
||||
"--source=http://gw:3000/api/b".to_string(),
|
||||
];
|
||||
let result = parse_cli_args(&args).unwrap();
|
||||
assert!(result.upgrade);
|
||||
assert_eq!(
|
||||
result.upgrade_source,
|
||||
Some("http://gw:3000/api/b".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_upgrade_source_missing_value_is_error() {
|
||||
let args = vec!["upgrade".to_string(), "--source".to_string()];
|
||||
assert!(parse_cli_args(&args).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_no_args_upgrade_is_false() {
|
||||
let result = parse_cli_args(&[]).unwrap();
|
||||
assert!(!result.upgrade);
|
||||
assert_eq!(result.upgrade_source, None);
|
||||
}
|
||||
|
||||
// ── resolve_path_arg ────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user