runmat_execution_artifact/bundle/
manifest.rs1use std::collections::BTreeSet;
2
3use runmat_execution::resource::Capability;
4use runmat_execution::{Digest, ProgramRevision};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 ArtifactError, ArtifactResult, BundleCodeClosure, LogicalObject, ObjectDescriptor,
9 ProgramArtifact, ProgramBuildRecipe,
10};
11
12pub const EXECUTION_BUNDLE_SCHEMA_VERSION: u16 = 3;
13
14#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
15#[serde(deny_unknown_fields)]
16pub struct ProjectRevisionRecord {
17 pub graph_digest: Digest,
18 pub source_digest: Digest,
19}
20
21#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
22#[serde(deny_unknown_fields)]
23pub struct BundleCallable {
24 pub owner_identity: String,
25 pub qualified_name: String,
26 pub source_digest: Digest,
27}
28
29#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
30#[serde(deny_unknown_fields)]
31pub struct BuildResourceDeclaration {
32 pub cpu_millicores: u32,
33 pub memory_bytes: u64,
34 pub scratch_bytes: u64,
35}
36
37#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
38#[serde(deny_unknown_fields)]
39pub struct BundleManifest {
40 pub schema_version: u16,
41 pub program_revision: ProgramRevision,
42 pub project_revision: ProjectRevisionRecord,
43 pub code_closure: BundleCodeClosure,
44 pub sources: Vec<ObjectDescriptor>,
45 pub callables: Vec<BundleCallable>,
46 pub recipes: Vec<ProgramBuildRecipe>,
47 pub artifacts: Vec<ProgramArtifact>,
48 pub requested_capabilities: BTreeSet<Capability>,
49 pub resources: BuildResourceDeclaration,
50 pub portable_environment: Vec<(String, String)>,
51}
52
53#[derive(Clone, Debug, Eq, PartialEq)]
54pub struct ExecutionBundle {
55 pub manifest: BundleManifest,
56 pub objects: Vec<LogicalObject>,
57}
58
59impl ExecutionBundle {
60 pub fn validate(&self) -> ArtifactResult<()> {
61 super::validator::validate(self)
62 }
63
64 pub fn identity(&self) -> ArtifactResult<Digest> {
65 self.validate()?;
66 super::validator::identity(&self.manifest)
67 }
68
69 pub fn project_handoff_at(
74 &self,
75 root: &std::path::Path,
76 ) -> ArtifactResult<runmat_package::FrozenProjectHandoff> {
77 self.validate()?;
78 let BundleCodeClosure::SourceProject { handoff } = &self.manifest.code_closure else {
79 return Err(ArtifactError::Invalid(
80 "compiled execution bundle has no source project to materialize".into(),
81 ));
82 };
83 let mut handoff = handoff.clone();
84 handoff.project.workspace_root = root.to_path_buf();
85 handoff.project.manifest_path = root.join("runmat.toml");
86 for path in handoff.project.access_paths.values_mut() {
87 let relative = runmat_package::NormalizedRelativePath::new(path.as_path())
88 .map_err(|error| crate::ArtifactError::Invalid(error.to_string()))?;
89 *path = root.join(relative.as_str());
90 }
91 handoff
92 .validate()
93 .map_err(|error| crate::ArtifactError::Invalid(error.to_string()))?;
94 Ok(handoff)
95 }
96
97 pub fn requires_source_project(&self) -> bool {
98 matches!(
99 self.manifest.code_closure,
100 BundleCodeClosure::SourceProject { .. }
101 )
102 }
103}