diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 917bdbd..4845b94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -470,12 +470,22 @@ jobs: # devlaunch-core/public-api.rest.txt the tripwire over the binary surface, and # devlaunch-runner/public-api.txt the process seam. # - # "As a path match can see it" is the honest scope, and it is narrower than it - # reads: cargo public-api renders methods and impls only at a type's canonical - # path, so a promised type's constructors, methods and derived impls are in - # the rest file, and renaming `api::Launch::run` leaves the promise file - # byte-identical. A diff in the rest file touching a promised type is a - # contract change too. Widening the classifier is #352. + # "As a path match can see it" was the honest scope until #352 and is no + # longer the scope at all. cargo public-api renders methods and impls only at + # a type's canonical path, so matching the `api` path alone kept the promised + # types' names and left every one of their constructors, methods and derived + # impls in the rest file — renaming `api::Launch::run` diffed neither file + # where a reader would look. The classifier now resolves each `api` re-export + # back to the path it names and claims that item's rows too, which is why most + # of the promise file is written at `flows::` and `domain::` paths. + # + # What is left over is still real and is not one type: 39 types that a + # promised signature hands back but `api` never re-exports own over six + # hundred rows in the rest file, `domain::spec::DevcontainerRefError` — the + # error type of the promised `api::resolve_devcontainer_ref` — among them. + # So a rest-file diff is routine for a row whose subject nothing promised + # names and a contract change for a row whose subject is one of those; + # `--print-residual` tells them apart. # # Nightly because cargo-public-api's rustdoc-JSON backend needs it; the crates # themselves still build on the stable pin everywhere else. The pinned @@ -526,8 +536,9 @@ jobs: "scripts/public-api-snapshots.sh (needs a nightly toolchain and the" \ "cargo-public-api the script pins; see 'The public-API snapshots' in" \ "docs/development.md). A diff in devlaunch-core/public-api.api.txt is a change" \ - "to the promised API — say which, and note that a promised type's" \ - "methods and impls diff in the rest file instead (#352)." + "to the promised API — say which. A promised type's methods and impls are" \ + "in there too, under the canonical path they are rendered at, so a diff" \ + "that names a flows:: or domain:: path in that file is still a promise." exit 1 fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 1207e31..9de844d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -206,6 +206,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `json.dumps` printed for it. `wf` parses that document, so the bar was byte-identity and not equivalence. +- **The frozen-API snapshot now covers the promised types' behaviour, not just their + names (#352).** `cargo public-api` renders inherent methods and trait impls at a + type's canonical path only, never at the path it is re-exported under, so + `api::Launch::run` was rendered `flows::launch::Launch::run` and a filter matching + the `api` path could not see it. `public-api.api.txt` held 182 rows and not one + `::new(` or `::run(`, which means renaming `Launch::run` left the file that exists + to catch exactly that byte-identical. Measured, not inferred: the rename was done + and the file did not move. + + The classifier now reads the `api` module's own re-exports, resolves each back to + the path it names, and claims that item's rows too. 631 rows moved from + `public-api.rest.txt` to `public-api.api.txt`, none appeared from nowhere, and the + same rename now diffs the promise file. Two things follow for a reader of these + files. Most of the promise file is written at `flows::` and `domain::` paths now, + and that is the promise rather than strays. And moving a promised type between + modules churns it, which is the price of the guard working at all. + + What the widened classifier still does not reach is written down as a number + rather than as an example, because the example was doing the work of the number. + Every place describing the promise file named `flows::launch::Launched` and + stopped, which reads as one type; the residual is 39 types owning over six + hundred rows in `public-api.rest.txt`, and one of them is + `DevcontainerRefError`, the error type of `api::resolve_devcontainer_ref`, + whose own row is in the promise file at the `api` path. Rename a variant of it + and every consumer matching on it breaks while the only diff is in the file the + docs call freely regenerated. `scripts/public-api-snapshots.sh + --print-residual` lists them from the checked-in snapshots with no toolchain, + and `test/test_public_api_snapshots_doc.py` holds the count in all three + descriptions to what it prints, so the sentence goes red rather than stale. + +### Fixed + ### Fixed - **A captured command no longer pays the drain grace twice.** When a command diff --git a/docs/development.md b/docs/development.md index 7fb6c47..dbcf4d5 100644 --- a/docs/development.md +++ b/docs/development.md @@ -49,19 +49,51 @@ because they are not one promise: | File | What a diff means | | --- | --- | -| `devlaunch-core/public-api.api.txt` | **A change to the promised contract.** A removal or a changed signature breaks a consumer, an addition is a deliberate widening. Holds the 126 declarations written *at* the `devlaunch_core::api` path, and only those. | -| `devlaunch-core/public-api.rest.txt` | Mostly routine. The binary API (`flows::`, `domain::`, `clients::`) is reachable but never promised, so read it for the accidental `pub`. **But** the promised types' methods and impls are in here too (see below), and a diff touching one of those is a contract change. | +| `devlaunch-core/public-api.api.txt` | **A change to the promised contract.** A removal or a changed signature breaks a consumer, an addition is a deliberate widening. Holds the 813 rows that declare what `devlaunch_core::api` re-exports, wherever `cargo public-api` chose to render them. | +| `devlaunch-core/public-api.rest.txt` | Mostly routine. The binary API (`flows::`, `domain::`, `clients::`) is reachable but never promised, so read it for the accidental `pub`. **But** see the limit below before reading a diff as routine. | | `devlaunch-runner/public-api.txt` | The process seam an external `Runner` implementer writes against. | -**The promise file holds declarations, not behaviour.** `cargo public-api` renders inherent methods -and trait impls only at a type's *canonical* path, never at the path it is re-exported under, so -the classifier cannot see them. `api::Launch`'s only constructor and only method are rendered -`flows::launch::Launch::{new, run}` and land in the rest file, along with `CommandContext::new`, -`DevcontainerPath::as_str` and every derived `Clone`/`Debug`/`PartialEq` on the promised types: 133 -of the 259 rows the generator emits for the `api` section. Measured consequence: renaming -`api::Launch::run` leaves `public-api.api.txt` byte-identical. The guard is therefore one-way. A -diff in the promise file is a change to the promise, but not every change to the promise diffs it. -Widening the classifier is [#352](https://github.com/blooop/devlaunch/issues/352). +**Why the promise file is full of `flows::` and `domain::` paths.** `cargo public-api` renders an +item's own declaration at every path it is reachable by, so `api::Launch` gets a row of its own. It +renders inherent methods and trait impls at the type's *canonical* path only, never at the path it +is re-exported under, so `api::Launch::run` is rendered `flows::launch::Launch::run`. A classifier +that matched the `api` path alone therefore kept the promised types' names and dropped all of their +behaviour, and renaming `api::Launch::run` left the file byte-identical. So the classifier resolves +each `api` re-export back to the path it names and claims that item's rows too +([#352](https://github.com/blooop/devlaunch/issues/352)), which moved 631 rows across: `Launch::new` +and `Launch::run`, `CommandContext::new`, `DevcontainerPath::as_str`, and every derived +`Clone`/`Debug`/`PartialEq` on a promised type. Those paths are the promise and not strays. The +cost is real and worth knowing before you see it: moving a promised type between modules now churns +the file where churn is expensive. Some rows appear twice, because the generator emits them twice, +once under the `api` section and once under the module that owns them. + +**What it still does not reach, and it is not one type.** A type `api` never re-exports but a +promised signature hands back is reachable from outside and classified as binary surface. Counted +on the checked-in files rather than guessed at, that is **39 types owning over six hundred rows** in +`public-api.rest.txt`, and the command that lists them needs no toolchain: + +```bash +scripts/public-api-snapshots.sh --print-residual +``` + +`domain::spec::DevcontainerRefError` is the one to hold the limit against. `api` promises +`resolve_devcontainer_ref`, whose row sits in the promise file at the `api` path itself, and it +returns that error: rename a variant of it and every consumer matching on it breaks, while the only +file that moves is the one this page calls freely regenerated. +`domain::metadata::MetadataError` is the same shape, carried by the promised +`StartupError::Metadata`. `flows::launch::Launched`, returned by `Launch::run`, is the example this +section used to give on its own, which made six hundred rows read as one. + +So a diff in `public-api.rest.txt` is routine for a row whose subject nothing promised names, and a +contract change for a row whose subject is one of the 39. `--print-residual` is how you tell the two +apart, and `test/test_public_api_snapshots_doc.py` diffs the count of types in this paragraph +against it, so the sentence goes red rather than stale. The row total is left round on purpose: it +moves whenever anything is added to any one of the 39 and says nothing about the scale of the +limit, where the count of types moves only when the residual really grows. + +The `-ss` flag also omits blanket and auto-trait impls from both files, +deliberately: those rows move when rustdoc moves, and a tripwire that fires on toolchain drift +teaches people to update snapshots unread. The runner had no snapshot of its own until #338: its whole API entered core's as the single unexpanded row `pub use devlaunch_core::runner::<>`, so removing a trait @@ -89,15 +121,19 @@ cargo install cargo-public-api --locked --version "$(scripts/public-api-snapshot ``` Committing a regenerated `public-api.api.txt` is committing a change to the promised contract, so -say which one in the pull request. If the change was to a promised type's methods or impls, -the diff to point at is in `public-api.rest.txt`. `rust/devlaunch-core/tests/public_api_snapshots.rs` -holds the two core files to the split itself, every promised row an `api` declaration and none -of the others one, so a hand-edit that files a row in the wrong tier fails in the Rust suite. -Ordering is not a partition property and nothing local checks it, so a block written in the -wrong position satisfies every one of those assertions and is caught only by CI's `public-api` -job, which regenerates the files and diffs them. A hand-edited snapshot is therefore provisional -until that job agrees, and in this repository's devcontainer, which has neither prerequisite -above, hand-editing is the only route there is. +say which one in the pull request. `rust/devlaunch-core/tests/public_api_snapshots.rs` holds the two +core files to the split itself: feed it both and the classifier has to hand back the same two files, +each row on the side it is already on. So a hand-edit that files a row in the wrong tier, or a pair +regenerated by different rules, fails in the Rust suite rather than in review. That test reaches the +classifier through `scripts/public-api-snapshots.sh --classify`, which filters rows on stdin and +needs no toolchain at all, so the rule has one definition rather than a Rust copy of a shell one. + +What that fixed point does not pin is where a row sits *within* its file. The classifier preserves +the order it is fed, so a block moved to the wrong position inside `public-api.api.txt` comes back +in the position it was moved to and satisfies every assertion. Only CI's `public-api` job, which +regenerates both files and diffs them, catches that. A hand-edited snapshot is therefore provisional +until that job agrees, and in this repository's devcontainer, which has neither prerequisite above, +hand-editing is the only route there is. **What a failed run leaves behind**, precisely, because "nothing" would be a claim rather than a fact. The script checks every destination is writable before it generates anything, then writes diff --git a/rust/devlaunch-core/public-api.api.txt b/rust/devlaunch-core/public-api.api.txt index 2197a33..29d11c9 100644 --- a/rust/devlaunch-core/public-api.api.txt +++ b/rust/devlaunch-core/public-api.api.txt @@ -2,11 +2,37 @@ pub mod devlaunch_core::api pub enum devlaunch_core::api::ColdRefused pub devlaunch_core::api::ColdRefused::NoColdPath pub devlaunch_core::api::ColdRefused::Startup(devlaunch_core::flows::records::StartupError) +impl core::clone::Clone for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::clone(&self) -> devlaunch_core::flows::launch::ColdRefused +impl core::cmp::Eq for devlaunch_core::flows::launch::ColdRefused +impl core::cmp::PartialEq for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::eq(&self, &devlaunch_core::flows::launch::ColdRefused) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::ColdRefused pub enum devlaunch_core::api::DeleteStalled pub devlaunch_core::api::DeleteStalled::OnTheLock +impl core::clone::Clone for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::clone(&self) -> devlaunch_core::flows::lifecycle::DeleteStalled +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::DeleteStalled +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::eq(&self, &devlaunch_core::flows::lifecycle::DeleteStalled) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::DeleteStalled +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::DeleteStalled pub enum devlaunch_core::api::Insistence pub devlaunch_core::api::Insistence::Insisted pub devlaunch_core::api::Insistence::NotInsisted +impl core::clone::Clone for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::clone(&self) -> devlaunch_core::flows::lifecycle::Insistence +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Insistence +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::eq(&self, &devlaunch_core::flows::lifecycle::Insistence) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::Insistence +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Insistence pub enum devlaunch_core::api::LaunchNotice pub devlaunch_core::api::LaunchNotice::AlreadyRunning pub devlaunch_core::api::LaunchNotice::AlreadyRunning::workspace_id: alloc::string::String @@ -48,6 +74,14 @@ pub devlaunch_core::api::LaunchNotice::TokenNotStaged pub devlaunch_core::api::LaunchNotice::TokenNotStaged::reason: alloc::string::String pub devlaunch_core::api::LaunchNotice::WaitingForSiblingLaunch pub devlaunch_core::api::LaunchNotice::WaitingForSiblingLaunch::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::clone(&self) -> devlaunch_core::flows::launch::LaunchNotice +impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchNotice +impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::eq(&self, &devlaunch_core::flows::launch::LaunchNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchNotice pub enum devlaunch_core::api::LaunchVerb pub devlaunch_core::api::LaunchVerb::Attach pub devlaunch_core::api::LaunchVerb::Attach::command: core::option::Option @@ -57,6 +91,14 @@ pub devlaunch_core::api::LaunchVerb::Recreate pub devlaunch_core::api::LaunchVerb::Reset pub devlaunch_core::api::LaunchVerb::Restart pub devlaunch_core::api::LaunchVerb::Up +impl core::clone::Clone for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::clone(&self) -> devlaunch_core::flows::launch::LaunchVerb +impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchVerb +impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::eq(&self, &devlaunch_core::flows::launch::LaunchVerb) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchVerb pub enum devlaunch_core::api::LifecycleNotice pub devlaunch_core::api::LifecycleNotice::AddressingRecordedWorkspace pub devlaunch_core::api::LifecycleNotice::AddressingRecordedWorkspace::branch: alloc::string::String @@ -81,6 +123,14 @@ pub devlaunch_core::api::LifecycleNotice::VolumesNotRemoved pub devlaunch_core::api::LifecycleNotice::VolumesNotRemoved::occasion: devlaunch_core::flows::lifecycle::SweepOccasion pub devlaunch_core::api::LifecycleNotice::VolumesNotRemoved::refusal: devlaunch_core::flows::lifecycle::VolumeRefusal pub devlaunch_core::api::LifecycleNotice::VolumesNotRemoved::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::clone(&self) -> devlaunch_core::flows::lifecycle::LifecycleNotice +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::LifecycleNotice +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::eq(&self, &devlaunch_core::flows::lifecycle::LifecycleNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice pub enum devlaunch_core::api::ProvisionEvent pub devlaunch_core::api::ProvisionEvent::NotInstalled pub devlaunch_core::api::ProvisionEvent::NotInstalled::exit: devlaunch_runner::Exit @@ -102,15 +152,42 @@ pub devlaunch_core::api::ProvisionEvent::StageNotReported::workspace: alloc::str pub devlaunch_core::api::ProvisionEvent::TripRefused pub devlaunch_core::api::ProvisionEvent::TripRefused::refusal: devlaunch_core::clients::devpod::NotRun pub devlaunch_core::api::ProvisionEvent::TripRefused::workspace: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::clone(&self) -> devlaunch_core::flows::provision::ProvisionEvent +impl core::cmp::Eq for devlaunch_core::flows::provision::ProvisionEvent +impl core::cmp::PartialEq for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::eq(&self, &devlaunch_core::flows::provision::ProvisionEvent) -> bool +impl core::fmt::Debug for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::ProvisionEvent pub enum devlaunch_core::api::RecordsNotice pub devlaunch_core::api::RecordsNotice::Metadata(devlaunch_core::domain::metadata::Notice) pub devlaunch_core::api::RecordsNotice::Migrated(devlaunch_core::flows::migration::MigrationReport) pub devlaunch_core::api::RecordsNotice::MigrationRefused(devlaunch_core::domain::metadata::MetadataError) pub devlaunch_core::api::RecordsNotice::RetiredKey(devlaunch_core::domain::config::RetiredKey) +impl core::clone::Clone for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::clone(&self) -> devlaunch_core::flows::records::RecordsNotice +impl core::cmp::Eq for devlaunch_core::flows::records::RecordsNotice +impl core::cmp::PartialEq for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::eq(&self, &devlaunch_core::flows::records::RecordsNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::RecordsNotice pub enum devlaunch_core::api::Removal pub devlaunch_core::api::Removal::Guarded pub devlaunch_core::api::Removal::Insisted pub devlaunch_core::api::Removal::Wedged +impl devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::insistence(self) -> devlaunch_core::flows::lifecycle::Insistence +impl core::clone::Clone for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::clone(&self) -> devlaunch_core::flows::lifecycle::Removal +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Removal +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::eq(&self, &devlaunch_core::flows::lifecycle::Removal) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::Removal +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Removal pub enum devlaunch_core::api::RemovalRefused pub devlaunch_core::api::RemovalRefused::CouldNotTell pub devlaunch_core::api::RemovalRefused::CouldNotTell::cause: devlaunch_core::domain::workspace_state::CouldNotTell @@ -118,6 +195,14 @@ pub devlaunch_core::api::RemovalRefused::CouldNotTell::workspace_id: alloc::stri pub devlaunch_core::api::RemovalRefused::WouldLose pub devlaunch_core::api::RemovalRefused::WouldLose::losses: devlaunch_core::domain::workspace_state::NonEmpty pub devlaunch_core::api::RemovalRefused::WouldLose::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::clone(&self) -> devlaunch_core::flows::lifecycle::RemovalRefused +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemovalRefused +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::eq(&self, &devlaunch_core::flows::lifecycle::RemovalRefused) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemovalRefused pub enum devlaunch_core::api::RemoveOutcome pub devlaunch_core::api::RemoveOutcome::Deleted pub devlaunch_core::api::RemoveOutcome::Deleted::clone: core::result::Result @@ -125,15 +210,45 @@ pub devlaunch_core::api::RemoveOutcome::Deleted::volumes: devlaunch_core::flows: pub devlaunch_core::api::RemoveOutcome::DevpodRefused pub devlaunch_core::api::RemoveOutcome::DevpodRefused::exit: devlaunch_runner::Exit pub devlaunch_core::api::RemoveOutcome::Refused(devlaunch_core::flows::lifecycle::RemovalRefused) +impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::clone(&self) -> devlaunch_core::flows::lifecycle::RemoveOutcome +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemoveOutcome +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::eq(&self, &devlaunch_core::flows::lifecycle::RemoveOutcome) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome pub enum devlaunch_core::api::SpecIdentity<'a> pub devlaunch_core::api::SpecIdentity::ExistingName(&'a str) pub devlaunch_core::api::SpecIdentity::PathLeaf(&'a str) pub devlaunch_core::api::SpecIdentity::RepoLabel(alloc::string::String) pub devlaunch_core::api::SpecIdentity::Workspace(alloc::string::String) +impl<'a> core::clone::Clone for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::clone(&self) -> devlaunch_core::domain::spec::SpecIdentity<'a> +impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::SpecIdentity<'a> +impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::eq(&self, &devlaunch_core::domain::spec::SpecIdentity<'a>) -> bool +impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> pub enum devlaunch_core::api::StartupError pub devlaunch_core::api::StartupError::Config(devlaunch_core::domain::config::ConfigError) pub devlaunch_core::api::StartupError::Metadata(devlaunch_core::domain::metadata::MetadataError) pub devlaunch_core::api::StartupError::NoHomeDirectory +impl core::clone::Clone for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::clone(&self) -> devlaunch_core::flows::records::StartupError +impl core::cmp::Eq for devlaunch_core::flows::records::StartupError +impl core::cmp::PartialEq for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::eq(&self, &devlaunch_core::flows::records::StartupError) -> bool +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self +impl core::fmt::Debug for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::StartupError pub enum devlaunch_core::api::WorkspaceSpec<'a> pub devlaunch_core::api::WorkspaceSpec::ExistingIdOrName(&'a str) pub devlaunch_core::api::WorkspaceSpec::HostPath(&'a str) @@ -144,35 +259,142 @@ pub devlaunch_core::api::WorkspaceSpec::OwnerRepo::repo: &'a str pub devlaunch_core::api::WorkspaceSpec::Path(&'a str) pub devlaunch_core::api::WorkspaceSpec::SshUrl(&'a str) pub devlaunch_core::api::WorkspaceSpec::Url(&'a str) +impl<'a> core::clone::Clone for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::clone(&self) -> devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::eq(&self, &devlaunch_core::domain::spec::WorkspaceSpec<'a>) -> bool +impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::Copy for devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> pub struct devlaunch_core::api::Cold<'a, 'r> pub devlaunch_core::api::Cold::clones: &'a devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> pub devlaunch_core::api::Cold::storage: &'a mut devlaunch_core::domain::metadata::MetadataStorage pub struct devlaunch_core::api::ColdPath<'r, 'e> +impl<'r, 'e> devlaunch_core::flows::launch::ColdPath<'r, 'e> +pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::new(&'r dyn devlaunch_runner::Runner, &'e mut dyn devlaunch_core::notices::Notices) -> Self +pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::records(&mut self) -> core::result::Result<&mut devlaunch_core::flows::records::Records<'r>, devlaunch_core::flows::records::StartupError> +impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> pub struct devlaunch_core::api::CommandContext<'r> +impl<'r> devlaunch_core::flows::listing::CommandContext<'r> +pub fn devlaunch_core::flows::listing::CommandContext<'r>::git(&self) -> devlaunch_core::clients::git::Git<'r> +pub fn devlaunch_core::flows::listing::CommandContext<'r>::new(&'r dyn devlaunch_runner::Runner) -> Self +pub fn devlaunch_core::flows::listing::CommandContext<'r>::workspaces(&mut self) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> pub struct devlaunch_core::api::DevcontainerPath(_) +impl devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::as_str(&self) -> &str +impl core::clone::Clone for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::clone(&self) -> devlaunch_core::domain::spec::DevcontainerPath +impl core::cmp::Eq for devlaunch_core::domain::spec::DevcontainerPath +impl core::cmp::PartialEq for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::eq(&self, &devlaunch_core::domain::spec::DevcontainerPath) -> bool +impl core::fmt::Debug for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::domain::spec::DevcontainerPath pub struct devlaunch_core::api::DevpodHome +impl devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::at(impl core::convert::Into) -> Self +pub fn devlaunch_core::clients::devpod_home::DevpodHome::locate() -> core::option::Option +pub fn devlaunch_core::clients::devpod_home::DevpodHome::path(&self) -> &std::path::Path +impl core::clone::Clone for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::clone(&self) -> devlaunch_core::clients::devpod_home::DevpodHome +impl core::cmp::Eq for devlaunch_core::clients::devpod_home::DevpodHome +impl core::cmp::PartialEq for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::eq(&self, &devlaunch_core::clients::devpod_home::DevpodHome) -> bool +impl core::fmt::Debug for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::clients::devpod_home::DevpodHome pub struct devlaunch_core::api::Host +impl devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::from_process(impl core::convert::Into) -> Self +impl core::clone::Clone for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::clone(&self) -> devlaunch_core::flows::launch::Host +impl core::cmp::Eq for devlaunch_core::flows::launch::Host +impl core::cmp::PartialEq for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::eq(&self, &devlaunch_core::flows::launch::Host) -> bool +impl core::default::Default for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::default() -> devlaunch_core::flows::launch::Host +impl core::fmt::Debug for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::Host pub struct devlaunch_core::api::KeptCopies +impl devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::under(&std::path::Path) -> Self +impl core::clone::Clone for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::clone(&self) -> devlaunch_core::flows::kept_copies::KeptCopies +impl core::cmp::Eq for devlaunch_core::flows::kept_copies::KeptCopies +impl core::cmp::PartialEq for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::eq(&self, &devlaunch_core::flows::kept_copies::KeptCopies) -> bool +impl core::fmt::Debug for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::kept_copies::KeptCopies pub struct devlaunch_core::api::Launch<'a, 'r, 'l> +impl<'a, 'r, 'l> devlaunch_core::flows::launch::Launch<'a, 'r, 'l> +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::new(&'a mut devlaunch_core::flows::listing::CommandContext<'r>, &'a mut devlaunch_core::flows::lifecycle::Refresh<'l>, &'a mut dyn devlaunch_core::flows::launch::ColdMachinery<'r>, &'a dyn devlaunch_core::flows::launch::Provision, &'a devlaunch_core::flows::launch::Host, &'a mut dyn core::ops::function::FnMut(&str), &'a mut dyn devlaunch_core::notices::Notices) -> Self +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::recognised_as(self, core::option::Option) -> Self +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::run(&mut self, &str, &devlaunch_core::flows::launch::LaunchVerb, core::option::Option<&devlaunch_core::domain::spec::DevcontainerPath>) -> core::result::Result pub struct devlaunch_core::api::MetadataStorage +impl devlaunch_core::domain::metadata::MetadataStorage +pub fn devlaunch_core::domain::metadata::MetadataStorage::default_path() -> core::result::Result +pub fn devlaunch_core::domain::metadata::MetadataStorage::look(impl core::convert::Into) -> Self +pub fn devlaunch_core::domain::metadata::MetadataStorage::on_metadata_lock_wait(&mut self, impl core::ops::function::Fn() + 'static) +pub fn devlaunch_core::domain::metadata::MetadataStorage::open(impl core::convert::Into) -> core::result::Result<(Self, alloc::vec::Vec), devlaunch_core::domain::metadata::MetadataError> +impl core::fmt::Debug for devlaunch_core::domain::metadata::MetadataStorage +pub fn devlaunch_core::domain::metadata::MetadataStorage::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub struct devlaunch_core::api::Records<'r> pub devlaunch_core::api::Records::clones: devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> pub devlaunch_core::api::Records::reported: alloc::vec::Vec pub devlaunch_core::api::Records::storage: devlaunch_core::domain::metadata::MetadataStorage pub struct devlaunch_core::api::Refresh<'a> +impl<'a> devlaunch_core::flows::lifecycle::Refresh<'a> +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::ask(&mut self, &dyn devlaunch_runner::Runner, devlaunch_core::flows::lifecycle::RefreshReason) -> devlaunch_core::flows::lifecycle::RefreshSpawn +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::new(&'a devlaunch_core::flows::lifecycle::SelfInvocation, &'a std::path::Path) -> Self +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::rearm(&mut self) +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::spawned(&self) -> bool pub struct devlaunch_core::api::SelfInvocation +impl devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::new(impl core::convert::Into) -> Self +impl core::clone::Clone for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::clone(&self) -> devlaunch_core::flows::lifecycle::SelfInvocation +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::SelfInvocation +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::eq(&self, &devlaunch_core::flows::lifecycle::SelfInvocation) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::SelfInvocation pub struct devlaunch_core::api::ToolProvisioning<'e> +impl<'e> devlaunch_core::flows::launch::ToolProvisioning<'e> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'e>::from_env(&std::path::Path, &'e mut dyn devlaunch_core::notices::Notices) -> Self +impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option pub struct devlaunch_core::api::WorkspaceCloneManager<'r> +impl<'r> devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::in_cache(&std::path::Path, &devlaunch_core::domain::config::WorktreeConfig, devlaunch_core::clients::git::Git<'r>) -> Self +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::on_repo_lock_wait(&mut self, impl core::ops::function::Fn(&str, &str) + 'static) +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::repo_manager(&self) -> &devlaunch_core::flows::repo_manager::RepositoryManager<'r> +impl core::fmt::Debug for devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_> +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub const devlaunch_core::api::HANDOFF_VAR: &str pub const devlaunch_core::api::PREWARM_VAR: &str pub trait devlaunch_core::api::ColdMachinery<'r> pub fn devlaunch_core::api::ColdMachinery::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> pub fn devlaunch_core::api::ColdMachinery::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> +impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> pub trait devlaunch_core::api::Notices pub fn devlaunch_core::api::Notices::say(&mut self, T) +impl devlaunch_core::notices::Notices for alloc::vec::Vec pub trait devlaunch_core::api::Provision pub fn devlaunch_core::api::Provision::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> pub fn devlaunch_core::api::Provision::remembered_claude(&self, &str) -> core::option::Option +impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option pub fn devlaunch_core::api::enriched_listing(&mut devlaunch_core::flows::listing::CommandContext<'_>, &devlaunch_core::flows::listing::DlView<'_>, devlaunch_core::flows::listing::Sizes) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> pub fn devlaunch_core::api::identity(&str) -> core::result::Result, devlaunch_core::domain::workspace_id::UnsafeName> pub fn devlaunch_core::api::json_document(&[devlaunch_core::flows::listing::ListedWorkspace]) -> serde_json::value::Value @@ -180,3 +402,412 @@ pub fn devlaunch_core::api::parse(&str) -> devlaunch_core::domain::spec::Workspa pub fn devlaunch_core::api::resolve_devcontainer_ref(&str) -> core::result::Result pub fn devlaunch_core::api::workspace_remove(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>, &mut devlaunch_core::domain::metadata::MetadataStorage, &std::path::Path, core::option::Option<&devlaunch_core::clients::devpod_home::DevpodHome>, &devlaunch_core::flows::kept_copies::KeptCopies, &str, devlaunch_core::flows::lifecycle::Removal, &mut dyn core::ops::function::FnMut(devlaunch_core::flows::lifecycle::DeleteStalled), &mut dyn devlaunch_core::notices::Notices) -> core::result::Result pub fn devlaunch_core::api::workspace_stop(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &str) -> core::result::Result +pub struct devlaunch_core::clients::devpod_home::DevpodHome +impl devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::at(impl core::convert::Into) -> Self +pub fn devlaunch_core::clients::devpod_home::DevpodHome::locate() -> core::option::Option +pub fn devlaunch_core::clients::devpod_home::DevpodHome::path(&self) -> &std::path::Path +impl core::clone::Clone for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::clone(&self) -> devlaunch_core::clients::devpod_home::DevpodHome +impl core::cmp::Eq for devlaunch_core::clients::devpod_home::DevpodHome +impl core::cmp::PartialEq for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::eq(&self, &devlaunch_core::clients::devpod_home::DevpodHome) -> bool +impl core::fmt::Debug for devlaunch_core::clients::devpod_home::DevpodHome +pub fn devlaunch_core::clients::devpod_home::DevpodHome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::clients::devpod_home::DevpodHome +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self +pub struct devlaunch_core::domain::metadata::MetadataStorage +impl devlaunch_core::domain::metadata::MetadataStorage +pub fn devlaunch_core::domain::metadata::MetadataStorage::default_path() -> core::result::Result +pub fn devlaunch_core::domain::metadata::MetadataStorage::look(impl core::convert::Into) -> Self +pub fn devlaunch_core::domain::metadata::MetadataStorage::on_metadata_lock_wait(&mut self, impl core::ops::function::Fn() + 'static) +pub fn devlaunch_core::domain::metadata::MetadataStorage::open(impl core::convert::Into) -> core::result::Result<(Self, alloc::vec::Vec), devlaunch_core::domain::metadata::MetadataError> +impl core::fmt::Debug for devlaunch_core::domain::metadata::MetadataStorage +pub fn devlaunch_core::domain::metadata::MetadataStorage::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub enum devlaunch_core::domain::spec::SpecIdentity<'a> +pub devlaunch_core::domain::spec::SpecIdentity::ExistingName(&'a str) +pub devlaunch_core::domain::spec::SpecIdentity::PathLeaf(&'a str) +pub devlaunch_core::domain::spec::SpecIdentity::RepoLabel(alloc::string::String) +pub devlaunch_core::domain::spec::SpecIdentity::Workspace(alloc::string::String) +impl<'a> core::clone::Clone for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::clone(&self) -> devlaunch_core::domain::spec::SpecIdentity<'a> +impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::SpecIdentity<'a> +impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::eq(&self, &devlaunch_core::domain::spec::SpecIdentity<'a>) -> bool +impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::SpecIdentity<'a> +pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> +pub enum devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub devlaunch_core::domain::spec::WorkspaceSpec::ExistingIdOrName(&'a str) +pub devlaunch_core::domain::spec::WorkspaceSpec::HostPath(&'a str) +pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo +pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::branch: core::option::Option<&'a str> +pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::owner: &'a str +pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::repo: &'a str +pub devlaunch_core::domain::spec::WorkspaceSpec::Path(&'a str) +pub devlaunch_core::domain::spec::WorkspaceSpec::SshUrl(&'a str) +pub devlaunch_core::domain::spec::WorkspaceSpec::Url(&'a str) +impl<'a> core::clone::Clone for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::clone(&self) -> devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::eq(&self, &devlaunch_core::domain::spec::WorkspaceSpec<'a>) -> bool +impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::Copy for devlaunch_core::domain::spec::WorkspaceSpec<'a> +impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> +pub struct devlaunch_core::domain::spec::DevcontainerPath(_) +impl devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::as_str(&self) -> &str +impl core::clone::Clone for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::clone(&self) -> devlaunch_core::domain::spec::DevcontainerPath +impl core::cmp::Eq for devlaunch_core::domain::spec::DevcontainerPath +impl core::cmp::PartialEq for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::eq(&self, &devlaunch_core::domain::spec::DevcontainerPath) -> bool +impl core::fmt::Debug for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::DevcontainerPath::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::domain::spec::DevcontainerPath +pub fn devlaunch_core::domain::spec::identity(&str) -> core::result::Result, devlaunch_core::domain::workspace_id::UnsafeName> +pub fn devlaunch_core::domain::spec::parse(&str) -> devlaunch_core::domain::spec::WorkspaceSpec<'_> +pub fn devlaunch_core::domain::spec::resolve_devcontainer_ref(&str) -> core::result::Result +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self +pub struct devlaunch_core::flows::kept_copies::KeptCopies +impl devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::under(&std::path::Path) -> Self +impl core::clone::Clone for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::clone(&self) -> devlaunch_core::flows::kept_copies::KeptCopies +impl core::cmp::Eq for devlaunch_core::flows::kept_copies::KeptCopies +impl core::cmp::PartialEq for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::eq(&self, &devlaunch_core::flows::kept_copies::KeptCopies) -> bool +impl core::fmt::Debug for devlaunch_core::flows::kept_copies::KeptCopies +pub fn devlaunch_core::flows::kept_copies::KeptCopies::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::kept_copies::KeptCopies +pub enum devlaunch_core::flows::launch::ColdRefused +pub devlaunch_core::flows::launch::ColdRefused::NoColdPath +pub devlaunch_core::flows::launch::ColdRefused::Startup(devlaunch_core::flows::records::StartupError) +impl core::clone::Clone for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::clone(&self) -> devlaunch_core::flows::launch::ColdRefused +impl core::cmp::Eq for devlaunch_core::flows::launch::ColdRefused +impl core::cmp::PartialEq for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::eq(&self, &devlaunch_core::flows::launch::ColdRefused) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::ColdRefused +pub fn devlaunch_core::flows::launch::ColdRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::ColdRefused +pub enum devlaunch_core::flows::launch::LaunchNotice +pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunning +pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunning::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunningAttaching +pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunningAttaching::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::BroughtUpBySibling +pub devlaunch_core::flows::launch::LaunchNotice::BroughtUpBySibling::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::Cache(devlaunch_core::flows::repo_manager::CacheNotice) +pub devlaunch_core::flows::launch::LaunchNotice::CreateNeverFinished +pub devlaunch_core::flows::launch::LaunchNotice::CreateNeverFinished::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning +pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning::spec: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::DevpodSessionFailed +pub devlaunch_core::flows::launch::LaunchNotice::DevpodSessionFailed::exit: devlaunch_runner::Exit +pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable +pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable::reason: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::Lifecycle(devlaunch_core::flows::lifecycle::LifecycleNotice) +pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig +pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig::looked_in: std::path::PathBuf +pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::NoGitHubToken(devlaunch_core::clients::gh::GhEvent) +pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias +pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias::config: std::path::PathBuf +pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotADirectory +pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotADirectory::source: std::path::PathBuf +pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated +pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated::reason: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated::source: std::path::PathBuf +pub devlaunch_core::flows::launch::LaunchNotice::SshCommand +pub devlaunch_core::flows::launch::LaunchNotice::SshCommand::argv: alloc::vec::Vec +pub devlaunch_core::flows::launch::LaunchNotice::SshConfigUnlocatable +pub devlaunch_core::flows::launch::LaunchNotice::StartingForDotfiles +pub devlaunch_core::flows::launch::LaunchNotice::StartingForDotfiles::workspace_id: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::TerminalTitle(devlaunch_core::flows::launch::TerminalTitle) +pub devlaunch_core::flows::launch::LaunchNotice::TokenNotStaged +pub devlaunch_core::flows::launch::LaunchNotice::TokenNotStaged::reason: alloc::string::String +pub devlaunch_core::flows::launch::LaunchNotice::WaitingForSiblingLaunch +pub devlaunch_core::flows::launch::LaunchNotice::WaitingForSiblingLaunch::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::clone(&self) -> devlaunch_core::flows::launch::LaunchNotice +impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchNotice +impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::eq(&self, &devlaunch_core::flows::launch::LaunchNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchNotice +pub fn devlaunch_core::flows::launch::LaunchNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchNotice +pub enum devlaunch_core::flows::launch::LaunchVerb +pub devlaunch_core::flows::launch::LaunchVerb::Attach +pub devlaunch_core::flows::launch::LaunchVerb::Attach::command: core::option::Option +pub devlaunch_core::flows::launch::LaunchVerb::Code +pub devlaunch_core::flows::launch::LaunchVerb::Dotfiles +pub devlaunch_core::flows::launch::LaunchVerb::Recreate +pub devlaunch_core::flows::launch::LaunchVerb::Reset +pub devlaunch_core::flows::launch::LaunchVerb::Restart +pub devlaunch_core::flows::launch::LaunchVerb::Up +impl core::clone::Clone for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::clone(&self) -> devlaunch_core::flows::launch::LaunchVerb +impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchVerb +impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::eq(&self, &devlaunch_core::flows::launch::LaunchVerb) -> bool +impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchVerb +pub fn devlaunch_core::flows::launch::LaunchVerb::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchVerb +pub struct devlaunch_core::flows::launch::Cold<'a, 'r> +pub devlaunch_core::flows::launch::Cold::clones: &'a devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> +pub devlaunch_core::flows::launch::Cold::storage: &'a mut devlaunch_core::domain::metadata::MetadataStorage +pub struct devlaunch_core::flows::launch::ColdPath<'r, 'e> +impl<'r, 'e> devlaunch_core::flows::launch::ColdPath<'r, 'e> +pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::new(&'r dyn devlaunch_runner::Runner, &'e mut dyn devlaunch_core::notices::Notices) -> Self +pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::records(&mut self) -> core::result::Result<&mut devlaunch_core::flows::records::Records<'r>, devlaunch_core::flows::records::StartupError> +impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> +pub struct devlaunch_core::flows::launch::Host +impl devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::from_process(impl core::convert::Into) -> Self +impl core::clone::Clone for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::clone(&self) -> devlaunch_core::flows::launch::Host +impl core::cmp::Eq for devlaunch_core::flows::launch::Host +impl core::cmp::PartialEq for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::eq(&self, &devlaunch_core::flows::launch::Host) -> bool +impl core::default::Default for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::default() -> devlaunch_core::flows::launch::Host +impl core::fmt::Debug for devlaunch_core::flows::launch::Host +pub fn devlaunch_core::flows::launch::Host::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::Host +pub struct devlaunch_core::flows::launch::Launch<'a, 'r, 'l> +impl<'a, 'r, 'l> devlaunch_core::flows::launch::Launch<'a, 'r, 'l> +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::new(&'a mut devlaunch_core::flows::listing::CommandContext<'r>, &'a mut devlaunch_core::flows::lifecycle::Refresh<'l>, &'a mut dyn devlaunch_core::flows::launch::ColdMachinery<'r>, &'a dyn devlaunch_core::flows::launch::Provision, &'a devlaunch_core::flows::launch::Host, &'a mut dyn core::ops::function::FnMut(&str), &'a mut dyn devlaunch_core::notices::Notices) -> Self +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::recognised_as(self, core::option::Option) -> Self +pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::run(&mut self, &str, &devlaunch_core::flows::launch::LaunchVerb, core::option::Option<&devlaunch_core::domain::spec::DevcontainerPath>) -> core::result::Result +pub struct devlaunch_core::flows::launch::ToolProvisioning<'e> +impl<'e> devlaunch_core::flows::launch::ToolProvisioning<'e> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'e>::from_env(&std::path::Path, &'e mut dyn devlaunch_core::notices::Notices) -> Self +impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option +pub trait devlaunch_core::flows::launch::ColdMachinery<'r> +pub fn devlaunch_core::flows::launch::ColdMachinery::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> +pub fn devlaunch_core::flows::launch::ColdMachinery::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> +impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> +pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> +pub trait devlaunch_core::flows::launch::Provision +pub fn devlaunch_core::flows::launch::Provision::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> +pub fn devlaunch_core::flows::launch::Provision::remembered_claude(&self, &str) -> core::option::Option +impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> +pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option +pub enum devlaunch_core::flows::lifecycle::DeleteStalled +pub devlaunch_core::flows::lifecycle::DeleteStalled::OnTheLock +impl core::clone::Clone for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::clone(&self) -> devlaunch_core::flows::lifecycle::DeleteStalled +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::DeleteStalled +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::eq(&self, &devlaunch_core::flows::lifecycle::DeleteStalled) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::DeleteStalled +pub fn devlaunch_core::flows::lifecycle::DeleteStalled::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::DeleteStalled +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::DeleteStalled +pub enum devlaunch_core::flows::lifecycle::Insistence +pub devlaunch_core::flows::lifecycle::Insistence::Insisted +pub devlaunch_core::flows::lifecycle::Insistence::NotInsisted +impl core::clone::Clone for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::clone(&self) -> devlaunch_core::flows::lifecycle::Insistence +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Insistence +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::eq(&self, &devlaunch_core::flows::lifecycle::Insistence) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Insistence +pub fn devlaunch_core::flows::lifecycle::Insistence::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::Insistence +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Insistence +pub enum devlaunch_core::flows::lifecycle::LifecycleNotice +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::branch: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::derived: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::owner: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::recorded: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::repo: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::Cache(devlaunch_core::flows::repo_manager::CacheNotice) +pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved +pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved::refusal: devlaunch_core::flows::workspace_clone::RemoveWorkspaceError +pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved::workspace_id: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneRemoved +pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneRemoved::workspace_id: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped +pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped::path: std::path::PathBuf +pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped::refusal: devlaunch_core::domain::metadata::MetadataError +pub devlaunch_core::flows::lifecycle::LifecycleNotice::Removing +pub devlaunch_core::flows::lifecycle::LifecycleNotice::Removing::workspace_id: alloc::string::String +pub devlaunch_core::flows::lifecycle::LifecycleNotice::RemovingOverWork +pub devlaunch_core::flows::lifecycle::LifecycleNotice::RemovingOverWork::refusal: devlaunch_core::flows::lifecycle::RemovalRefused +pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved +pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::occasion: devlaunch_core::flows::lifecycle::SweepOccasion +pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::refusal: devlaunch_core::flows::lifecycle::VolumeRefusal +pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::clone(&self) -> devlaunch_core::flows::lifecycle::LifecycleNotice +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::LifecycleNotice +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::eq(&self, &devlaunch_core::flows::lifecycle::LifecycleNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::LifecycleNotice +pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice +pub enum devlaunch_core::flows::lifecycle::Removal +pub devlaunch_core::flows::lifecycle::Removal::Guarded +pub devlaunch_core::flows::lifecycle::Removal::Insisted +pub devlaunch_core::flows::lifecycle::Removal::Wedged +impl devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::insistence(self) -> devlaunch_core::flows::lifecycle::Insistence +impl core::clone::Clone for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::clone(&self) -> devlaunch_core::flows::lifecycle::Removal +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Removal +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::eq(&self, &devlaunch_core::flows::lifecycle::Removal) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Removal +pub fn devlaunch_core::flows::lifecycle::Removal::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for devlaunch_core::flows::lifecycle::Removal +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Removal +pub enum devlaunch_core::flows::lifecycle::RemovalRefused +pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell +pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell::cause: devlaunch_core::domain::workspace_state::CouldNotTell +pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell::workspace_id: alloc::string::String +pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose +pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose::losses: devlaunch_core::domain::workspace_state::NonEmpty +pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose::workspace_id: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::clone(&self) -> devlaunch_core::flows::lifecycle::RemovalRefused +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemovalRefused +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::eq(&self, &devlaunch_core::flows::lifecycle::RemovalRefused) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemovalRefused +pub fn devlaunch_core::flows::lifecycle::RemovalRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemovalRefused +pub enum devlaunch_core::flows::lifecycle::RemoveOutcome +pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted +pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted::clone: core::result::Result +pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted::volumes: devlaunch_core::flows::lifecycle::VolumeSweep +pub devlaunch_core::flows::lifecycle::RemoveOutcome::DevpodRefused +pub devlaunch_core::flows::lifecycle::RemoveOutcome::DevpodRefused::exit: devlaunch_runner::Exit +pub devlaunch_core::flows::lifecycle::RemoveOutcome::Refused(devlaunch_core::flows::lifecycle::RemovalRefused) +impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::clone(&self) -> devlaunch_core::flows::lifecycle::RemoveOutcome +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemoveOutcome +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::eq(&self, &devlaunch_core::flows::lifecycle::RemoveOutcome) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemoveOutcome +pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome +pub struct devlaunch_core::flows::lifecycle::Refresh<'a> +impl<'a> devlaunch_core::flows::lifecycle::Refresh<'a> +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::ask(&mut self, &dyn devlaunch_runner::Runner, devlaunch_core::flows::lifecycle::RefreshReason) -> devlaunch_core::flows::lifecycle::RefreshSpawn +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::new(&'a devlaunch_core::flows::lifecycle::SelfInvocation, &'a std::path::Path) -> Self +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::rearm(&mut self) +pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::spawned(&self) -> bool +pub struct devlaunch_core::flows::lifecycle::SelfInvocation +impl devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::new(impl core::convert::Into) -> Self +impl core::clone::Clone for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::clone(&self) -> devlaunch_core::flows::lifecycle::SelfInvocation +impl core::cmp::Eq for devlaunch_core::flows::lifecycle::SelfInvocation +impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::eq(&self, &devlaunch_core::flows::lifecycle::SelfInvocation) -> bool +impl core::fmt::Debug for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::SelfInvocation::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::SelfInvocation +pub fn devlaunch_core::flows::lifecycle::workspace_remove(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>, &mut devlaunch_core::domain::metadata::MetadataStorage, &std::path::Path, core::option::Option<&devlaunch_core::clients::devpod_home::DevpodHome>, &devlaunch_core::flows::kept_copies::KeptCopies, &str, devlaunch_core::flows::lifecycle::Removal, &mut dyn core::ops::function::FnMut(devlaunch_core::flows::lifecycle::DeleteStalled), &mut dyn devlaunch_core::notices::Notices) -> core::result::Result +pub fn devlaunch_core::flows::lifecycle::workspace_stop(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &str) -> core::result::Result +pub struct devlaunch_core::flows::listing::CommandContext<'r> +impl<'r> devlaunch_core::flows::listing::CommandContext<'r> +pub fn devlaunch_core::flows::listing::CommandContext<'r>::git(&self) -> devlaunch_core::clients::git::Git<'r> +pub fn devlaunch_core::flows::listing::CommandContext<'r>::new(&'r dyn devlaunch_runner::Runner) -> Self +pub fn devlaunch_core::flows::listing::CommandContext<'r>::workspaces(&mut self) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> +pub fn devlaunch_core::flows::listing::enriched_listing(&mut devlaunch_core::flows::listing::CommandContext<'_>, &devlaunch_core::flows::listing::DlView<'_>, devlaunch_core::flows::listing::Sizes) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> +pub fn devlaunch_core::flows::listing::json_document(&[devlaunch_core::flows::listing::ListedWorkspace]) -> serde_json::value::Value +pub enum devlaunch_core::flows::provision::ProvisionEvent +pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled +pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::exit: devlaunch_runner::Exit +pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::tools: alloc::vec::Vec<&'static str> +pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::workspace: alloc::string::String +pub devlaunch_core::flows::provision::ProvisionEvent::PayloadNotBundled +pub devlaunch_core::flows::provision::ProvisionEvent::PayloadNotBundled::failure: devlaunch_core::flows::provision::BundleFailed +pub devlaunch_core::flows::provision::ProvisionEvent::ProvisioningDisabled +pub devlaunch_core::flows::provision::ProvisionEvent::ProvisioningDisabled::workspace: alloc::string::String +pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed +pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::loudness: devlaunch_core::flows::provision::FailureLevel +pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::stage: &'static str +pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::status: i32 +pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::workspace: alloc::string::String +pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported +pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::loudness: devlaunch_core::flows::provision::FailureLevel +pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::stage: &'static str +pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::workspace: alloc::string::String +pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused +pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused::refusal: devlaunch_core::clients::devpod::NotRun +pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused::workspace: alloc::string::String +impl core::clone::Clone for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::clone(&self) -> devlaunch_core::flows::provision::ProvisionEvent +impl core::cmp::Eq for devlaunch_core::flows::provision::ProvisionEvent +impl core::cmp::PartialEq for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::eq(&self, &devlaunch_core::flows::provision::ProvisionEvent) -> bool +impl core::fmt::Debug for devlaunch_core::flows::provision::ProvisionEvent +pub fn devlaunch_core::flows::provision::ProvisionEvent::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::ProvisionEvent +pub enum devlaunch_core::flows::records::RecordsNotice +pub devlaunch_core::flows::records::RecordsNotice::Metadata(devlaunch_core::domain::metadata::Notice) +pub devlaunch_core::flows::records::RecordsNotice::Migrated(devlaunch_core::flows::migration::MigrationReport) +pub devlaunch_core::flows::records::RecordsNotice::MigrationRefused(devlaunch_core::domain::metadata::MetadataError) +pub devlaunch_core::flows::records::RecordsNotice::RetiredKey(devlaunch_core::domain::config::RetiredKey) +impl core::clone::Clone for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::clone(&self) -> devlaunch_core::flows::records::RecordsNotice +impl core::cmp::Eq for devlaunch_core::flows::records::RecordsNotice +impl core::cmp::PartialEq for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::eq(&self, &devlaunch_core::flows::records::RecordsNotice) -> bool +impl core::fmt::Debug for devlaunch_core::flows::records::RecordsNotice +pub fn devlaunch_core::flows::records::RecordsNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::RecordsNotice +pub enum devlaunch_core::flows::records::StartupError +pub devlaunch_core::flows::records::StartupError::Config(devlaunch_core::domain::config::ConfigError) +pub devlaunch_core::flows::records::StartupError::Metadata(devlaunch_core::domain::metadata::MetadataError) +pub devlaunch_core::flows::records::StartupError::NoHomeDirectory +impl core::clone::Clone for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::clone(&self) -> devlaunch_core::flows::records::StartupError +impl core::cmp::Eq for devlaunch_core::flows::records::StartupError +impl core::cmp::PartialEq for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::eq(&self, &devlaunch_core::flows::records::StartupError) -> bool +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self +impl core::convert::From for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self +impl core::fmt::Debug for devlaunch_core::flows::records::StartupError +pub fn devlaunch_core::flows::records::StartupError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::StartupError +pub struct devlaunch_core::flows::records::Records<'r> +pub devlaunch_core::flows::records::Records::clones: devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> +pub devlaunch_core::flows::records::Records::reported: alloc::vec::Vec +pub devlaunch_core::flows::records::Records::storage: devlaunch_core::domain::metadata::MetadataStorage +pub struct devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> +impl<'r> devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::in_cache(&std::path::Path, &devlaunch_core::domain::config::WorktreeConfig, devlaunch_core::clients::git::Git<'r>) -> Self +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::on_repo_lock_wait(&mut self, impl core::ops::function::Fn(&str, &str) + 'static) +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::repo_manager(&self) -> &devlaunch_core::flows::repo_manager::RepositoryManager<'r> +impl core::fmt::Debug for devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_> +pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub trait devlaunch_core::notices::Notices +pub fn devlaunch_core::notices::Notices::say(&mut self, T) +impl devlaunch_core::notices::Notices for alloc::vec::Vec +pub const devlaunch_core::timing::HANDOFF_VAR: &str +pub const devlaunch_core::timing::PREWARM_VAR: &str diff --git a/rust/devlaunch-core/public-api.rest.txt b/rust/devlaunch-core/public-api.rest.txt index f9b262d..b95d57f 100644 --- a/rust/devlaunch-core/public-api.rest.txt +++ b/rust/devlaunch-core/public-api.rest.txt @@ -1,226 +1,5 @@ pub mod devlaunch_core -impl core::clone::Clone for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::clone(&self) -> devlaunch_core::flows::launch::ColdRefused -impl core::cmp::Eq for devlaunch_core::flows::launch::ColdRefused -impl core::cmp::PartialEq for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::eq(&self, &devlaunch_core::flows::launch::ColdRefused) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::ColdRefused -impl core::clone::Clone for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::clone(&self) -> devlaunch_core::flows::lifecycle::DeleteStalled -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::DeleteStalled -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::eq(&self, &devlaunch_core::flows::lifecycle::DeleteStalled) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::DeleteStalled -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::DeleteStalled -impl core::clone::Clone for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::clone(&self) -> devlaunch_core::flows::lifecycle::Insistence -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Insistence -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::eq(&self, &devlaunch_core::flows::lifecycle::Insistence) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::Insistence -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Insistence -impl core::clone::Clone for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::clone(&self) -> devlaunch_core::flows::launch::LaunchNotice -impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchNotice -impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::eq(&self, &devlaunch_core::flows::launch::LaunchNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchNotice -impl core::clone::Clone for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::clone(&self) -> devlaunch_core::flows::launch::LaunchVerb -impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchVerb -impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::eq(&self, &devlaunch_core::flows::launch::LaunchVerb) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchVerb -impl core::clone::Clone for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::clone(&self) -> devlaunch_core::flows::lifecycle::LifecycleNotice -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::LifecycleNotice -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::eq(&self, &devlaunch_core::flows::lifecycle::LifecycleNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice -impl core::clone::Clone for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::clone(&self) -> devlaunch_core::flows::provision::ProvisionEvent -impl core::cmp::Eq for devlaunch_core::flows::provision::ProvisionEvent -impl core::cmp::PartialEq for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::eq(&self, &devlaunch_core::flows::provision::ProvisionEvent) -> bool -impl core::fmt::Debug for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::ProvisionEvent -impl core::clone::Clone for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::clone(&self) -> devlaunch_core::flows::records::RecordsNotice -impl core::cmp::Eq for devlaunch_core::flows::records::RecordsNotice -impl core::cmp::PartialEq for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::eq(&self, &devlaunch_core::flows::records::RecordsNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::RecordsNotice -impl devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::insistence(self) -> devlaunch_core::flows::lifecycle::Insistence -impl core::clone::Clone for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::clone(&self) -> devlaunch_core::flows::lifecycle::Removal -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Removal -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::eq(&self, &devlaunch_core::flows::lifecycle::Removal) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::Removal -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Removal -impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::clone(&self) -> devlaunch_core::flows::lifecycle::RemovalRefused -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemovalRefused -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::eq(&self, &devlaunch_core::flows::lifecycle::RemovalRefused) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemovalRefused -impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::clone(&self) -> devlaunch_core::flows::lifecycle::RemoveOutcome -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemoveOutcome -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::eq(&self, &devlaunch_core::flows::lifecycle::RemoveOutcome) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome -impl<'a> core::clone::Clone for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::clone(&self) -> devlaunch_core::domain::spec::SpecIdentity<'a> -impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::SpecIdentity<'a> -impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::eq(&self, &devlaunch_core::domain::spec::SpecIdentity<'a>) -> bool -impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> -impl core::clone::Clone for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::clone(&self) -> devlaunch_core::flows::records::StartupError -impl core::cmp::Eq for devlaunch_core::flows::records::StartupError -impl core::cmp::PartialEq for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::eq(&self, &devlaunch_core::flows::records::StartupError) -> bool -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self -impl core::fmt::Debug for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::StartupError -impl<'a> core::clone::Clone for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::clone(&self) -> devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::eq(&self, &devlaunch_core::domain::spec::WorkspaceSpec<'a>) -> bool -impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'a> core::marker::Copy for devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'r, 'e> devlaunch_core::flows::launch::ColdPath<'r, 'e> -pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::new(&'r dyn devlaunch_runner::Runner, &'e mut dyn devlaunch_core::notices::Notices) -> Self -pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::records(&mut self) -> core::result::Result<&mut devlaunch_core::flows::records::Records<'r>, devlaunch_core::flows::records::StartupError> -impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> -impl<'r> devlaunch_core::flows::listing::CommandContext<'r> -pub fn devlaunch_core::flows::listing::CommandContext<'r>::git(&self) -> devlaunch_core::clients::git::Git<'r> -pub fn devlaunch_core::flows::listing::CommandContext<'r>::new(&'r dyn devlaunch_runner::Runner) -> Self -pub fn devlaunch_core::flows::listing::CommandContext<'r>::workspaces(&mut self) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> -impl devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::as_str(&self) -> &str -impl core::clone::Clone for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::clone(&self) -> devlaunch_core::domain::spec::DevcontainerPath -impl core::cmp::Eq for devlaunch_core::domain::spec::DevcontainerPath -impl core::cmp::PartialEq for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::eq(&self, &devlaunch_core::domain::spec::DevcontainerPath) -> bool -impl core::fmt::Debug for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::domain::spec::DevcontainerPath -impl devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::at(impl core::convert::Into) -> Self -pub fn devlaunch_core::clients::devpod_home::DevpodHome::locate() -> core::option::Option -pub fn devlaunch_core::clients::devpod_home::DevpodHome::path(&self) -> &std::path::Path -impl core::clone::Clone for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::clone(&self) -> devlaunch_core::clients::devpod_home::DevpodHome -impl core::cmp::Eq for devlaunch_core::clients::devpod_home::DevpodHome -impl core::cmp::PartialEq for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::eq(&self, &devlaunch_core::clients::devpod_home::DevpodHome) -> bool -impl core::fmt::Debug for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::clients::devpod_home::DevpodHome -impl devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::from_process(impl core::convert::Into) -> Self -impl core::clone::Clone for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::clone(&self) -> devlaunch_core::flows::launch::Host -impl core::cmp::Eq for devlaunch_core::flows::launch::Host -impl core::cmp::PartialEq for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::eq(&self, &devlaunch_core::flows::launch::Host) -> bool -impl core::default::Default for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::default() -> devlaunch_core::flows::launch::Host -impl core::fmt::Debug for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::Host -impl devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::under(&std::path::Path) -> Self -impl core::clone::Clone for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::clone(&self) -> devlaunch_core::flows::kept_copies::KeptCopies -impl core::cmp::Eq for devlaunch_core::flows::kept_copies::KeptCopies -impl core::cmp::PartialEq for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::eq(&self, &devlaunch_core::flows::kept_copies::KeptCopies) -> bool -impl core::fmt::Debug for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::kept_copies::KeptCopies -impl<'a, 'r, 'l> devlaunch_core::flows::launch::Launch<'a, 'r, 'l> -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::new(&'a mut devlaunch_core::flows::listing::CommandContext<'r>, &'a mut devlaunch_core::flows::lifecycle::Refresh<'l>, &'a mut dyn devlaunch_core::flows::launch::ColdMachinery<'r>, &'a dyn devlaunch_core::flows::launch::Provision, &'a devlaunch_core::flows::launch::Host, &'a mut dyn core::ops::function::FnMut(&str), &'a mut dyn devlaunch_core::notices::Notices) -> Self -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::recognised_as(self, core::option::Option) -> Self -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::run(&mut self, &str, &devlaunch_core::flows::launch::LaunchVerb, core::option::Option<&devlaunch_core::domain::spec::DevcontainerPath>) -> core::result::Result -impl devlaunch_core::domain::metadata::MetadataStorage -pub fn devlaunch_core::domain::metadata::MetadataStorage::default_path() -> core::result::Result -pub fn devlaunch_core::domain::metadata::MetadataStorage::on_metadata_lock_wait(&mut self, impl core::ops::function::Fn() + 'static) -pub fn devlaunch_core::domain::metadata::MetadataStorage::open(impl core::convert::Into) -> core::result::Result<(Self, alloc::vec::Vec), devlaunch_core::domain::metadata::MetadataError> -impl core::fmt::Debug for devlaunch_core::domain::metadata::MetadataStorage -pub fn devlaunch_core::domain::metadata::MetadataStorage::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'a> devlaunch_core::flows::lifecycle::Refresh<'a> -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::ask(&mut self, &dyn devlaunch_runner::Runner, devlaunch_core::flows::lifecycle::RefreshReason) -> devlaunch_core::flows::lifecycle::RefreshSpawn -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::new(&'a devlaunch_core::flows::lifecycle::SelfInvocation, &'a std::path::Path) -> Self -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::rearm(&mut self) -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::spawned(&self) -> bool -impl devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::new(impl core::convert::Into) -> Self -impl core::clone::Clone for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::clone(&self) -> devlaunch_core::flows::lifecycle::SelfInvocation -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::SelfInvocation -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::eq(&self, &devlaunch_core::flows::lifecycle::SelfInvocation) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::SelfInvocation -impl<'e> devlaunch_core::flows::launch::ToolProvisioning<'e> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'e>::from_env(&std::path::Path, &'e mut dyn devlaunch_core::notices::Notices) -> Self -impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option -impl<'r> devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::in_cache(&std::path::Path, &devlaunch_core::domain::config::WorktreeConfig, devlaunch_core::clients::git::Git<'r>) -> Self -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::on_repo_lock_wait(&mut self, impl core::ops::function::Fn(&str, &str) + 'static) -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::repo_manager(&self) -> &devlaunch_core::flows::repo_manager::RepositoryManager<'r> -impl core::fmt::Debug for devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_> -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> -impl devlaunch_core::notices::Notices for alloc::vec::Vec pub fn alloc::vec::Vec::say(&mut self, T) -impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option pub mod devlaunch_core::clients pub mod devlaunch_core::clients::devpod pub enum devlaunch_core::clients::devpod::ContainerState @@ -360,19 +139,6 @@ pub fn devlaunch_core::clients::devpod_home::RepointFailure::eq(&self, &devlaunc impl core::fmt::Debug for devlaunch_core::clients::devpod_home::RepointFailure pub fn devlaunch_core::clients::devpod_home::RepointFailure::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::clients::devpod_home::RepointFailure -pub struct devlaunch_core::clients::devpod_home::DevpodHome -impl devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::at(impl core::convert::Into) -> Self -pub fn devlaunch_core::clients::devpod_home::DevpodHome::locate() -> core::option::Option -pub fn devlaunch_core::clients::devpod_home::DevpodHome::path(&self) -> &std::path::Path -impl core::clone::Clone for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::clone(&self) -> devlaunch_core::clients::devpod_home::DevpodHome -impl core::cmp::Eq for devlaunch_core::clients::devpod_home::DevpodHome -impl core::cmp::PartialEq for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::eq(&self, &devlaunch_core::clients::devpod_home::DevpodHome) -> bool -impl core::fmt::Debug for devlaunch_core::clients::devpod_home::DevpodHome -pub fn devlaunch_core::clients::devpod_home::DevpodHome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::clients::devpod_home::DevpodHome pub mod devlaunch_core::clients::gh pub enum devlaunch_core::clients::gh::GhEvent pub devlaunch_core::clients::gh::GhEvent::CouldNotRun(devlaunch_core::clients::gh::GhUnavailable) @@ -482,8 +248,6 @@ pub fn devlaunch_core::domain::config::ConfigError::clone(&self) -> devlaunch_co impl core::cmp::Eq for devlaunch_core::domain::config::ConfigError impl core::cmp::PartialEq for devlaunch_core::domain::config::ConfigError pub fn devlaunch_core::domain::config::ConfigError::eq(&self, &devlaunch_core::domain::config::ConfigError) -> bool -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self impl core::convert::From for devlaunch_core::domain::config::ConfigError pub fn devlaunch_core::domain::config::ConfigError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self impl core::fmt::Debug for devlaunch_core::domain::config::ConfigError @@ -602,8 +366,6 @@ pub fn devlaunch_core::domain::metadata::MetadataError::clone(&self) -> devlaunc impl core::cmp::Eq for devlaunch_core::domain::metadata::MetadataError impl core::cmp::PartialEq for devlaunch_core::domain::metadata::MetadataError pub fn devlaunch_core::domain::metadata::MetadataError::eq(&self, &devlaunch_core::domain::metadata::MetadataError) -> bool -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self impl core::fmt::Debug for devlaunch_core::domain::metadata::MetadataError pub fn devlaunch_core::domain::metadata::MetadataError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::domain::metadata::MetadataError @@ -675,14 +437,6 @@ impl core::fmt::Debug for devlaunch_core::domain::metadata::Section pub fn devlaunch_core::domain::metadata::Section::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::domain::metadata::Section impl core::marker::StructuralPartialEq for devlaunch_core::domain::metadata::Section -pub struct devlaunch_core::domain::metadata::MetadataStorage -impl devlaunch_core::domain::metadata::MetadataStorage -pub fn devlaunch_core::domain::metadata::MetadataStorage::default_path() -> core::result::Result -pub fn devlaunch_core::domain::metadata::MetadataStorage::look(impl core::convert::Into) -> Self -pub fn devlaunch_core::domain::metadata::MetadataStorage::on_metadata_lock_wait(&mut self, impl core::ops::function::Fn() + 'static) -pub fn devlaunch_core::domain::metadata::MetadataStorage::open(impl core::convert::Into) -> core::result::Result<(Self, alloc::vec::Vec), devlaunch_core::domain::metadata::MetadataError> -impl core::fmt::Debug for devlaunch_core::domain::metadata::MetadataStorage -pub fn devlaunch_core::domain::metadata::MetadataStorage::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub struct devlaunch_core::domain::metadata::OsFailure pub devlaunch_core::domain::metadata::OsFailure::kind: core::io::error::ErrorKind pub devlaunch_core::domain::metadata::OsFailure::message: alloc::string::String @@ -755,52 +509,6 @@ impl core::fmt::Debug for devlaunch_core::domain::spec::DevcontainerRefError pub fn devlaunch_core::domain::spec::DevcontainerRefError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::domain::spec::DevcontainerRefError impl core::marker::StructuralPartialEq for devlaunch_core::domain::spec::DevcontainerRefError -pub enum devlaunch_core::domain::spec::SpecIdentity<'a> -pub devlaunch_core::domain::spec::SpecIdentity::ExistingName(&'a str) -pub devlaunch_core::domain::spec::SpecIdentity::PathLeaf(&'a str) -pub devlaunch_core::domain::spec::SpecIdentity::RepoLabel(alloc::string::String) -pub devlaunch_core::domain::spec::SpecIdentity::Workspace(alloc::string::String) -impl<'a> core::clone::Clone for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::clone(&self) -> devlaunch_core::domain::spec::SpecIdentity<'a> -impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::SpecIdentity<'a> -impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::eq(&self, &devlaunch_core::domain::spec::SpecIdentity<'a>) -> bool -impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::SpecIdentity<'a> -pub fn devlaunch_core::domain::spec::SpecIdentity<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::SpecIdentity<'a> -pub enum devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub devlaunch_core::domain::spec::WorkspaceSpec::ExistingIdOrName(&'a str) -pub devlaunch_core::domain::spec::WorkspaceSpec::HostPath(&'a str) -pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo -pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::branch: core::option::Option<&'a str> -pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::owner: &'a str -pub devlaunch_core::domain::spec::WorkspaceSpec::OwnerRepo::repo: &'a str -pub devlaunch_core::domain::spec::WorkspaceSpec::Path(&'a str) -pub devlaunch_core::domain::spec::WorkspaceSpec::SshUrl(&'a str) -pub devlaunch_core::domain::spec::WorkspaceSpec::Url(&'a str) -impl<'a> core::clone::Clone for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::clone(&self) -> devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::cmp::Eq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::cmp::PartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::eq(&self, &devlaunch_core::domain::spec::WorkspaceSpec<'a>) -> bool -impl<'a> core::fmt::Debug for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub fn devlaunch_core::domain::spec::WorkspaceSpec<'a>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl<'a> core::marker::Copy for devlaunch_core::domain::spec::WorkspaceSpec<'a> -impl<'a> core::marker::StructuralPartialEq for devlaunch_core::domain::spec::WorkspaceSpec<'a> -pub struct devlaunch_core::domain::spec::DevcontainerPath(_) -impl devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::as_str(&self) -> &str -impl core::clone::Clone for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::clone(&self) -> devlaunch_core::domain::spec::DevcontainerPath -impl core::cmp::Eq for devlaunch_core::domain::spec::DevcontainerPath -impl core::cmp::PartialEq for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::eq(&self, &devlaunch_core::domain::spec::DevcontainerPath) -> bool -impl core::fmt::Debug for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::DevcontainerPath::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::domain::spec::DevcontainerPath -pub fn devlaunch_core::domain::spec::identity(&str) -> core::result::Result, devlaunch_core::domain::workspace_id::UnsafeName> -pub fn devlaunch_core::domain::spec::parse(&str) -> devlaunch_core::domain::spec::WorkspaceSpec<'_> -pub fn devlaunch_core::domain::spec::resolve_devcontainer_ref(&str) -> core::result::Result pub mod devlaunch_core::domain::workspace_id pub enum devlaunch_core::domain::workspace_id::NamePart pub devlaunch_core::domain::workspace_id::NamePart::Owner @@ -929,8 +637,6 @@ impl core::convert::From for devla pub fn devlaunch_core::domain::config::ConfigError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self impl core::convert::From for devlaunch_core::flows::completion::InstallError pub fn devlaunch_core::flows::completion::InstallError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self impl core::fmt::Debug for devlaunch_core::domain::xdg::NoHomeDirectory pub fn devlaunch_core::domain::xdg::NoHomeDirectory::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::domain::xdg::NoHomeDirectory @@ -1077,17 +783,6 @@ pub fn devlaunch_core::flows::disk_usage::DiskUsage::fmt(&self, &mut core::fmt:: impl core::marker::StructuralPartialEq for devlaunch_core::flows::disk_usage::DiskUsage pub fn devlaunch_core::flows::disk_usage::describe_usage(&devlaunch_core::flows::disk_usage::DiskUsage) -> alloc::string::String pub mod devlaunch_core::flows::kept_copies -pub struct devlaunch_core::flows::kept_copies::KeptCopies -impl devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::under(&std::path::Path) -> Self -impl core::clone::Clone for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::clone(&self) -> devlaunch_core::flows::kept_copies::KeptCopies -impl core::cmp::Eq for devlaunch_core::flows::kept_copies::KeptCopies -impl core::cmp::PartialEq for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::eq(&self, &devlaunch_core::flows::kept_copies::KeptCopies) -> bool -impl core::fmt::Debug for devlaunch_core::flows::kept_copies::KeptCopies -pub fn devlaunch_core::flows::kept_copies::KeptCopies::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::kept_copies::KeptCopies pub mod devlaunch_core::flows::kill pub enum devlaunch_core::flows::kill::ContainerRefusal pub devlaunch_core::flows::kill::ContainerRefusal::NotRun @@ -1273,17 +968,6 @@ pub fn devlaunch_core::flows::launch::BranchNotNamed::eq(&self, &devlaunch_core: impl core::fmt::Debug for devlaunch_core::flows::launch::BranchNotNamed pub fn devlaunch_core::flows::launch::BranchNotNamed::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::BranchNotNamed -pub enum devlaunch_core::flows::launch::ColdRefused -pub devlaunch_core::flows::launch::ColdRefused::NoColdPath -pub devlaunch_core::flows::launch::ColdRefused::Startup(devlaunch_core::flows::records::StartupError) -impl core::clone::Clone for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::clone(&self) -> devlaunch_core::flows::launch::ColdRefused -impl core::cmp::Eq for devlaunch_core::flows::launch::ColdRefused -impl core::cmp::PartialEq for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::eq(&self, &devlaunch_core::flows::launch::ColdRefused) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::ColdRefused -pub fn devlaunch_core::flows::launch::ColdRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::ColdRefused pub enum devlaunch_core::flows::launch::LaunchAborted pub devlaunch_core::flows::launch::LaunchAborted::DevpodNotRun(devlaunch_core::clients::devpod::NotRun) pub devlaunch_core::flows::launch::LaunchAborted::ListingUnreadable(devlaunch_core::clients::devpod::ListingUnreadable) @@ -1296,55 +980,6 @@ pub fn devlaunch_core::flows::launch::LaunchAborted::eq(&self, &devlaunch_core:: impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchAborted pub fn devlaunch_core::flows::launch::LaunchAborted::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchAborted -pub enum devlaunch_core::flows::launch::LaunchNotice -pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunning -pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunning::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunningAttaching -pub devlaunch_core::flows::launch::LaunchNotice::AlreadyRunningAttaching::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::BroughtUpBySibling -pub devlaunch_core::flows::launch::LaunchNotice::BroughtUpBySibling::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::Cache(devlaunch_core::flows::repo_manager::CacheNotice) -pub devlaunch_core::flows::launch::LaunchNotice::CreateNeverFinished -pub devlaunch_core::flows::launch::LaunchNotice::CreateNeverFinished::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning -pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning::spec: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::DevcontainerIgnoredRunning::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::DevpodSessionFailed -pub devlaunch_core::flows::launch::LaunchNotice::DevpodSessionFailed::exit: devlaunch_runner::Exit -pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable -pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable::reason: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::LaunchLockUnavailable::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::Lifecycle(devlaunch_core::flows::lifecycle::LifecycleNotice) -pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig -pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig::looked_in: std::path::PathBuf -pub devlaunch_core::flows::launch::LaunchNotice::NoDevpodSshConfig::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::NoGitHubToken(devlaunch_core::clients::gh::GhEvent) -pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias -pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias::config: std::path::PathBuf -pub devlaunch_core::flows::launch::LaunchNotice::NoTerminalAlias::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotADirectory -pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotADirectory::source: std::path::PathBuf -pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated -pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated::reason: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::PixiCacheNotCreated::source: std::path::PathBuf -pub devlaunch_core::flows::launch::LaunchNotice::SshCommand -pub devlaunch_core::flows::launch::LaunchNotice::SshCommand::argv: alloc::vec::Vec -pub devlaunch_core::flows::launch::LaunchNotice::SshConfigUnlocatable -pub devlaunch_core::flows::launch::LaunchNotice::StartingForDotfiles -pub devlaunch_core::flows::launch::LaunchNotice::StartingForDotfiles::workspace_id: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::TerminalTitle(devlaunch_core::flows::launch::TerminalTitle) -pub devlaunch_core::flows::launch::LaunchNotice::TokenNotStaged -pub devlaunch_core::flows::launch::LaunchNotice::TokenNotStaged::reason: alloc::string::String -pub devlaunch_core::flows::launch::LaunchNotice::WaitingForSiblingLaunch -pub devlaunch_core::flows::launch::LaunchNotice::WaitingForSiblingLaunch::workspace_id: alloc::string::String -impl core::clone::Clone for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::clone(&self) -> devlaunch_core::flows::launch::LaunchNotice -impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchNotice -impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::eq(&self, &devlaunch_core::flows::launch::LaunchNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchNotice -pub fn devlaunch_core::flows::launch::LaunchNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchNotice pub enum devlaunch_core::flows::launch::LaunchRefusal pub devlaunch_core::flows::launch::LaunchRefusal::BranchNotNamed pub devlaunch_core::flows::launch::LaunchRefusal::BranchNotNamed::error: devlaunch_core::flows::launch::BranchNotNamed @@ -1379,23 +1014,6 @@ pub fn devlaunch_core::flows::launch::LaunchRefusal::eq(&self, &devlaunch_core:: impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchRefusal pub fn devlaunch_core::flows::launch::LaunchRefusal::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchRefusal -pub enum devlaunch_core::flows::launch::LaunchVerb -pub devlaunch_core::flows::launch::LaunchVerb::Attach -pub devlaunch_core::flows::launch::LaunchVerb::Attach::command: core::option::Option -pub devlaunch_core::flows::launch::LaunchVerb::Code -pub devlaunch_core::flows::launch::LaunchVerb::Dotfiles -pub devlaunch_core::flows::launch::LaunchVerb::Recreate -pub devlaunch_core::flows::launch::LaunchVerb::Reset -pub devlaunch_core::flows::launch::LaunchVerb::Restart -pub devlaunch_core::flows::launch::LaunchVerb::Up -impl core::clone::Clone for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::clone(&self) -> devlaunch_core::flows::launch::LaunchVerb -impl core::cmp::Eq for devlaunch_core::flows::launch::LaunchVerb -impl core::cmp::PartialEq for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::eq(&self, &devlaunch_core::flows::launch::LaunchVerb) -> bool -impl core::fmt::Debug for devlaunch_core::flows::launch::LaunchVerb -pub fn devlaunch_core::flows::launch::LaunchVerb::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::LaunchVerb pub enum devlaunch_core::flows::launch::Launched pub devlaunch_core::flows::launch::Launched::AlreadyRunning pub devlaunch_core::flows::launch::Launched::Ready @@ -1520,40 +1138,6 @@ pub fn devlaunch_core::flows::launch::TerminalTitle::eq(&self, &devlaunch_core:: impl core::fmt::Debug for devlaunch_core::flows::launch::TerminalTitle pub fn devlaunch_core::flows::launch::TerminalTitle::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::TerminalTitle -pub struct devlaunch_core::flows::launch::Cold<'a, 'r> -pub devlaunch_core::flows::launch::Cold::clones: &'a devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> -pub devlaunch_core::flows::launch::Cold::storage: &'a mut devlaunch_core::domain::metadata::MetadataStorage -pub struct devlaunch_core::flows::launch::ColdPath<'r, 'e> -impl<'r, 'e> devlaunch_core::flows::launch::ColdPath<'r, 'e> -pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::new(&'r dyn devlaunch_runner::Runner, &'e mut dyn devlaunch_core::notices::Notices) -> Self -pub fn devlaunch_core::flows::launch::ColdPath<'r, 'e>::records(&mut self) -> core::result::Result<&mut devlaunch_core::flows::records::Records<'r>, devlaunch_core::flows::records::StartupError> -impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> -pub struct devlaunch_core::flows::launch::Host -impl devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::from_process(impl core::convert::Into) -> Self -impl core::clone::Clone for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::clone(&self) -> devlaunch_core::flows::launch::Host -impl core::cmp::Eq for devlaunch_core::flows::launch::Host -impl core::cmp::PartialEq for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::eq(&self, &devlaunch_core::flows::launch::Host) -> bool -impl core::default::Default for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::default() -> devlaunch_core::flows::launch::Host -impl core::fmt::Debug for devlaunch_core::flows::launch::Host -pub fn devlaunch_core::flows::launch::Host::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::Host -pub struct devlaunch_core::flows::launch::Launch<'a, 'r, 'l> -impl<'a, 'r, 'l> devlaunch_core::flows::launch::Launch<'a, 'r, 'l> -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::new(&'a mut devlaunch_core::flows::listing::CommandContext<'r>, &'a mut devlaunch_core::flows::lifecycle::Refresh<'l>, &'a mut dyn devlaunch_core::flows::launch::ColdMachinery<'r>, &'a dyn devlaunch_core::flows::launch::Provision, &'a devlaunch_core::flows::launch::Host, &'a mut dyn core::ops::function::FnMut(&str), &'a mut dyn devlaunch_core::notices::Notices) -> Self -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::recognised_as(self, core::option::Option) -> Self -pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::run(&mut self, &str, &devlaunch_core::flows::launch::LaunchVerb, core::option::Option<&devlaunch_core::domain::spec::DevcontainerPath>) -> core::result::Result -pub struct devlaunch_core::flows::launch::ToolProvisioning<'e> -impl<'e> devlaunch_core::flows::launch::ToolProvisioning<'e> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'e>::from_env(&std::path::Path, &'e mut dyn devlaunch_core::notices::Notices) -> Self -impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option pub struct devlaunch_core::flows::launch::UnquotableCommand pub devlaunch_core::flows::launch::UnquotableCommand::command: alloc::string::String impl core::clone::Clone for devlaunch_core::flows::launch::UnquotableCommand @@ -1564,18 +1148,6 @@ pub fn devlaunch_core::flows::launch::UnquotableCommand::eq(&self, &devlaunch_co impl core::fmt::Debug for devlaunch_core::flows::launch::UnquotableCommand pub fn devlaunch_core::flows::launch::UnquotableCommand::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::launch::UnquotableCommand -pub trait devlaunch_core::flows::launch::ColdMachinery<'r> -pub fn devlaunch_core::flows::launch::ColdMachinery::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> -pub fn devlaunch_core::flows::launch::ColdMachinery::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> -impl<'r> devlaunch_core::flows::launch::ColdMachinery<'r> for devlaunch_core::flows::launch::ColdPath<'r, '_> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::open(&mut self) -> core::result::Result, devlaunch_core::flows::launch::ColdRefused> -pub fn devlaunch_core::flows::launch::ColdPath<'r, '_>::recorded(&mut self) -> core::option::Option<&devlaunch_core::domain::metadata::MetadataStorage> -pub trait devlaunch_core::flows::launch::Provision -pub fn devlaunch_core::flows::launch::Provision::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> -pub fn devlaunch_core::flows::launch::Provision::remembered_claude(&self, &str) -> core::option::Option -impl devlaunch_core::flows::launch::Provision for devlaunch_core::flows::launch::ToolProvisioning<'_> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::provision_tools(&self, &dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, core::option::Option<&str>) -> core::result::Result, devlaunch_core::flows::provision::DevpodMissing> -pub fn devlaunch_core::flows::launch::ToolProvisioning<'_>::remembered_claude(&self, &str) -> core::option::Option pub fn devlaunch_core::flows::launch::plan(&str) -> core::result::Result pub fn devlaunch_core::flows::launch::resolve_triple(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut dyn devlaunch_core::flows::launch::ColdMachinery<'_>, &devlaunch_core::domain::workspace_id::WorkspaceId, &mut dyn devlaunch_core::notices::Notices, devlaunch_core::clients::devpod::Patience) -> core::result::Result pub mod devlaunch_core::flows::lifecycle @@ -1606,29 +1178,6 @@ impl core::fmt::Debug for devlaunch_core::flows::lifecycle::ChildWork pub fn devlaunch_core::flows::lifecycle::ChildWork::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::flows::lifecycle::ChildWork impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::ChildWork -pub enum devlaunch_core::flows::lifecycle::DeleteStalled -pub devlaunch_core::flows::lifecycle::DeleteStalled::OnTheLock -impl core::clone::Clone for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::clone(&self) -> devlaunch_core::flows::lifecycle::DeleteStalled -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::DeleteStalled -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::eq(&self, &devlaunch_core::flows::lifecycle::DeleteStalled) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::DeleteStalled -pub fn devlaunch_core::flows::lifecycle::DeleteStalled::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::DeleteStalled -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::DeleteStalled -pub enum devlaunch_core::flows::lifecycle::Insistence -pub devlaunch_core::flows::lifecycle::Insistence::Insisted -pub devlaunch_core::flows::lifecycle::Insistence::NotInsisted -impl core::clone::Clone for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::clone(&self) -> devlaunch_core::flows::lifecycle::Insistence -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Insistence -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::eq(&self, &devlaunch_core::flows::lifecycle::Insistence) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Insistence -pub fn devlaunch_core::flows::lifecycle::Insistence::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::Insistence -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Insistence pub enum devlaunch_core::flows::lifecycle::KeptBecause pub devlaunch_core::flows::lifecycle::KeptBecause::Objected(devlaunch_core::flows::lifecycle::Objection) pub devlaunch_core::flows::lifecycle::KeptBecause::RecordsDisagree @@ -1644,38 +1193,6 @@ pub fn devlaunch_core::flows::lifecycle::KeptBecause::eq(&self, &devlaunch_core: impl core::fmt::Debug for devlaunch_core::flows::lifecycle::KeptBecause pub fn devlaunch_core::flows::lifecycle::KeptBecause::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::KeptBecause -pub enum devlaunch_core::flows::lifecycle::LifecycleNotice -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::branch: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::derived: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::owner: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::recorded: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::AddressingRecordedWorkspace::repo: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::Cache(devlaunch_core::flows::repo_manager::CacheNotice) -pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved -pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved::refusal: devlaunch_core::flows::workspace_clone::RemoveWorkspaceError -pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneNotRemoved::workspace_id: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneRemoved -pub devlaunch_core::flows::lifecycle::LifecycleNotice::CloneRemoved::workspace_id: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped -pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped::path: std::path::PathBuf -pub devlaunch_core::flows::lifecycle::LifecycleNotice::RecordNotDropped::refusal: devlaunch_core::domain::metadata::MetadataError -pub devlaunch_core::flows::lifecycle::LifecycleNotice::Removing -pub devlaunch_core::flows::lifecycle::LifecycleNotice::Removing::workspace_id: alloc::string::String -pub devlaunch_core::flows::lifecycle::LifecycleNotice::RemovingOverWork -pub devlaunch_core::flows::lifecycle::LifecycleNotice::RemovingOverWork::refusal: devlaunch_core::flows::lifecycle::RemovalRefused -pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved -pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::occasion: devlaunch_core::flows::lifecycle::SweepOccasion -pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::refusal: devlaunch_core::flows::lifecycle::VolumeRefusal -pub devlaunch_core::flows::lifecycle::LifecycleNotice::VolumesNotRemoved::workspace_id: alloc::string::String -impl core::clone::Clone for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::clone(&self) -> devlaunch_core::flows::lifecycle::LifecycleNotice -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::LifecycleNotice -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::eq(&self, &devlaunch_core::flows::lifecycle::LifecycleNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::LifecycleNotice -pub fn devlaunch_core::flows::lifecycle::LifecycleNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::LifecycleNotice pub enum devlaunch_core::flows::lifecycle::NotAdopted pub devlaunch_core::flows::lifecycle::NotAdopted::CloneWantedByManyWorkspaces pub devlaunch_core::flows::lifecycle::NotAdopted::CloneWantedByManyWorkspaces::clone: std::path::PathBuf @@ -1796,51 +1313,6 @@ impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RefreshSpawn pub fn devlaunch_core::flows::lifecycle::RefreshSpawn::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::flows::lifecycle::RefreshSpawn impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RefreshSpawn -pub enum devlaunch_core::flows::lifecycle::Removal -pub devlaunch_core::flows::lifecycle::Removal::Guarded -pub devlaunch_core::flows::lifecycle::Removal::Insisted -pub devlaunch_core::flows::lifecycle::Removal::Wedged -impl devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::insistence(self) -> devlaunch_core::flows::lifecycle::Insistence -impl core::clone::Clone for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::clone(&self) -> devlaunch_core::flows::lifecycle::Removal -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::Removal -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::eq(&self, &devlaunch_core::flows::lifecycle::Removal) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::Removal -pub fn devlaunch_core::flows::lifecycle::Removal::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::Copy for devlaunch_core::flows::lifecycle::Removal -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::Removal -pub enum devlaunch_core::flows::lifecycle::RemovalRefused -pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell -pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell::cause: devlaunch_core::domain::workspace_state::CouldNotTell -pub devlaunch_core::flows::lifecycle::RemovalRefused::CouldNotTell::workspace_id: alloc::string::String -pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose -pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose::losses: devlaunch_core::domain::workspace_state::NonEmpty -pub devlaunch_core::flows::lifecycle::RemovalRefused::WouldLose::workspace_id: alloc::string::String -impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::clone(&self) -> devlaunch_core::flows::lifecycle::RemovalRefused -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemovalRefused -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::eq(&self, &devlaunch_core::flows::lifecycle::RemovalRefused) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemovalRefused -pub fn devlaunch_core::flows::lifecycle::RemovalRefused::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemovalRefused -pub enum devlaunch_core::flows::lifecycle::RemoveOutcome -pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted -pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted::clone: core::result::Result -pub devlaunch_core::flows::lifecycle::RemoveOutcome::Deleted::volumes: devlaunch_core::flows::lifecycle::VolumeSweep -pub devlaunch_core::flows::lifecycle::RemoveOutcome::DevpodRefused -pub devlaunch_core::flows::lifecycle::RemoveOutcome::DevpodRefused::exit: devlaunch_runner::Exit -pub devlaunch_core::flows::lifecycle::RemoveOutcome::Refused(devlaunch_core::flows::lifecycle::RemovalRefused) -impl core::clone::Clone for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::clone(&self) -> devlaunch_core::flows::lifecycle::RemoveOutcome -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::RemoveOutcome -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::eq(&self, &devlaunch_core::flows::lifecycle::RemoveOutcome) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::RemoveOutcome -pub fn devlaunch_core::flows::lifecycle::RemoveOutcome::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::RemoveOutcome pub enum devlaunch_core::flows::lifecycle::SpawnRefused pub devlaunch_core::flows::lifecycle::SpawnRefused::Blocked(devlaunch_runner::OsFailure) pub devlaunch_core::flows::lifecycle::SpawnRefused::ProgramNotFound @@ -2057,23 +1529,6 @@ pub fn devlaunch_core::flows::lifecycle::ReconcileReport::eq(&self, &devlaunch_c impl core::fmt::Debug for devlaunch_core::flows::lifecycle::ReconcileReport pub fn devlaunch_core::flows::lifecycle::ReconcileReport::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::ReconcileReport -pub struct devlaunch_core::flows::lifecycle::Refresh<'a> -impl<'a> devlaunch_core::flows::lifecycle::Refresh<'a> -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::ask(&mut self, &dyn devlaunch_runner::Runner, devlaunch_core::flows::lifecycle::RefreshReason) -> devlaunch_core::flows::lifecycle::RefreshSpawn -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::new(&'a devlaunch_core::flows::lifecycle::SelfInvocation, &'a std::path::Path) -> Self -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::rearm(&mut self) -pub fn devlaunch_core::flows::lifecycle::Refresh<'a>::spawned(&self) -> bool -pub struct devlaunch_core::flows::lifecycle::SelfInvocation -impl devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::new(impl core::convert::Into) -> Self -impl core::clone::Clone for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::clone(&self) -> devlaunch_core::flows::lifecycle::SelfInvocation -impl core::cmp::Eq for devlaunch_core::flows::lifecycle::SelfInvocation -impl core::cmp::PartialEq for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::eq(&self, &devlaunch_core::flows::lifecycle::SelfInvocation) -> bool -impl core::fmt::Debug for devlaunch_core::flows::lifecycle::SelfInvocation -pub fn devlaunch_core::flows::lifecycle::SelfInvocation::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::lifecycle::SelfInvocation pub struct devlaunch_core::flows::lifecycle::SweepReport pub devlaunch_core::flows::lifecycle::SweepReport::notices: alloc::vec::Vec impl core::default::Default for devlaunch_core::flows::lifecycle::SweepReport @@ -2134,9 +1589,7 @@ pub fn devlaunch_core::flows::lifecycle::purge_all_data(&mut devlaunch_core::flo pub fn devlaunch_core::flows::lifecycle::purge_plan(&mut devlaunch_core::flows::listing::CommandContext<'_>, &std::path::Path) -> core::result::Result pub fn devlaunch_core::flows::lifecycle::reconcile_plan(&devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>, &devlaunch_core::domain::metadata::MetadataStorage, &[devlaunch_core::clients::devpod::Workspace], &devlaunch_core::flows::lifecycle::ClonePlacement, &mut dyn devlaunch_core::notices::Notices) -> devlaunch_core::flows::lifecycle::ReconcilePlan pub fn devlaunch_core::flows::lifecycle::sweep_repo_fetches(&devlaunch_core::flows::repo_manager::RepositoryManager<'_>, &mut devlaunch_core::domain::metadata::MetadataStorage) -> devlaunch_core::flows::lifecycle::SweepReport -pub fn devlaunch_core::flows::lifecycle::workspace_remove(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>, &mut devlaunch_core::domain::metadata::MetadataStorage, &std::path::Path, core::option::Option<&devlaunch_core::clients::devpod_home::DevpodHome>, &devlaunch_core::flows::kept_copies::KeptCopies, &str, devlaunch_core::flows::lifecycle::Removal, &mut dyn core::ops::function::FnMut(devlaunch_core::flows::lifecycle::DeleteStalled), &mut dyn devlaunch_core::notices::Notices) -> core::result::Result pub fn devlaunch_core::flows::lifecycle::workspace_state(&dyn devlaunch_runner::Runner, &str, devlaunch_core::clients::devpod::Patience) -> core::result::Result -pub fn devlaunch_core::flows::lifecycle::workspace_stop(&mut devlaunch_core::flows::listing::CommandContext<'_>, &mut devlaunch_core::flows::lifecycle::Refresh<'_>, &str) -> core::result::Result pub mod devlaunch_core::flows::listing pub enum devlaunch_core::flows::listing::LastUsed pub devlaunch_core::flows::listing::LastUsed::At(alloc::string::String) @@ -2199,11 +1652,6 @@ pub fn devlaunch_core::flows::listing::WorkspaceTable::eq(&self, &devlaunch_core impl core::fmt::Debug for devlaunch_core::flows::listing::WorkspaceTable pub fn devlaunch_core::flows::listing::WorkspaceTable::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::flows::listing::WorkspaceTable -pub struct devlaunch_core::flows::listing::CommandContext<'r> -impl<'r> devlaunch_core::flows::listing::CommandContext<'r> -pub fn devlaunch_core::flows::listing::CommandContext<'r>::git(&self) -> devlaunch_core::clients::git::Git<'r> -pub fn devlaunch_core::flows::listing::CommandContext<'r>::new(&'r dyn devlaunch_runner::Runner) -> Self -pub fn devlaunch_core::flows::listing::CommandContext<'r>::workspaces(&mut self) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> pub struct devlaunch_core::flows::listing::DlView<'a> pub devlaunch_core::flows::listing::DlView::cache_dir: &'a std::path::Path pub devlaunch_core::flows::listing::DlView::clones: &'a dyn devlaunch_core::flows::listing::ClonePathResolver @@ -2300,10 +1748,8 @@ pub fn devlaunch_core::flows::lifecycle::CloneDirectories<'_, '_>::bare_path(&se pub fn devlaunch_core::flows::lifecycle::CloneDirectories<'_, '_>::clone_path(&self, &devlaunch_core::domain::model::WorktreeInfo) -> core::option::Option pub fn devlaunch_core::flows::listing::describe_source(&devlaunch_core::clients::devpod::WorkspaceSource) -> devlaunch_core::flows::listing::SourceDescription pub fn devlaunch_core::flows::listing::discover_repos_from_workspaces(&devlaunch_core::clients::git::Git<'_>, &[devlaunch_core::clients::devpod::Workspace]) -> devlaunch_core::flows::listing::RepoDiscovery -pub fn devlaunch_core::flows::listing::enriched_listing(&mut devlaunch_core::flows::listing::CommandContext<'_>, &devlaunch_core::flows::listing::DlView<'_>, devlaunch_core::flows::listing::Sizes) -> core::result::Result, devlaunch_core::clients::devpod::ListingUnreadable> pub fn devlaunch_core::flows::listing::flatten_repos(&indexmap::map::IndexMap>) -> alloc::vec::Vec pub fn devlaunch_core::flows::listing::head_branch_of(&devlaunch_core::clients::devpod::Workspace, &std::path::Path) -> core::option::Option -pub fn devlaunch_core::flows::listing::json_document(&[devlaunch_core::flows::listing::ListedWorkspace]) -> serde_json::value::Value pub fn devlaunch_core::flows::listing::outstanding_sweep_notes(&devlaunch_core::domain::metadata::MetadataStorage) -> alloc::vec::Vec pub fn devlaunch_core::flows::listing::owner_of(&devlaunch_core::clients::devpod::Workspace, &std::path::Path) -> core::option::Option pub fn devlaunch_core::flows::listing::repo_of(&devlaunch_core::clients::devpod::Workspace, &std::path::Path) -> core::option::Option @@ -2477,35 +1923,6 @@ impl core::fmt::Debug for devlaunch_core::flows::provision::PassOccasion pub fn devlaunch_core::flows::provision::PassOccasion::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::flows::provision::PassOccasion impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::PassOccasion -pub enum devlaunch_core::flows::provision::ProvisionEvent -pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled -pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::exit: devlaunch_runner::Exit -pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::tools: alloc::vec::Vec<&'static str> -pub devlaunch_core::flows::provision::ProvisionEvent::NotInstalled::workspace: alloc::string::String -pub devlaunch_core::flows::provision::ProvisionEvent::PayloadNotBundled -pub devlaunch_core::flows::provision::ProvisionEvent::PayloadNotBundled::failure: devlaunch_core::flows::provision::BundleFailed -pub devlaunch_core::flows::provision::ProvisionEvent::ProvisioningDisabled -pub devlaunch_core::flows::provision::ProvisionEvent::ProvisioningDisabled::workspace: alloc::string::String -pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed -pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::loudness: devlaunch_core::flows::provision::FailureLevel -pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::stage: &'static str -pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::status: i32 -pub devlaunch_core::flows::provision::ProvisionEvent::StageFailed::workspace: alloc::string::String -pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported -pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::loudness: devlaunch_core::flows::provision::FailureLevel -pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::stage: &'static str -pub devlaunch_core::flows::provision::ProvisionEvent::StageNotReported::workspace: alloc::string::String -pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused -pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused::refusal: devlaunch_core::clients::devpod::NotRun -pub devlaunch_core::flows::provision::ProvisionEvent::TripRefused::workspace: alloc::string::String -impl core::clone::Clone for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::clone(&self) -> devlaunch_core::flows::provision::ProvisionEvent -impl core::cmp::Eq for devlaunch_core::flows::provision::ProvisionEvent -impl core::cmp::PartialEq for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::eq(&self, &devlaunch_core::flows::provision::ProvisionEvent) -> bool -impl core::fmt::Debug for devlaunch_core::flows::provision::ProvisionEvent -pub fn devlaunch_core::flows::provision::ProvisionEvent::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::ProvisionEvent pub enum devlaunch_core::flows::provision::Provisioning pub devlaunch_core::flows::provision::Provisioning::AlreadyProvisioned pub devlaunch_core::flows::provision::Provisioning::CachedProvisioned @@ -2601,41 +2018,6 @@ impl core::marker::Copy for devlaunch_core::flows::provision::Switches impl core::marker::StructuralPartialEq for devlaunch_core::flows::provision::Switches pub fn devlaunch_core::flows::provision::provision_tools(&dyn devlaunch_runner::Runner, &str, devlaunch_core::flows::provision::PassOccasion, devlaunch_core::flows::provision::Switches, core::option::Option<&str>, core::option::Option<&devlaunch_core::flows::provision::HostLayout>, core::option::Option<&devlaunch_core::flows::provision::verdict_cache::VerdictCache>, &mut dyn devlaunch_core::notices::Notices) -> core::result::Result pub mod devlaunch_core::flows::records -pub enum devlaunch_core::flows::records::RecordsNotice -pub devlaunch_core::flows::records::RecordsNotice::Metadata(devlaunch_core::domain::metadata::Notice) -pub devlaunch_core::flows::records::RecordsNotice::Migrated(devlaunch_core::flows::migration::MigrationReport) -pub devlaunch_core::flows::records::RecordsNotice::MigrationRefused(devlaunch_core::domain::metadata::MetadataError) -pub devlaunch_core::flows::records::RecordsNotice::RetiredKey(devlaunch_core::domain::config::RetiredKey) -impl core::clone::Clone for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::clone(&self) -> devlaunch_core::flows::records::RecordsNotice -impl core::cmp::Eq for devlaunch_core::flows::records::RecordsNotice -impl core::cmp::PartialEq for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::eq(&self, &devlaunch_core::flows::records::RecordsNotice) -> bool -impl core::fmt::Debug for devlaunch_core::flows::records::RecordsNotice -pub fn devlaunch_core::flows::records::RecordsNotice::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::RecordsNotice -pub enum devlaunch_core::flows::records::StartupError -pub devlaunch_core::flows::records::StartupError::Config(devlaunch_core::domain::config::ConfigError) -pub devlaunch_core::flows::records::StartupError::Metadata(devlaunch_core::domain::metadata::MetadataError) -pub devlaunch_core::flows::records::StartupError::NoHomeDirectory -impl core::clone::Clone for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::clone(&self) -> devlaunch_core::flows::records::StartupError -impl core::cmp::Eq for devlaunch_core::flows::records::StartupError -impl core::cmp::PartialEq for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::eq(&self, &devlaunch_core::flows::records::StartupError) -> bool -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::config::ConfigError) -> Self -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::metadata::MetadataError) -> Self -impl core::convert::From for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::from(devlaunch_core::domain::xdg::NoHomeDirectory) -> Self -impl core::fmt::Debug for devlaunch_core::flows::records::StartupError -pub fn devlaunch_core::flows::records::StartupError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -impl core::marker::StructuralPartialEq for devlaunch_core::flows::records::StartupError -pub struct devlaunch_core::flows::records::Records<'r> -pub devlaunch_core::flows::records::Records::clones: devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> -pub devlaunch_core::flows::records::Records::reported: alloc::vec::Vec -pub devlaunch_core::flows::records::Records::storage: devlaunch_core::domain::metadata::MetadataStorage pub fn devlaunch_core::flows::records::open_records<'r>(&'r dyn devlaunch_runner::Runner) -> core::result::Result, devlaunch_core::flows::records::StartupError> pub fn devlaunch_core::flows::records::open_storage() -> core::result::Result<(devlaunch_core::domain::metadata::MetadataStorage, alloc::vec::Vec), devlaunch_core::flows::records::StartupError> pub mod devlaunch_core::flows::repo_manager @@ -2922,13 +2304,6 @@ impl core::fmt::Debug for devlaunch_core::flows::workspace_clone::Removed pub fn devlaunch_core::flows::workspace_clone::Removed::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for devlaunch_core::flows::workspace_clone::Removed impl core::marker::StructuralPartialEq for devlaunch_core::flows::workspace_clone::Removed -pub struct devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> -impl<'r> devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r> -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::in_cache(&std::path::Path, &devlaunch_core::domain::config::WorktreeConfig, devlaunch_core::clients::git::Git<'r>) -> Self -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::on_repo_lock_wait(&mut self, impl core::ops::function::Fn(&str, &str) + 'static) -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'r>::repo_manager(&self) -> &devlaunch_core::flows::repo_manager::RepositoryManager<'r> -impl core::fmt::Debug for devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_> -pub fn devlaunch_core::flows::workspace_clone::WorkspaceCloneManager<'_>::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub mod devlaunch_core::json pub enum devlaunch_core::json::JsonKind pub devlaunch_core::json::JsonKind::Array @@ -2948,9 +2323,6 @@ impl core::marker::Copy for devlaunch_core::json::JsonKind impl core::marker::StructuralPartialEq for devlaunch_core::json::JsonKind pub fn devlaunch_core::json::as_python_writes_it_indented(&serde_json::value::Value) -> alloc::string::String pub mod devlaunch_core::notices -pub trait devlaunch_core::notices::Notices -pub fn devlaunch_core::notices::Notices::say(&mut self, T) -impl devlaunch_core::notices::Notices for alloc::vec::Vec pub fn alloc::vec::Vec::say(&mut self, T) pub mod devlaunch_core::osext pub fn devlaunch_core::osext::env_str(&str) -> core::option::Option @@ -2972,7 +2344,5 @@ pub fn devlaunch_core::timing::Report::eq(&self, &devlaunch_core::timing::Report impl core::fmt::Debug for devlaunch_core::timing::Report pub fn devlaunch_core::timing::Report::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for devlaunch_core::timing::Report -pub const devlaunch_core::timing::HANDOFF_VAR: &str -pub const devlaunch_core::timing::PREWARM_VAR: &str pub fn devlaunch_core::timing::begin() pub fn devlaunch_core::timing::emit() -> core::option::Option diff --git a/rust/devlaunch-core/src/lib.rs b/rust/devlaunch-core/src/lib.rs index da38212..5bc77a3 100644 --- a/rust/devlaunch-core/src/lib.rs +++ b/rust/devlaunch-core/src/lib.rs @@ -43,23 +43,46 @@ //! item, and by two `cargo public-api` snapshots that CI diffs on every pull //! request: any change to the crate's public surface is a committed, reviewed //! diff or a red tick. The two tiers get a file each — `public-api.api.txt` -//! for declarations at the [`api`] path, `public-api.rest.txt` for the rest — -//! so that a change to the promised tier's *declarations* is a diff in a -//! 126-row file rather than one row inside two thousand. +//! for the promised tier, `public-api.rest.txt` for the rest — so that a change +//! to what [`api`] promises is a diff in an 813-row file rather than one row +//! inside two thousand. //! -//! **What that file does not cover, and it is not a small gap.** -//! `cargo public-api` renders inherent methods and trait impls only at a -//! type's canonical path, never at the path it is re-exported under. So -//! [`api::Launch`]'s only constructor and only method are rendered -//! `flows::launch::Launch::{new, run}` and land in `public-api.rest.txt`, as do -//! `CommandContext::new`, `DevcontainerPath::as_str` and every derived -//! `Clone`/`Debug`/`PartialEq` on the promised types: 133 of the 259 rows the -//! generator emits for the `api` section. Renaming `api::Launch::run` — an -//! unambiguous break — leaves `public-api.api.txt` byte-identical. So the -//! sound direction is one-way: a diff in the promise file *is* a change to the -//! promise, but a change to the promise need not diff it, and a diff in the -//! rest file that touches a promised type is a contract change too. Widening -//! the classifier is . +//! **How the promise file is filled, because the `api` path is not the whole +//! answer.** `cargo public-api` renders an item's own declaration at every path +//! it is reachable by, so [`api::Launch`] gets a row — but it renders inherent +//! methods and trait impls at the type's *canonical* path only, never at the +//! path it is re-exported under, so `api::Launch::run` is rendered +//! `flows::launch::Launch::run`. Matching the `api` path alone therefore kept +//! the promised types' names and dropped all of their behaviour, and renaming +//! `api::Launch::run` — an unambiguous break — left the file byte-identical. +//! So the classifier resolves each of [`api`]'s re-exports back to the path it +//! names and claims that item's rows too (#352), which moved 631 rows out of +//! the rest file: `Launch::{new, run}`, `CommandContext::new`, +//! `DevcontainerPath::as_str` and every derived `Clone`/`Debug`/`PartialEq` on +//! a promised type. A `flows::` or `domain::` path inside `public-api.api.txt` +//! is the promise and not a stray, and the cost of that is real: moving a +//! promised type between modules now churns the file where churn is expensive. +//! +//! **What it still does not reach, and it is not one type.** A type [`api`] +//! never re-exports but a promised signature names is reachable from outside +//! and classified as binary surface, so a break in it diffs +//! `public-api.rest.txt` alone. Counted rather than guessed at: **39 such types +//! own over six hundred rows over there**, and `scripts/public-api-snapshots.sh +//! --print-residual` lists them. +//! +//! The pointed one is `domain::spec::DevcontainerRefError`. [`api`] promises +//! `resolve_devcontainer_ref`, which returns it, so the *function* is a +//! promise-file row at the `api` path itself while the error it hands you is +//! not: rename one of that error's variants and every consumer matching on it +//! breaks, with the only diff in the file this doc calls freely regenerated. +//! `domain::metadata::MetadataError` is the same shape, carried by the promised +//! `StartupError::Metadata`. `flows::launch::Launched`, returned by +//! `Launch::run`, is the example this paragraph used to give as though it were +//! the whole of the residual, which is what made six hundred rows read as one. +//! +//! So a `public-api.rest.txt` diff is routine for a row whose subject nothing +//! promised names, and a contract change for a row whose subject is one of the +//! 39. `--print-residual` is how you tell which you are looking at. //! //! `scripts/public-api-snapshots.sh` regenerates both; see "The public-API //! snapshots" in docs/development.md. diff --git a/rust/devlaunch-core/tests/public_api_snapshots.rs b/rust/devlaunch-core/tests/public_api_snapshots.rs index 5327431..f77ba5f 100644 --- a/rust/devlaunch-core/tests/public_api_snapshots.rs +++ b/rust/devlaunch-core/tests/public_api_snapshots.rs @@ -1,10 +1,10 @@ //! The two files core's public-API snapshot splits into, and the invariant that //! keeps them worth reading. //! -//! `public-api.api.txt` is the promise as a path match can see it: every row is -//! a declaration written *at* `devlaunch_core::api`, the surface an external -//! consumer is entitled to depend on, so a diff there is a change to that -//! contract. `public-api.rest.txt` is the tripwire: the binary surface, +//! `public-api.api.txt` is the promise: every row declares something +//! `devlaunch_core::api` re-exports, the surface an external consumer is +//! entitled to depend on, so a diff there is a change to that contract. +//! `public-api.rest.txt` is the tripwire: the binary surface, //! reachable but never promised, regenerated freely whenever a refactor moves //! it. //! @@ -13,21 +13,22 @@ //! removed `api` function reads as routine, and the one row that mattered goes //! through review unremarked. //! -//! The tests below hold the partition, which is not the same as holding the -//! promise. `cargo public-api` renders methods and impls only at a type's -//! canonical path, so `api::Launch::{new, run}` and every derived impl on a -//! promised type are in the rest file — 133 of the 259 rows the generator emits -//! for the `api` section — and renaming `Launch::run` diffs neither of these -//! two files in the place a reader would look. Deliberately not asserted here: -//! widens the classifier, and -//! its red is that rename, so a test pinning today's classification of those -//! rows would have to be deleted to let the fix land. +//! The promise file holds behaviour and not only declarations, which took a +//! second rule to achieve (#352). `cargo public-api` renders inherent methods +//! and trait impls at a type's *canonical* path only, never at the path it is +//! re-exported under, so `api::Launch::{new, run}` are rendered +//! `flows::launch::Launch::{new, run}` and a path match on `api` cannot see +//! them. The classifier resolves each re-export back to the path it names and +//! claims that item's rows too, which is why `public-api.api.txt` is full of +//! `flows::` and `domain::` paths: they are the promise, not strays. //! //! The classification lives in `scripts/public-api-snapshots.sh` and nowhere -//! else — the CI job runs that script rather than re-implementing its filter. -//! These tests are the other half of that: they hold the *checked-in* files to -//! the rule, so a hand-edited snapshot, or a regeneration that put the promise -//! in the file nobody reads, fails here rather than passing quietly. +//! else — the CI job runs that script rather than re-implementing its filter, +//! and so does the fixed-point test below rather than restating the rule in +//! Rust, where the restatement is what would be under test. These tests are the +//! other half of that: they hold the *checked-in* files to the rule, so a +//! hand-edited snapshot, or a regeneration that put the promise in the file +//! nobody reads, fails here rather than passing quietly. const PROMISE: &str = include_str!("../public-api.api.txt"); const REST: &str = include_str!("../public-api.rest.txt"); @@ -57,16 +58,56 @@ fn names_api(row: &str) -> bool { }) } -#[test] -fn every_promised_row_is_an_api_declaration() { - let strays: Vec<&str> = rows(PROMISE) - .into_iter() - .filter(|row| !names_api(row)) - .collect(); +/// One side of the split, as the regeneration script itself decides it. +/// +/// Shelling out rather than reimplementing: the rule is now two clauses over a +/// path list read out of `src/lib.rs`, and a copy of it here would be a second +/// definition of what is promised -- the exact thing the script exists to stop +/// there being. Needs no nightly toolchain and generates nothing; `--classify` +/// is a filter over rows on stdin. +fn classified(kind: &str, corpus: &str) -> String { + let script = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../scripts/public-api-snapshots.sh"); + let input = std::env::temp_dir().join(format!( + "devlaunch-public-api-{kind}-{}.txt", + std::process::id() + )); + std::fs::write(&input, corpus).expect("staging the corpus for the classifier"); + let done = std::process::Command::new(&script) + .args(["--classify", kind]) + .stdin(std::fs::File::open(&input).expect("reopening the staged corpus")) + .output() + .expect("running the regeneration script's classifier"); + let _ = std::fs::remove_file(&input); assert!( - strays.is_empty(), - "public-api.api.txt is the frozen promise and holds only \ - devlaunch_core::api declarations; these rows are something else: {strays:#?}" + done.status.success(), + "{} --classify {kind} failed: {}", + script.display(), + String::from_utf8_lossy(&done.stderr) + ); + String::from_utf8(done.stdout).expect("the classifier's output is the rows it was given") +} + +#[test] +fn the_checked_in_split_is_the_one_the_classifier_makes() { + // Feed the classifier everything the two files hold and it must hand back + // the same two files: each row on the side it is already on, in the order + // it is already in. That is a stronger statement than "every promised row + // names the api path", which stopped being true when the classifier learned + // to claim canonical paths -- and it covers what that one covered, since a + // hand-added row on the wrong side changes which list it comes back in. + let corpus = format!("{PROMISE}{REST}"); + assert_eq!( + rows(&classified("api", &corpus)), + rows(PROMISE), + "public-api.api.txt is not what the classifier would put there; a row \ + was hand-edited in, or the two were regenerated by different rules" + ); + assert_eq!( + rows(&classified("rest", &corpus)), + rows(REST), + "public-api.rest.txt holds a row the classifier calls promised, where a \ + breaking change to it would read as routine churn" ); } @@ -83,6 +124,49 @@ fn no_row_of_the_rest_is_an_api_declaration() { ); } +/// Whether some row of a snapshot declares `Type::method`, wherever +/// `cargo public-api` chose to render it and whatever generics it carried. +/// +/// A row is `pub fn () -> `, so the declaration is everything +/// before the first `(`; matching against that and not the whole row is what +/// keeps an argument of type `Launch` from reading as a method on one. +fn declares(snapshot: &str, ty: &str, method: &str) -> bool { + let owner = format!("::{ty}"); + let called = format!("::{method}"); + rows(snapshot).into_iter().any(|row| { + let Some(rest) = row.strip_prefix("pub fn ") else { + return false; + }; + let path = rest.split('(').next().unwrap_or_default(); + path.ends_with(&called) + && path + .match_indices(&owner) + .any(|(at, _)| matches!(path[at + owner.len()..].chars().next(), Some(':' | '<'))) + }) +} + +#[test] +fn the_promise_file_carries_the_promised_types_behaviour() { + // Every one of these is reachable only through the promised tier, and + // renaming any of them breaks a caller that has `api` and nothing else. + let missing: Vec = [ + ("Launch", "new"), + ("Launch", "run"), + ("CommandContext", "new"), + ("DevcontainerPath", "as_str"), + ] + .into_iter() + .filter(|(ty, method)| !declares(PROMISE, ty, method)) + .map(|(ty, method)| format!("{ty}::{method}")) + .collect(); + assert!( + missing.is_empty(), + "public-api.api.txt is the frozen promise and does not declare {missing:?}; \ + renaming one of those is an unambiguous break that leaves the file \ + byte-identical" + ); +} + #[test] fn the_two_files_share_no_row() { let promise = rows(PROMISE); diff --git a/scripts/public-api-snapshots.sh b/scripts/public-api-snapshots.sh index 5fefdae..e9e1938 100755 --- a/scripts/public-api-snapshots.sh +++ b/scripts/public-api-snapshots.sh @@ -5,49 +5,85 @@ # # There are three files because there are three different promises: # -# rust/devlaunch-core/public-api.api.txt the promise, as far as a path match -# can see it: every row is a declaration *at* `devlaunch_core::api`, the -# tier an external consumer is entitled to depend on. A diff here is a -# deliberate change to that tier -- a removal or a changed signature is a -# break -- and wants a reviewer who reads it that way. The converse does -# not hold; see the limit below. -# rust/devlaunch-core/public-api.rest.txt the tripwire, and today also the -# promised types' behaviour. Mostly the binary surface -- `flows::`, -# `domain::`, `clients::` -- which is reachable but never promised, so -# most of a diff here is routine and read for the accidental `pub`. But -# see the limit below before reading a diff that touches a promised type -# as routine. +# rust/devlaunch-core/public-api.api.txt the promise: every row declares +# something `devlaunch_core::api` re-exports, the tier an external +# consumer is entitled to depend on. A diff here is a deliberate change to +# that tier -- a removal or a changed signature is a break -- and wants a +# reviewer who reads it that way. Most of its rows are written at a +# `flows::` or `domain::` path rather than at `api`, which is not a bug in +# the filter; see how it is filled, below. +# rust/devlaunch-core/public-api.rest.txt the tripwire. The binary surface -- +# `flows::`, `domain::`, `clients::` -- which is reachable but never +# promised, so most of a diff here is routine and read for the accidental +# `pub`. But see the limit below before reading one as routine. # rust/devlaunch-runner/public-api.txt the process seam, as an external # `Runner` implementer sees it. It had no snapshot until the split: the # whole crate entered core's as one unexpanded glob row, so a removed # trait method moved nothing and passed CI. # -# The limit, measured rather than assumed: `cargo public-api` renders inherent -# methods and trait impls only at a type's *canonical* path, never at the path -# it is re-exported under. So `api::Launch::run` is rendered -# `devlaunch_core::flows::launch::Launch::run` and this classifier cannot see -# it. Of the 259 rows the generator emits for the `api` section, the match keeps -# 126; the other 133 -- `Launch::new`, `Launch::run`, `CommandContext::new`, -# `DevcontainerPath::as_str` and every derived `Clone`/`Debug`/`PartialEq` on -# the promised types -- land in the rest file. Renaming `Launch::run` therefore -# leaves the promise file byte-identical. Two consequences worth carrying: -# a diff in the rest file that touches a promised type is a contract change -# too, and this classifier is not the whole guard. Widening it is -# https://github.com/blooop/devlaunch/issues/352. -# -# The classification is one `grep` and it lives here, in the script CI runs, -# because the alternative is two copies of it -- one in the workflow, one in -# whatever regenerates the files -- drifting until the promise file quietly -# stops holding even what it does hold. `.github/workflows/ci.yml`'s -# `public-api` job runs this into a scratch tree and diffs the result against -# what the repo carries; a developer runs it with no argument to accept a -# deliberate change. +# How the promise file is filled, measured rather than assumed. `cargo +# public-api` renders an item's own declaration at every path it is reachable +# by, so `api::Launch` gets a row -- but it renders inherent methods and trait +# impls at the type's *canonical* path only, never at the path it is re-exported +# under, so `api::Launch::run` is rendered +# `devlaunch_core::flows::launch::Launch::run`. Matching the `api` path alone +# kept 182 rows and left 631 in the rest file, `Launch::new` and `Launch::run` +# among them, so renaming `Launch::run` left the promise file byte-identical +# (#352). So the classifier resolves each `api` re-export back to the path it +# names and claims that item's rows too, which is what `promised_row_pattern` +# below does. Some rows are in the file twice, because the generator emits them +# twice: once under the `api` section and once under the module that owns them. +# +# The limit that is left, and it is not one type. A type `api` never re-exports +# but a promised signature names is reachable from outside and is classified as +# binary surface, so a break in it diffs public-api.rest.txt alone. Measured on +# the checked-in files rather than guessed at: 39 such types own over six +# hundred rows over there. `--print-residual` lists them, needs no toolchain, +# and prints the exact row count; the type count above is the figure +# `test/test_public_api_snapshots_doc.py` diffs against it, because that is the +# one a reader calibrates on and the one that moves only when the residual +# really grows. +# +# The pointed one is `domain::spec::DevcontainerRefError`, because +# `pub fn devlaunch_core::api::resolve_devcontainer_ref(&str) -> Result<..., +# DevcontainerRefError>` is a promise-file row at the `api` path itself: rename +# one of that error's variants and every consumer matching on it breaks, while +# the only file that moves is the one this header calls routine. So is +# `domain::metadata::MetadataError`, which the promised `StartupError::Metadata` +# carries. `flows::launch::Launched`, which `Launch::run` returns, is the +# example this comment used to give as though it were the whole of it. +# +# What that means for reading a rest-file diff: it is routine for a row whose +# subject is nothing a promised signature names, and a contract change for a row +# whose subject is one of the 39. `--print-residual` is how you tell. +# +# Whether the tool does this already, since the obvious first question is why +# any of it is hand-rolled (#352 asked it explicitly). It does not, in the pin +# this script names. `cargo public-api 0.52.0` offers exactly four ways to +# select what is rendered -- `--omit blanket-impls|auto-trait-impls| +# auto-derived-impls` (and the `-s` shorthands), `--include +# function-parameter-names`, the feature and target flags, and `-p` for which +# package -- and not one of them is a path, module or reachability filter. There +# is no upstream notion of "the surface reachable from this module", so the +# choice is a filter over rendered rows or nothing. Re-check it when the pin +# moves; `cargo public-api --help` is the whole answer. +# +# The classification lives here, in the script CI runs, because the alternative +# is two copies of it -- one in the workflow, one in whatever regenerates the +# files -- drifting until the promise file quietly stops holding even what it +# does hold. `.github/workflows/ci.yml`'s `public-api` job runs this into a +# scratch tree and diffs the result against what the repo carries; a developer +# runs it with no argument to accept a deliberate change; and the tests over the +# checked-in files reach it through `--classify` rather than restating it. # # Usage: # scripts/public-api-snapshots.sh # rewrite the checked-in files # scripts/public-api-snapshots.sh DEST # write them under DEST instead # scripts/public-api-snapshots.sh --print-pin # scripts/public-api-snapshots.sh --print-files +# scripts/public-api-snapshots.sh --print-promised +# scripts/public-api-snapshots.sh --print-residual # the limit, counted +# scripts/public-api-snapshots.sh --classify api|rest # rows on stdin # # Needs a nightly toolchain (cargo-public-api's rustdoc-JSON backend is # nightly-only; the crates themselves still build on the stable pin) and the @@ -70,7 +106,7 @@ PIN=0.52.0 # moves -- `UnsafeUnpin` appeared with a nightly, not with a crate change -- and # a tripwire that fires on toolchain drift teaches people to update snapshots # unread. Derived impls (Clone, Debug, serde) stay in: losing one is a real -# break. Note where they stay -- the rest file, per the limit above. +# break, and a promised type's are in the promise file with the rest of it. FLAGS=(-ss) # The boundary matters: `\b` is what keeps a future `devlaunch_core::apiary` @@ -87,6 +123,168 @@ REST_FILE=devlaunch-core/public-api.rest.txt RUNNER_FILE=devlaunch-runner/public-api.txt FILES=("$API_FILE" "$REST_FILE" "$RUNNER_FILE") +# Where the promised tier is declared, and so where the canonical paths behind +# it are read from. The `api` module is a wall of `pub use crate::...`, which is +# exactly the mapping the renderer throws away. +CORE_LIB=devlaunch-core/src/lib.rs + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# The canonical path of every item the `api` module re-exports, spelled the way +# `cargo public-api` spells one. +# +# Reading Rust with awk is not free, and the alternative was worse: a list of +# paths kept here by hand is a second declaration of what is promised, and the +# day it falls behind `api` the promise file quietly stops covering whatever was +# added. This reads the one declaration there is. +# +# What it understands, exactly, because a form it half-understands is a path it +# gets wrong: `pub use crate::a::b::Name;`, `pub use crate::a::b::{X, Y};`, and +# either of those with an `as` rename on any name, all of them free to wrap +# across lines. `//` and `/* */` comments are removed first, so a commented-out +# re-export is not a promise. Anything else -- a glob, a path that is not an +# identifier chain -- is refused by the shape check below rather than guessed at. +# +# The `as` form matters more than it looks, and the previous version of this +# parser got it wrong *quietly*: it stripped whitespace before looking, so +# `pub use crate::domain::spec::WorkspaceSpec as Spec;` welded into +# `...::WorkspaceSpecasSpec`, which is a valid identifier chain and so passed +# the shape check on its way to matching nothing. The alias is not what to +# match: `cargo public-api` renders the item's methods at its canonical path, +# and the alias only ever appears on the `api`-path row that the first clause of +# the pattern already claims. So the rename is dropped and the canonical path +# kept, which is the right answer rather than merely a loud one. +promised_paths() { + awk ' + /^pub mod api \{/ { inside = 1; next } + inside && /^\}/ { inside = 0 } + inside { sub(/\/\/.*/, ""); body = body " " $0 } + END { + # Block comments only after the lines are joined: one can span them. + gsub(/\/\*([^*]|\*+[^*\/])*\*+\//, " ", body) + n = split(body, statements, ";") + for (i = 1; i <= n; i++) { + if (statements[i] !~ /pub[ \t]+use[ \t]+crate::/) continue + item = statements[i] + sub(/^.*pub[ \t]+use[ \t]+crate::/, "", item) + # Before the whitespace goes, or `X as Y` becomes the identifier `XasY`. + gsub(/[ \t]+as[ \t]+[A-Za-z_][A-Za-z0-9_]*/, "", item) + gsub(/[ \t]/, "", item) + if (match(item, /\{/)) { + module = substr(item, 1, RSTART - 1) + names = substr(item, RSTART + 1) + sub(/\}.*$/, "", names) + m = split(names, list, ",") + for (j = 1; j <= m; j++) if (list[j] != "") print "devlaunch_core::" module list[j] + } else { + print "devlaunch_core::" item + } + } + } + ' "$repo_root/rust/$CORE_LIB" | while read -r path; do + if [[ ! "$path" =~ ^devlaunch_core(::[A-Za-z_][A-Za-z0-9_]*)+$ ]]; then + echo "cannot read '$path' as a path: the api module uses a re-export form this script does not parse." >&2 + exit 1 + fi + echo "$path" + done +} + +# The rule that decides which file a row belongs in, as one extended regex. +# +# Two clauses, and the second is what #352 added. `cargo public-api` renders an +# item's own declaration at every path it is reachable by, so `api::Launch` gets +# a row -- but it renders inherent methods and trait impls at the type's +# *canonical* path only, so `api::Launch::run` is rendered +# `devlaunch_core::flows::launch::Launch::run` and the first clause cannot see +# it. The second clause claims those by resolving the re-export back to the path +# it names. +# +# The anchors are the whole difficulty. A promised type appears in a signature +# somewhere in most of this crate, so claiming any row that *mentions* one would +# drag the binary surface into the promise file. A row's subject is what is +# claimed: the path right after `pub` and its item keywords, or -- for an impl, +# where the subject is either side of `for` -- any path in the header that +# follows a space. +# +# That second anchor is an approximation and it is worth saying which way it is +# wrong, since a comment that oversells it is how the next person stops +# checking. `Vec` and `From` are safe: a path nested in a +# single-argument generic follows a `<`, never a space. A path nested in a +# *multi*-argument generic, a tuple, or a trait bound does follow a space, so +# `impl From<(u8, Promised)> for Internal` and `impl Trait for +# Internal` would be claimed as promises. No row of that shape exists today (no +# `where` clause is rendered at all, and no promised path appears in a bound), +# which is why this is a note rather than a second clause: the fix is to parse +# the header rather than match it, and there is nothing yet to parse it for. +# +# Note what this costs, and it is not nothing: the canonical path is now part of +# the promise file, so moving a promised type between modules diffs it. That is +# churn in the file where churn is expensive. It is still the better trade, +# because the alternative is a promise file that a rename of the promise does +# not touch. +promised_row_pattern() { + local paths + paths="$(promised_paths | paste -sd'|' -)" + if [[ -z "$paths" ]]; then + echo "the api module re-exports nothing: rust/$CORE_LIB no longer declares 'pub mod api'?" >&2 + exit 1 + fi + # `([a-z]+ )*`, not `?`: a row is `pub ` and there can be + # more than one keyword. With `?` a promised type's `pub const fn` or `pub + # unsafe fn` fell to the tripwire file, which is an ordinary thing to add and + # a silent hole. Widening cannot over-claim, because every rendered path + # starts `devlaunch_core::` and no `[a-z]+ ` alternative can consume a segment + # of one: there is no space inside a path. Measured: no row moves today. + printf '%s|^pub ([a-z]+ )*(%s)\\b|^impl.* (%s)\\b' "$API_ROW" "$paths" "$paths" +} + +# The limit, counted: every type the promise file names that is not itself +# promised and owns rows in the tripwire file, as `\t` sorted by +# rows. Those are the types a promised signature hands you and the promise file +# does not cover, so a diff to one of them reads as routine churn and is not. +# +# Read off the checked-in snapshots, so this needs no toolchain and nothing is +# generated. It exists because the header used to name one such type as though +# it were the whole residual, and prose that carries a number nothing recomputes +# is prose that is wrong a release later: `test/test_public_api_snapshots_doc.py` +# diffs the figures in the three places the limit is described against this. +# +# A "type" is a path whose last segment is capitalised, which is what separates +# `domain::spec::DevcontainerRefError` from the module it lives in and from the +# free functions beside it. Ownership is the same anchored subject test the +# classifier uses, not a mention: a row that merely takes one as an argument +# belongs to whatever declares it. +residual_types() { + local api_file="$repo_root/rust/$API_FILE" rest_file="$repo_root/rust/$REST_FILE" + for file in "$api_file" "$rest_file"; do + [[ -r "$file" ]] || { + echo "--print-residual reads the checked-in snapshots and $file is not there." >&2 + exit 1 + } + done + local promised + promised="$(promised_paths)" + grep -oE 'devlaunch_core(::[A-Za-z_][A-Za-z0-9_]*)+' "$api_file" | + grep -E '::[A-Z][A-Za-z0-9_]*$' | + sort -u | + grep -Fxv -f <(printf '%s\n' "$promised") | + while read -r path; do + local rows + rows="$(grep -cE "^pub ([a-z]+ )?$path\\b|^impl.* $path\\b" "$rest_file" || true)" + [[ "$rows" -gt 0 ]] && printf '%s\t%s\n' "$rows" "$path" + done | sort -rn +} + +# One side of the split, over rows on stdin. `grep` says "no match" with status +# 1, which is not an error for a filter -- an empty side is only wrong when a +# whole snapshot is being generated, and the generation path checks it there. +classify() { + local status=0 + grep -E "$@" || status=$? + [[ "$status" -le 1 ]] || exit "$status" +} + case "${1:-}" in --print-pin) echo "$PIN" @@ -96,9 +294,31 @@ case "${1:-}" in printf '%s\n' "${FILES[@]}" exit 0 ;; +--print-promised) + promised_paths + exit 0 + ;; +--print-residual) + residual_types + exit 0 + ;; +--classify) + # The classification, reachable without a nightly toolchain and without + # generating anything -- so the rule above can be exercised on rows chosen to + # be awkward. `test/test_public_api_snapshots_doc.py` is what does that. + pattern="$(promised_row_pattern)" + case "${2:-}" in + api) classify "$pattern" ;; + rest) classify -v "$pattern" ;; + *) + echo "--classify takes 'api' or 'rest'" >&2 + exit 2 + ;; + esac + exit 0 + ;; esac -repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" dest="${1:-$repo_root/rust}" for file in "${FILES[@]}"; do mkdir -p "$dest/$(dirname "$file")" @@ -155,18 +375,38 @@ done cd "$repo_root/rust" core="$(cargo public-api -p devlaunch-core "${FLAGS[@]}")" +pattern="$(promised_row_pattern)" # Two greps rather than one pass with a fallthrough, so the two files are # complements by construction. Either coming out empty means the filter no # longer matches the crate, which is a broken split rather than a small API. -if ! printf '%s\n' "$core" | grep -E "$API_ROW" >"$staging/$API_FILE"; then - echo "no rows matched $API_ROW: devlaunch-core no longer declares an 'api' module?" >&2 +if ! printf '%s\n' "$core" | grep -E "$pattern" >"$staging/$API_FILE"; then + echo "no rows matched the promise: devlaunch-core no longer declares an 'api' module?" >&2 exit 1 fi -if ! printf '%s\n' "$core" | grep -Ev "$API_ROW" >"$staging/$REST_FILE"; then - echo "every row matched $API_ROW: the split has nothing left to classify?" >&2 +if ! printf '%s\n' "$core" | grep -Ev "$pattern" >"$staging/$REST_FILE"; then + echo "every row matched the promise: the split has nothing left to classify?" >&2 exit 1 fi + +# Every promised path has to claim something. Without this the parse above can +# drift silently: `api` grows a re-export form awk reads as a shorter path, or +# a rename leaves a path nothing is rendered at, and the promise file loses the +# rows for it while every test over the two files still passes -- they check the +# split is a partition, not that it is the right one. +# +# A here-string rather than a pipe into `grep -q`: `grep -q` stops reading at +# the first match, `printf` takes a SIGPIPE for the rest, and `pipefail` reports +# that as the pipeline failing -- so every path that *did* claim a row was +# reported as one that had not. +while read -r path; do + if ! grep -qE "^pub ([a-z]+ )?$path\\b|^impl.* $path\\b" <<<"$core"; then + echo "the api module re-exports $path and no rendered row declares it." >&2 + echo "Either that item is gone, or --print-promised is reading the module wrongly." >&2 + exit 1 + fi +done < <(promised_paths) + cargo public-api -p devlaunch-runner "${FLAGS[@]}" >"$staging/$RUNNER_FILE" for file in "${FILES[@]}"; do diff --git a/test/test_public_api_snapshots_doc.py b/test/test_public_api_snapshots_doc.py index 86927e3..ef6eb74 100644 --- a/test/test_public_api_snapshots_doc.py +++ b/test/test_public_api_snapshots_doc.py @@ -40,9 +40,27 @@ CI_CHECK_STEP = "The public surface is the snapshots the repo carries" # The classification itself: the pattern that decides "promise" from "rest". API_ROW_PATTERN = "devlaunch_core::api\\b" -# The ticket that widens the classifier to cover a promised type's methods and -# impls. Named in the docs so the gap is a known follow-up rather than folklore. -WIDENING_TICKET = "352" +# The other snapshot, named in the docs because the widened classifier still does +# not reach everything a promised signature does: a type the `api` module never +# re-exports but a promised method returns is reachable from outside and lives +# only here, so a diff in it can still be a contract change. +REST_SNAPSHOT = "public-api.rest.txt" + +# The residual caveat, pinned by the phrases only it uses. Naming the file was +# not enough on its own and it is worth saying why, because the weak version of +# this guard looked exactly like the strong one: `REST_SNAPSHOT` alone is +# satisfied by `REST_FILE=devlaunch-core/public-api.rest.txt` in the script, by +# the sentence describing the split in lib.rs, and by a table row in the doc, so +# a reviewer deleted the entire caveat from two of the three sites and all +# fourteen tests passed. Each of these appears only in the caveat: +# +# the mechanism -- a type that is handed back but never re-exported; +# the example that makes the scale land, since it is the error type of a +# function that is itself a promise-file row at the `api` path; +# the command that recomputes the scale, so the prose stays checkable. +RESIDUAL_MECHANISM = "never re-exports" +RESIDUAL_EXAMPLE = "DevcontainerRefError" +RESIDUAL_COMMAND = "--print-residual" def script_files() -> list[str]: @@ -177,26 +195,191 @@ def test_the_ci_error_string_sends_a_reader_to_the_document_that_has_the_section ) +def residual() -> tuple[int, int]: + """The limit, as the script counts it: (types, rows). + + Types a promised signature hands back that `api` never re-exports, and the + rows they own in the tripwire file. Asked of the script for the same reason + the file list is: a figure this test kept itself would be a third copy, and + the copy that never goes stale is the one nobody wrote down. + """ + printed = subprocess.run( + [str(SCRIPT), "--print-residual"], + capture_output=True, + text=True, + check=True, + ) + counts = [int(line.split("\t")[0]) for line in printed.stdout.splitlines() if line.strip()] + assert counts, "--print-residual found no residual types at all; the split cannot be that clean" + return len(counts), sum(counts) + + @pytest.mark.unit -def test_the_docs_say_what_the_promise_file_does_not_cover(): +def test_the_docs_say_how_the_promise_file_is_filled_and_what_it_still_misses(): """The overclaim this section is one edit away from becoming again. `cargo public-api` renders methods and impls only at a type's canonical - path, so `api::Launch::run` is in the *rest* file and renaming it leaves the - promise file byte-identical. A guard that is trusted and silently does not - fire is worse than no guard, so the limit is documented where the guard is, - and the ticket that closes it is named. + path, so the classifier reaches `api::Launch::run` by resolving each `api` + re-export back to the path it names (#352). Two things a reader has to be + told, and both live wherever the promise file is described: that the + canonical-path rows in it are there on purpose and are not strays, and that + the rest file can still carry a contract change, because a type the `api` + module never re-exports but a promised signature hands back is reachable + from outside and is classified as binary surface. + + The second half is what this asserts properly now. It used to be spelled as + "the text names public-api.rest.txt", which every one of these files does + for reasons that have nothing to do with the caveat, so the caveat could be + deleted outright and this stayed green. """ for path in (DEV_DOC, SCRIPT, RUST / "devlaunch-core" / "src" / "lib.rs"): text = path.read_text(encoding="utf-8") assert "canonical" in text, ( - f"{path.name} describes the promise file without the canonical-path limit " - "that decides what it can see" + f"{path.name} describes the promise file without the canonical-path " + "rendering that decides how it is filled" + ) + assert REST_SNAPSHOT in text, ( + f"{path.name} describes the promise file without naming {REST_SNAPSHOT}, " + "which is where a promised signature's own types are still classified" + ) + assert RESIDUAL_MECHANISM in text, ( + f"{path.name} describes the promise file and not the limit on it: no " + f"sentence saying a type the api module {RESIDUAL_MECHANISM} but a " + "promised signature hands back is still classified as binary surface" ) - assert WIDENING_TICKET in text, ( - f"{path.name} states the limit without naming issue #{WIDENING_TICKET}, " - "which is what turns a known gap into a tracked one" + assert RESIDUAL_EXAMPLE in text, ( + f"{path.name} states the limit without naming {RESIDUAL_EXAMPLE}, which " + "is the case that shows what it costs: the error type of " + "api::resolve_devcontainer_ref, a promise-file row at the api path, " + "while renaming one of its variants diffs only the tripwire file" ) + assert RESIDUAL_COMMAND in text, ( + f"{path.name} states the limit without naming {RESIDUAL_COMMAND}, so a " + "reader is told the residual exists and given no way to see what is " + "in it today" + ) + + +@pytest.mark.unit +def test_the_documented_scale_of_the_limit_is_the_measured_one(): + """The number, because naming one type made six hundred rows read as one. + + Every site above described the residual as `flows::launch::Launched` and + nothing else. It is 39 types, and a reviewer who has been told the limit is + one type reads the other 38's diffs as routine churn. So the figure is + written down, and written down means diffed: this recomputes it from the + checked-in snapshots and holds the prose to it. A surface change that moves + the count turns this red in the same run that regenerates the snapshots, + which is when the sentence is cheapest to fix. + + The count of *types* and not of rows, deliberately. The row total moves + whenever anything is added to any one of the 39, which is often and says + nothing about the scale of the limit; the type count is what a reader is + calibrating on and it moves only when the residual genuinely grows. The + prose gives rows as a round number for that reason, and + ``--print-residual`` is where an exact one lives. + """ + types, _rows = residual() + for path in (DEV_DOC, SCRIPT, RUST / "devlaunch-core" / "src" / "lib.rs"): + text = path.read_text(encoding="utf-8") + # The number *and* the noun it counts. A bare `\b39\b` was satisfied + # twice over by things that are not this: `395 rows moved` two + # paragraphs up, and "39 of them" about orphaned Docker volumes five + # hundred lines away in the same document. Matching "39 types" and "39 + # such types" is what makes deleting the caveat show up here. + assert re.search(rf"\b{types}\b(?: \w+)? types", text), ( + f"{path.name} does not carry the current number of types in the " + f"residual ({types}). Regenerating the snapshots moved it; update the " + f"sentence there, or run {SCRIPT.name} {RESIDUAL_COMMAND} to see what " + "changed" + ) + + +def classify(kind: str, rows: list[str]) -> list[str]: + """One side of the split, as the script itself decides it. + + The classification is a filter over rows, and the script is the only place + it exists -- so this exercises the real one on rows chosen to be awkward, + rather than restating the pattern here where the restatement is what would + be tested. + """ + done = subprocess.run( + [str(SCRIPT), "--classify", kind], + input="".join(f"{row}\n" for row in rows), + capture_output=True, + text=True, + check=True, + ) + return done.stdout.splitlines() + + +# Rows in the shape `cargo public-api` renders, naming types this crate really +# has, so the classifier is exercised against the `api` module as it stands +# rather than against a fiction. `Launch` and `Host` are re-exported; the branch +# manager is not. +PROMISED_ROWS = [ + "pub struct devlaunch_core::api::Launch<'a, 'r, 'l>", + "impl<'a, 'r, 'l> devlaunch_core::flows::launch::Launch<'a, 'r, 'l>", + "pub fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::run(&mut self) -> ()", + # More than one keyword between `pub` and the path. No row of this shape + # exists yet, and the point is that one can be added without noticing: a + # `const fn` constructor on a promised type is an ordinary thing to write, + # and the pattern used to allow exactly one keyword, so it went to the + # tripwire file where a rename of it reads as routine churn. + "pub const fn devlaunch_core::flows::launch::Launch<'a, 'r, 'l>::konst() -> ()", + "impl core::fmt::Debug for devlaunch_core::flows::launch::Host", +] +UNPROMISED_ROWS = [ + "pub mod devlaunch_core", + "pub struct devlaunch_core::flows::branch_manager::BranchManager<'a>", + # The trap the whole rule turns on: a promised type in an argument, on a + # method of something that is not promised at all. + "pub fn devlaunch_core::flows::branch_manager::BranchManager<'a>::adopt" + "(&self, &devlaunch_core::flows::launch::Host) -> ()", + # And the boundary the `\b` is for. + "pub mod devlaunch_core::apiary", +] + + +@pytest.mark.unit +def test_a_promised_types_canonical_rows_are_classified_as_promise(): + """The finding this ticket is about, at the seam that decides it. + + `Launch::run` is rendered at `flows::launch::Launch`, never at the `api` + path it is re-exported under, so a classifier that matches the `api` path + alone keeps the type's declaration and drops its only method. + """ + kept = classify("api", PROMISED_ROWS + UNPROMISED_ROWS) + assert kept == PROMISED_ROWS, ( + "the classifier does not claim a promised type's canonical-path rows, so " + "renaming Launch::run leaves the promise file byte-identical" + ) + + +@pytest.mark.unit +def test_naming_a_promised_type_in_a_signature_does_not_promise_the_signature(): + """The control, and the reason the rule is anchored rather than a substring. + + Promised types are arguments and return types all over this crate. Claiming + every row that mentions one would pull most of the binary surface into the + promise file, which is the failure the split exists to prevent, wearing the + other hat. + """ + left = classify("rest", PROMISED_ROWS + UNPROMISED_ROWS) + assert left == UNPROMISED_ROWS, ( + "the classifier claimed a row that only mentions a promised type, or " + "dropped one that mentions nothing promised at all" + ) + + +@pytest.mark.unit +def test_the_two_sides_of_the_classification_are_a_partition(): + rows = PROMISED_ROWS + UNPROMISED_ROWS + kept, left = classify("api", rows), classify("rest", rows) + assert sorted(kept + left) == sorted(rows), ( + "a row was dropped by both sides or kept by both; the two files are " + "complements or they are not a split at all" + ) def ci_step_script(job: str, step_name: str) -> str: