Skip to main content

hm_plugin_protocol/
executor.rs

1//! Wire types passed to and returned by step-executor plugins.
2
3use std::collections::BTreeMap;
4
5use schemars::JsonSchema as DeriveJsonSchema;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::ir::CommandStep;
10
11/// Opaque archive handle. The plugin streams bytes via
12/// `hm_archive_read(id, offset, max)`.
13#[derive(
14    Debug,
15    Clone,
16    Copy,
17    PartialEq,
18    Eq,
19    Hash,
20    Serialize,
21    Deserialize,
22    DeriveJsonSchema,
23    derive_more::From,
24    derive_more::Deref,
25    derive_more::Display,
26)]
27#[serde(transparent)]
28pub struct ArchiveId(pub Uuid);
29
30/// Opaque snapshot reference. For the docker plugin this is an image
31/// tag; other plugins are free to encode their own format. The host
32/// never inspects the contents.
33#[derive(
34    Debug,
35    Clone,
36    PartialEq,
37    Eq,
38    Hash,
39    Serialize,
40    Deserialize,
41    DeriveJsonSchema,
42    derive_more::From,
43    derive_more::Deref,
44    derive_more::Display,
45)]
46#[serde(transparent)]
47pub struct SnapshotRef(pub String);
48
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
50pub struct ArtifactRef {
51    pub key: String,
52    pub mime: String,
53    pub size_bytes: u64,
54}
55
56/// Host-decided cache outcome. The executor honours this; it does
57/// not re-decide.
58#[derive(
59    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema, derive_more::IsVariant,
60)]
61#[serde(tag = "kind", rename_all = "snake_case")]
62pub enum CacheDecision {
63    /// Boot from `tag`; skip running `cmd`.
64    Hit { tag: SnapshotRef },
65    /// Run `cmd`; on success, commit to `tag` and report it back in
66    /// `StepResult::committed_snapshot`.
67    MissBuildAs { tag: SnapshotRef },
68    /// Run `cmd`; do not commit.
69    MissNoCommit,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
73#[serde(deny_unknown_fields)]
74pub struct ExecutorInput {
75    pub step: CommandStep,
76    pub workspace_archive_id: ArchiveId,
77    pub env: BTreeMap<String, String>,
78    pub workdir: String,
79    pub run_id: Uuid,
80    pub step_id: Uuid,
81    /// Host-decided; see [`CacheDecision`]. Every step has one.
82    pub cache_lookup: CacheDecision,
83
84    /// Snapshot tag of the upstream step in this chain (if any),
85    /// or of the chain-fork parent. When `Some`, the executor must
86    /// boot from this tag rather than `step.image` — that's how
87    /// chain-stepwise filesystem inheritance works: the orchestrator
88    /// commits a snapshot between steps and the next step boots from
89    /// it.
90    #[serde(default)]
91    pub parent_snapshot: Option<SnapshotRef>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
95pub struct StepResult {
96    pub exit_code: i32,
97    /// `Some(tag)` when the executor wrote a snapshot for this step
98    /// (typically only on `CacheDecision::MissBuildAs`).
99    pub committed_snapshot: Option<SnapshotRef>,
100    pub artifacts: Vec<ArtifactRef>,
101}