Skip to main content

one_member/
one_member.rs

1//! One-member verified transaction.
2//!
3//! Demonstrates the supported path:
4//! `InstallPlan -> prepare -> verify_integrity -> validate -> commit(ownership)`.
5//!
6//! This file is the source of the quickstart snippet in `README.md` and
7//! `docs/quickstart.md`, which reproduce it verbatim. Keep the three in sync:
8//! the gate builds and runs this example, so a divergence is a wrong doc.
9//!
10//! Run with `cargo run -p eggup-core --example one_member`.
11//! Output: `committed: Committed`
12
13use eggup_core::{
14    AbsentPolicy, AllValidators, ArtifactMember, ArtifactSet, CommitOwnership,
15    ExistingAsOwnedVerifier, InstallPlan, IntegrityRequirement, MemberId, ProductId, ReleaseId,
16    TransactionDisposition,
17};
18use std::fs;
19use std::path::PathBuf;
20use std::time::{SystemTime, UNIX_EPOCH};
21
22fn temp_root(prefix: &str) -> PathBuf {
23    let nanos = SystemTime::now()
24        .duration_since(UNIX_EPOCH)
25        .map(|d| d.as_nanos())
26        .unwrap_or(0);
27    std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id()))
28}
29
30fn main() -> Result<(), Box<dyn std::error::Error>> {
31    let base = temp_root("eggup-quickstart");
32    let (inputs, root) = (base.join("inputs"), base.join("install"));
33    fs::create_dir_all(inputs.join("bin"))?;
34    fs::create_dir_all(root.join("bin"))?;
35    fs::write(inputs.join("app"), b"new-app")?;
36
37    // 1. Describe one member, with the SHA-256 you expect to verify.
38    let source = inputs.join("app");
39    let digest = eggup_core::hash_file(&source)?;
40    let member = ArtifactMember::new(MemberId::new("main")?, source, "bin/app")?
41        .with_integrity(IntegrityRequirement::Sha256(digest));
42
43    // 2. Name the product, release, install root, and artifact set.
44    let plan = InstallPlan::new(
45        ProductId::new("demo")?,
46        ReleaseId::new("1.0.0")?,
47        &root,
48        ArtifactSet::single(member)?,
49    )?;
50
51    // 3. Stage, verify, validate, then commit with proven ownership.
52    let receipt = plan
53        .prepare()?
54        .verify_integrity()?
55        .validate(&AllValidators::new())?
56        .commit(CommitOwnership::new(
57            &ExistingAsOwnedVerifier,
58            AbsentPolicy::AllowCreate,
59        ))?;
60
61    assert_eq!(receipt.disposition(), TransactionDisposition::Committed);
62    assert_eq!(fs::read(root.join("bin/app"))?, b"new-app");
63    let _ = fs::remove_dir_all(&base);
64    println!("committed: {:?}", receipt.disposition());
65    Ok(())
66}