Skip to content

Commit 8f0fb59

Browse files
authored
Revamp how attaching works (#652)
## Overview The `CommandKind` type has confusing, non-orthogonal behavior. It combines two ideas: - Do we need a `HubrisArchive`, and if so, does it need to be fully loaded ("cooked") or do we just need the raw ZIP data? - Do we need to attach to a system (called a "core")? - If so, what kind of attachments are valid? - Live system (debugger) - Live system (network) - Dump (RAM) - Archive (flash only) - How should we validate any attached system? These two big ideas ("do we need an archive" and "do we need a core") are combined in unintuitive ways. For example, `CommandKind::Unattached { archive: Archive::Required }` tries to attach to both a dump and an archive, but does not fail if the archive is absent (see #564 (comment)). It's also unfortunate that it's defined at the `Command` level, because commands may not have consistent behavior across all of their subcommands. For example, `humility hiffy -l` just lists Hiffy APIs from an archive, and does not require attaching to a system. Indeed, if you run `humility hiffy -l` with an archive **and** you have a probe attached to an SP running a different image, it will fail: ```console $ humility --archive=build-cosmo-b-dev-image-default.zip hiffy -l Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.15s Running `target/debug/humility hiffy -l` humility: attached via ST-Link V3 humility hiffy failed: image ID in archive ([bd, 1b, fb, 72, 35, 4b, a7, 48]) does not equal ID at 0x8004f50 ([7c, 56, 0, 8, 38, 54, 0, 8]) # this is an attached Grapefruit, why is it interfering with hiffy -l? ``` Some commands work around this by doing an extra parse of the arguments in their `init` function, then return a different `Command` depending on arguments: https://github.com/oxidecomputer/humility/blob/27d1f1549e58a54538657ab5359be9a5ae856de1/cmd/monorail/src/lib.rs#L1186-L1221 This works, but is annoying to have to do! I have one more complaint, which is improved but not entirely fixed in this PR: the `HubrisArchive` is default-constructed, then _actually_ populated based on `archive` or `dump` arguments; if neither is present, then archive is not valid! Commands have to work around this (with varying degrees of incredulity), e.g. https://github.com/oxidecomputer/humility/blob/27d1f1549e58a54538657ab5359be9a5ae856de1/cmd/reset/src/lib.rs#L33-L37 ## So, what's to be done? This PR removes `CommandKind` entirely. It is replaced with a set of functions on `Cli` to build archives and cores, which can be called by commands when they are needed (instead of before the command is invoked). ### Archive handling - `archive` returns the archive (if available); it **does not** ever return a default-constructed archive - `try_archive` returns an optional archive - `raw_archive` returns the bytes of the ZIP file All of these return a full `HubrisArchive`; it is the caller's responsibility to store it somewhere and hand out references. ### Attachment - `attach_live` attaches to a live system (debugger or `net`-based) - `attach_live_or_dump` attaches to a live system or dump - `attach_archive` attaches to an archive There are also additional small wrapper functions with suffixes for validation, e.g. `attach_live_booted` checks that the live system has booted. Each of these functions returns a `Box<dyn Core>` directly, instead of stashing it in the `ExecutionContext`. ## Changes to commands Each command is updated to construct its archive and/or core on-demand. It's mostly mechanical porting, e.g. ```rust CommandKind::Attached { archive: Archive::Required, attach: Attach::LiveOnly, validate: Validate::Booted, } ``` becomes ```rust let hubris = &context.cli.archive()?; let core = &mut *context.cli.attach_live_booted(hubris)?; ``` ...but there are a few weird edge cases – for example, `humility probe` now uses `attach_probe` directly.
1 parent beb5a08 commit 8f0fb59

426 files changed

Lines changed: 1809 additions & 1551 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ humility = { path = "./humility-core", package = "humility-core" }
113113
humility-arch-arm = { path = "./humility-arch-arm" }
114114
humility-auxflash = { path = "./humility-auxflash" }
115115
humility-cortex = { path = "./humility-arch-cortex" }
116-
humility-cmd = { path = "./humility-cmd", default-features = false }
117-
humility-cli = { path = "./humility-cli" }
116+
humility-cmd = { path = "./humility-cmd" }
117+
humility-cli = { path = "./humility-cli", default-features = false }
118118
humility-dump-agent = { path = "./humility-dump-agent" }
119119
humility-doppel = { path = "./humility-doppel" }
120120
humility-hiffy = { path = "./humility-hiffy" }

DEVELOPING.mkdn

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ So you've decided to add a subcommand to Humility. Here's what you need to do.
3838

3939
2. Review the settings in the `init` routine you cribbed from to make sure they
4040
reflect your subcommand. In particular, the name must appear a second time in
41-
the `name:` field, and `kind` should reflect whether you need an attached
42-
target and archive, or not.
41+
the `name:` field.
4342

4443
3. Cite your new subcommand from the root `Cargo.toml`. This needs to happen in
4544
three places using two different names: in the `workspace.members` element

cmd/auxflash/src/lib.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ use anyhow::Result;
1313
use clap::{CommandFactory, Parser};
1414
use colored::Colorize;
1515
use humility_cli::ExecutionContext;
16-
use humility_cmd::CommandKind;
1716

1817
use humility_auxflash::AuxFlashHandler;
19-
use humility_cmd::{Archive, Attach, Command, Validate};
18+
use humility_cmd::Command;
2019

2120
#[derive(Parser, Debug)]
2221
#[clap(name = "auxflash", about = env!("CARGO_PKG_DESCRIPTION"))]
@@ -99,9 +98,9 @@ fn auxflash_status(mut worker: AuxFlashHandler, verbose: bool) -> Result<()> {
9998
}
10099

101100
fn auxflash(context: &mut ExecutionContext) -> Result<()> {
102-
let core = &mut **context.core.as_mut().unwrap();
103101
let subargs = AuxFlashArgs::try_parse_from(&context.cli.cmd)?;
104-
let hubris = context.archive.as_ref().unwrap();
102+
let hubris = &context.cli.archive()?;
103+
let core = &mut *context.cli.attach_live_booted(hubris)?;
105104
let mut worker = AuxFlashHandler::new(hubris, core, subargs.timeout)?;
106105

107106
match subargs.cmd {
@@ -132,14 +131,5 @@ fn auxflash(context: &mut ExecutionContext) -> Result<()> {
132131
}
133132

134133
pub fn init() -> Command {
135-
Command {
136-
app: AuxFlashArgs::command(),
137-
name: "auxflash",
138-
run: auxflash,
139-
kind: CommandKind::Attached {
140-
archive: Archive::Required,
141-
attach: Attach::LiveOnly,
142-
validate: Validate::Booted,
143-
},
144-
}
134+
Command { app: AuxFlashArgs::command(), name: "auxflash", run: auxflash }
145135
}

cmd/console-proxy/src/lib.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::path::PathBuf;
1010

1111
use clap::{CommandFactory, Parser};
1212

13-
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
13+
use humility_cmd::Command;
1414

1515
#[cfg(not(windows))]
1616
mod posix;
@@ -113,10 +113,5 @@ pub fn init() -> Command {
113113
app: UartConsoleArgs::command(),
114114
name: "console-proxy",
115115
run: console_proxy,
116-
kind: CommandKind::Attached {
117-
archive: Archive::Required,
118-
attach: Attach::LiveOnly,
119-
validate: Validate::Booted,
120-
},
121116
}
122117
}

cmd/console-proxy/src/posix.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,9 @@ impl UnrawTermiosGuard {
314314
}
315315

316316
pub(super) fn console_proxy(context: &mut ExecutionContext) -> Result<()> {
317-
let core = &mut **context.core.as_mut().unwrap();
318317
let subargs = UartConsoleArgs::try_parse_from(&context.cli.cmd)?;
319-
let hubris = context.archive.as_ref().unwrap();
318+
let hubris = &context.cli.archive()?;
319+
let core = &mut *context.cli.attach_live_booted(hubris)?;
320320
let mut worker = UartConsoleHandler::new(
321321
hubris,
322322
core,

cmd/counters/src/lib.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ use humility::core::Core;
206206
use humility::hubris::*;
207207
use humility::reflect::{self, Load, Value};
208208
use humility_cli::ExecutionContext;
209-
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
209+
use humility_cmd::Command;
210210
use humility_doppel::{CountedRingbuf, CounterVariant, Counters};
211211
use indexmap::IndexMap;
212212
use std::collections::BTreeMap;
@@ -324,12 +324,11 @@ const LIST_HINT: &str = "use `humility counters list` to list all \
324324
available counters";
325325

326326
fn counters(context: &mut ExecutionContext) -> Result<()> {
327-
let core = &mut **context.core.as_mut().unwrap();
328-
let hubris = context.archive.as_ref().unwrap();
329-
327+
let hubris = &context.cli.archive()?;
330328
let subargs = CountersArgs::try_parse_from(&context.cli.cmd)?;
331329

332330
if let Some(Subcmd::Ipc(ipc)) = subargs.command {
331+
let core = &mut *context.cli.attach_live_or_dump_match(hubris)?;
333332
return ipc.ipc_counter_dump(hubris, core);
334333
}
335334
let name = subargs.name();
@@ -428,6 +427,7 @@ fn counters(context: &mut ExecutionContext) -> Result<()> {
428427
}
429428

430429
let mut json: IndexMap<&str, IndexMap<_, _>> = IndexMap::new();
430+
let core = &mut *context.cli.attach_live_or_dump_match(hubris)?;
431431
for (t, ctrs) in counters {
432432
// Try not to use `?` here, because it causes one bad counter to make
433433
// them all unavailable. Instead, construct an iterator of
@@ -623,14 +623,5 @@ fn hint() -> impl std::fmt::Display {
623623
}
624624

625625
pub fn init() -> Command {
626-
Command {
627-
app: CountersArgs::command(),
628-
name: "counters",
629-
run: counters,
630-
kind: CommandKind::Attached {
631-
archive: Archive::Required,
632-
attach: Attach::Any,
633-
validate: Validate::Match,
634-
},
635-
}
626+
Command { app: CountersArgs::command(), name: "counters", run: counters }
636627
}

cmd/dashboard/src/lib.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use hif::*;
2929
use humility::core::Core;
3030
use humility::hubris::*;
3131
use humility_cli::ExecutionContext;
32-
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
32+
use humility_cmd::Command;
3333
use humility_hiffy::*;
3434
use humility_idol::{self as idol, HubrisIdol};
3535
use ratatui::{
@@ -736,11 +736,10 @@ where
736736
}
737737

738738
fn dashboard(context: &mut ExecutionContext) -> Result<()> {
739-
let hubris = context.archive.as_ref().unwrap();
740-
741-
let core = &mut **context.core.as_mut().unwrap();
742-
743739
let subargs = DashboardArgs::try_parse_from(&context.cli.cmd)?;
740+
let hubris = &context.cli.archive()?;
741+
let core = &mut *context.cli.attach_live_booted(hubris)?;
742+
744743
let dashboard = Dashboard::new(hubris, core, &subargs)?;
745744

746745
// setup terminal
@@ -767,16 +766,7 @@ fn dashboard(context: &mut ExecutionContext) -> Result<()> {
767766
}
768767

769768
pub fn init() -> Command {
770-
Command {
771-
app: DashboardArgs::command(),
772-
name: "dashboard",
773-
run: dashboard,
774-
kind: CommandKind::Attached {
775-
archive: Archive::Required,
776-
attach: Attach::LiveOnly,
777-
validate: Validate::Booted,
778-
},
779-
}
769+
Command { app: DashboardArgs::command(), name: "dashboard", run: dashboard }
780770
}
781771

782772
fn sensor_ops(

cmd/debugmailbox/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use anyhow::{Context, Result, bail};
3232
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
3333
use clap::{CommandFactory, Parser};
3434
use humility_cli::ExecutionContext;
35-
use humility_cmd::{Archive, Command, CommandKind};
35+
use humility_cmd::Command;
3636
use probe_rs::{
3737
DebugProbeError, DebugProbeSelector, Probe,
3838
architecture::arm::{ApAddress, ArmProbeInterface, DapError, DpAddress},
@@ -464,6 +464,5 @@ pub fn init() -> Command {
464464
app: DebugMailboxArgs::command(),
465465
name: "debugmailbox",
466466
run: debugmailboxcmd,
467-
kind: CommandKind::Unattached { archive: Archive::Ignored },
468467
}
469468
}

cmd/diagnose/src/lib.rs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,14 @@ use clap::{CommandFactory, Parser};
1919
use humility::core::Core;
2020
use humility::hubris::*;
2121
use humility_cli::ExecutionContext;
22-
use humility_cmd::CommandKind;
23-
use humility_cmd::{Archive, Attach, Command, Validate};
22+
use humility_cmd::Command;
2423
use humility_doppel::{GenOrRestartCount, Task, TaskDesc, TaskState};
2524
use std::num::NonZeroU32;
2625
use std::time::Duration;
2726

2827
/// Command registration.
2928
pub fn init() -> Command {
30-
Command {
31-
app: DiagnoseArgs::command(),
32-
name: "diagnose",
33-
run: diagnose,
34-
kind: CommandKind::Attached {
35-
archive: Archive::Required,
36-
attach: Attach::Any,
37-
validate: Validate::Booted,
38-
},
39-
}
29+
Command { app: DiagnoseArgs::command(), name: "diagnose", run: diagnose }
4030
}
4131

4232
#[derive(Parser, Debug)]
@@ -83,10 +73,9 @@ fn section(title: &str) {
8373
}
8474

8575
fn diagnose(context: &mut ExecutionContext) -> Result<()> {
86-
let core = &mut **context.core.as_mut().unwrap();
87-
let hubris = context.archive.as_ref().unwrap();
88-
8976
let subargs = DiagnoseArgs::try_parse_from(&context.cli.cmd)?;
77+
let hubris = &context.cli.archive()?;
78+
let core = &mut *context.cli.attach_live_or_dump_booted(hubris)?;
9079

9180
section("Initial Inspection");
9281

0 commit comments

Comments
 (0)