docs(package): explain packaging and dependency workflows
This commit is contained in:
@@ -1,4 +1,22 @@
|
||||
//! Local build, watch, and deployment loop for Component development.
|
||||
//!
|
||||
//! The loop fingerprints Rust/WIT inputs, materializes WIT dependencies,
|
||||
//! compiles a Component, creates a content-addressed development revision,
|
||||
//! registers it, and atomically switches the Console deployment. A failed
|
||||
//! build or deployment never removes the previously active revision.
|
||||
//!
|
||||
//! Build and deployment are separate states. Once a build succeeds,
|
||||
//! `pending_deployment` retains that exact package and retries network or
|
||||
//! Console failures without rebuilding it. A later source change supersedes
|
||||
//! the pending package and starts a new build.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```text
|
||||
//! cargo run -p wasmeld-package --bin wasmeld -- \
|
||||
//! dev components/counter/Cargo.toml \
|
||||
//! --console http://127.0.0.1:8080
|
||||
//! ```
|
||||
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
@@ -57,6 +75,9 @@ pub(crate) fn run(arguments: Vec<String>) -> Result<(), Box<dyn std::error::Erro
|
||||
fs::create_dir_all(&temporary_dir)?;
|
||||
let output = temporary_dir.join("component.wasmpkg");
|
||||
let mut observed = None;
|
||||
// Keeping this separate from `observed` lets transient deployment errors
|
||||
// retry the already-built bytes. Rebuilding on every HTTP failure would
|
||||
// waste time and could create a different revision unexpectedly.
|
||||
let mut pending_deployment = None;
|
||||
|
||||
println!("watching:");
|
||||
@@ -138,6 +159,10 @@ fn deploy_component(
|
||||
console: &str,
|
||||
packed: &PackedComponent,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Order is intentional: register makes the immutable revision available,
|
||||
// activate switches new gateway resolutions, and only then may old
|
||||
// development revisions be removed. Cleanup is best-effort because a
|
||||
// successful deployment must not be reported as failed due to stale files.
|
||||
register(client, console, packed)?;
|
||||
activate(
|
||||
client,
|
||||
@@ -235,6 +260,9 @@ fn register(
|
||||
if response.status().is_success() {
|
||||
return Ok(());
|
||||
}
|
||||
// Retrying a package whose registration response was lost is safe only
|
||||
// when the exact immutable identity already exists. Do not treat every
|
||||
// conflict as success; it may represent a different control-plane error.
|
||||
if response.status() == StatusCode::CONFLICT
|
||||
&& service_exists(
|
||||
client,
|
||||
@@ -334,6 +362,9 @@ fn watch_roots(manifest_path: &Path) -> Result<Vec<PathBuf>, Box<dyn std::error:
|
||||
let module_path = component_root.join(MODULE_MANIFEST_FILE);
|
||||
if module_path.is_file() {
|
||||
let module = ModuleManifest::read(&module_path)?;
|
||||
// Path replacements are source inputs just like the Component itself.
|
||||
// Registry dependencies are immutable and represented by wit.lock, so
|
||||
// they do not need independent watch roots.
|
||||
for replacement in module.replacements.values() {
|
||||
let path = component_root.join(&replacement.path);
|
||||
if path.exists() {
|
||||
@@ -351,6 +382,8 @@ fn source_fingerprint(roots: &[PathBuf]) -> Result<Vec<u8>, Box<dyn std::error::
|
||||
}
|
||||
let mut digest = Sha256::new();
|
||||
for path in files {
|
||||
// Include paths as well as bytes so file renames trigger a rebuild even
|
||||
// when their contents are unchanged.
|
||||
digest.update(path.to_string_lossy().as_bytes());
|
||||
match fs::read(&path) {
|
||||
Ok(bytes) => digest.update(bytes),
|
||||
@@ -384,6 +417,8 @@ fn ignored_directory(path: &Path) -> bool {
|
||||
name,
|
||||
Some(".git" | ".wasmeld" | "deps" | "dist" | "node_modules" | "target")
|
||||
) {
|
||||
// `wit/deps` is generated by dependency sync. Watching it would make
|
||||
// each build rewrite watched files and trigger an endless rebuild.
|
||||
return name != Some("deps")
|
||||
|| path
|
||||
.parent()
|
||||
@@ -395,6 +430,8 @@ fn ignored_directory(path: &Path) -> bool {
|
||||
}
|
||||
|
||||
fn is_source_file(path: &Path) -> bool {
|
||||
// The list is deliberately narrow: fingerprints should represent inputs
|
||||
// to Cargo/WIT resolution, not editor state or generated artifacts.
|
||||
matches!(
|
||||
path.extension().and_then(|extension| extension.to_str()),
|
||||
Some("rs" | "wit")
|
||||
|
||||
Reference in New Issue
Block a user