cubecl_environment/bundle/
manifest.rs1use alloc::string::{String, ToString};
2use alloc::vec::Vec;
3
4#[cfg(native_cache)]
6pub(super) const MANIFEST_KEY: &str = "manifest";
7
8pub const MANIFEST_SCHEMA: u32 = 1;
10
11#[derive(Debug)]
13pub enum BundleError {
14 #[cfg(native_cache)]
16 Io(std::io::Error),
17 #[cfg(native_cache)]
19 Storage(String),
20 NotABundle,
22 InvalidManifest(String),
24 UnsupportedSchema(u32),
26 #[cfg(native_cache)]
28 UnsupportedDatabase(String),
29 TooLarge,
31 Flat(super::EmbeddedBundleError),
33}
34
35impl core::fmt::Display for BundleError {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 match self {
38 #[cfg(native_cache)]
39 BundleError::Io(err) => write!(f, "bundle io error: {err}"),
40 #[cfg(native_cache)]
41 BundleError::Storage(err) => write!(f, "bundle storage error: {err}"),
42 BundleError::NotABundle => write!(f, "the file carries no bundle manifest"),
43 BundleError::InvalidManifest(err) => write!(f, "invalid bundle manifest: {err}"),
44 BundleError::UnsupportedSchema(schema) => {
45 write!(
46 f,
47 "unsupported bundle schema {schema} (this build supports {MANIFEST_SCHEMA})"
48 )
49 }
50 #[cfg(native_cache)]
51 BundleError::UnsupportedDatabase(schema) => {
52 write!(
53 f,
54 "unsupported bundle database schema {schema} (this build reads {})",
55 crate::persistence::turso::SCHEMA_VERSION
56 )
57 }
58 BundleError::TooLarge => write!(
59 f,
60 "the flat bundle format addresses at most {} bytes; export fewer namespaces",
61 u32::MAX
62 ),
63 BundleError::Flat(err) => write!(f, "{err}"),
66 }
67 }
68}
69
70impl core::error::Error for BundleError {}
71
72impl From<super::EmbeddedBundleError> for BundleError {
73 fn from(err: super::EmbeddedBundleError) -> Self {
74 Self::Flat(err)
75 }
76}
77
78#[cfg(native_cache)]
79impl From<std::io::Error> for BundleError {
80 fn from(err: std::io::Error) -> Self {
81 Self::Io(err)
82 }
83}
84
85#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
89pub struct BundleManifest {
90 pub schema: u32,
92 pub name: String,
94 pub cubecl_version: String,
97 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub created_unix_secs: Option<u64>,
100 #[serde(default, rename = "environments")]
102 pub environments: Vec<EnvironmentInfo>,
103}
104
105#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
108pub struct EnvironmentInfo {
109 #[serde(default)]
111 pub label: String,
112 #[serde(default)]
114 pub os: String,
115 #[serde(default)]
117 pub arch: String,
118 #[serde(default)]
120 pub devices: Vec<String>,
121}
122
123impl BundleManifest {
124 pub fn parse(content: &[u8]) -> Result<Self, BundleError> {
131 if content.is_empty() {
132 return Err(BundleError::NotABundle);
133 }
134
135 let manifest: Self = serde_json::from_slice(content)
136 .map_err(|err| BundleError::InvalidManifest(err.to_string()))?;
137
138 if manifest.schema != MANIFEST_SCHEMA {
139 return Err(BundleError::UnsupportedSchema(manifest.schema));
140 }
141
142 Ok(manifest)
143 }
144
145 pub fn warn_on_version_mismatch(&self) {
151 if self.cubecl_version != env!("CARGO_PKG_VERSION") {
152 log::warn!(
153 "Bundle '{}' was built for cubecl {}, running {}; its entries will be ignored.",
154 self.name,
155 self.cubecl_version,
156 env!("CARGO_PKG_VERSION"),
157 );
158 }
159 }
160
161 #[cfg(native_cache)]
169 pub fn new(database: &crate::persistence::Database) -> Result<Self, BundleError> {
170 database.with_connection(Self::read)
171 }
172
173 #[cfg(native_cache)]
181 pub fn write_to(&self, database: &crate::persistence::Database) -> Result<(), BundleError> {
182 database.with_connection(|connection| self.write(connection))
183 }
184
185 #[cfg(native_cache)]
187 pub(super) fn read(connection: &turso::Connection) -> Result<Self, BundleError> {
188 let content = crate::persistence::turso::meta_get(connection, MANIFEST_KEY)
189 .map_err(super::sqlite::missing_meta)?
190 .ok_or(BundleError::NotABundle)?;
191
192 Self::parse(content.as_bytes())
193 }
194
195 #[cfg(native_cache)]
197 pub(super) fn write(&self, connection: &turso::Connection) -> Result<(), BundleError> {
198 let content = serde_json::to_string_pretty(self)
199 .map_err(|err| BundleError::InvalidManifest(err.to_string()))?;
200
201 crate::persistence::turso::meta_set(connection, MANIFEST_KEY, &content)
202 .map_err(super::export::storage_error)
203 }
204}