Skip to main content

lightshuttle_export/
lib.rs

1#![deny(missing_docs)]
2//! Manifest to deployment artifact transpilation for LightShuttle.
3//!
4//! # Position in the crate graph
5//!
6//! `lightshuttle-export` sits above `lightshuttle-manifest` (the parsed
7//! YAML representation) and `lightshuttle-spec` (the canonical resource
8//! specification). It depends on both; the CLI crate depends on this one
9//! to write the produced files to disk.
10//!
11//! # Pipeline: manifest -> IR -> artifacts
12//!
13//! The export pipeline follows a compiler shape:
14//!
15//! 1. **Lowering** ([`lower`]): a [`lightshuttle_manifest::Manifest`] is
16//!    lowered into a target-agnostic [`ExportModel`] (the IR). Every
17//!    resource is resolved through `lightshuttle-spec` so the model
18//!    inherits the same image, port, environment, and healthcheck defaults
19//!    that the runtime applies - no drift between `lightshuttle up` and
20//!    `lightshuttle export`.
21//! 2. **Emission** ([`Emitter`]): a target-specific emitter consumes the
22//!    [`ExportModel`] and produces [`ExportArtifacts`], a list of named
23//!    files whose textual contents are ready to write. Three emitters ship
24//!    out of the box: [`ComposeEmitter`], [`KubernetesEmitter`], and
25//!    [`HelmEmitter`].
26//! 3. **Resolution** ([`resolve`]): pure helpers that turn the optional
27//!    `export:` manifest section into concrete per-target values (namespace,
28//!    replica count, image pull policy, chart name). All emitters share
29//!    this module so defaults are defined and tested in one place.
30//!
31//! # No daemon dependency
32//!
33//! This crate carries no container daemon dependency. It only reads the
34//! manifest and the resolved specification, so it transpiles identically
35//! on a developer machine or in CI without Docker.
36//!
37//! # Quick start
38//!
39//! ```rust,no_run
40//! use lightshuttle_export::{lower, ComposeEmitter, Emitter};
41//! use lightshuttle_manifest::Manifest;
42//!
43//! # fn main() -> lightshuttle_export::Result<()> {
44//! // Load a manifest from disk (I/O, so no_run).
45//! let manifest: Manifest = todo!("parse from YAML");
46//!
47//! // Lower the manifest into the neutral IR.
48//! let model = lower(&manifest)?;
49//!
50//! // Emit Docker Compose artifacts.
51//! let emitter = ComposeEmitter;
52//! let artifacts = emitter.emit(&model)?;
53//!
54//! for file in &artifacts.files {
55//!     println!("{}: {} bytes", file.path.display(), file.contents.len());
56//! }
57//! # Ok(())
58//! # }
59//! ```
60
61mod emit;
62mod emitters;
63mod error;
64mod lower;
65mod model;
66pub mod resolve;
67
68pub use crate::emit::Emitter;
69pub use crate::emitters::{ComposeEmitter, HelmEmitter, KubernetesEmitter};
70pub use crate::error::{ExportError, Result};
71pub use crate::lower::lower;
72pub use crate::model::{
73    ExportArtifacts, ExportFile, ExportModel, ExportProject, ExportService, Target,
74};