spin_loader/
lib.rs

1//! Loaders for Spin applications.
2//! This crate implements the possible application sources for Spin applications,
3//! and includes functionality to convert the specific configuration (for example
4//! local configuration files or from OCI) into Spin configuration that
5//! can be consumed by the Spin execution context.
6//!
7//! This crate can be extended (or replaced entirely) to support additional loaders,
8//! and any implementation that produces a `Application` is compatible
9//! with the Spin execution context.
10
11#![deny(missing_docs)]
12
13use std::path::{Path, PathBuf};
14
15use anyhow::{Context, Result};
16use local::LocalLoader;
17use spin_common::paths::parent_dir;
18use spin_locked_app::locked::LockedApp;
19
20pub mod cache;
21mod fs;
22#[cfg(feature = "async-io")]
23mod http;
24mod local;
25
26/// Maximum number of files to copy (or download) concurrently
27pub(crate) const MAX_FILE_LOADING_CONCURRENCY: usize = 16;
28
29/// Load a Spin locked app from a spin.toml manifest file. If `files_mount_root`
30/// is given, `files` mounts will be copied to that directory. If not, `files`
31/// mounts will validated as "direct mounts".
32pub async fn from_file(
33    manifest_path: impl AsRef<Path>,
34    files_mount_strategy: FilesMountStrategy,
35    cache_root: Option<PathBuf>,
36) -> Result<LockedApp> {
37    let path = manifest_path.as_ref();
38    let app_root = parent_dir(path).context("manifest path has no parent directory")?;
39    let loader = LocalLoader::new(&app_root, files_mount_strategy, cache_root).await?;
40    loader.load_file(path).await
41}
42
43/// Load a Spin locked app from a standalone Wasm file.
44pub async fn from_wasm_file(wasm_path: impl AsRef<Path>) -> Result<LockedApp> {
45    let app_root = std::env::current_dir()?;
46    let manifest = single_file_manifest(wasm_path)?;
47    let loader = LocalLoader::new(&app_root, FilesMountStrategy::Direct, None).await?;
48    loader.load_manifest(manifest).await
49}
50
51/// The strategy to use for mounting WASI files into a guest.
52#[derive(Debug)]
53pub enum FilesMountStrategy {
54    /// Copy files into the given mount root directory.
55    Copy(PathBuf),
56    /// Mount files directly from their source director(ies). This only
57    /// supports mounting full directories; mounting single files, glob
58    /// patterns, and `exclude_files` are not supported.
59    Direct,
60}
61
62fn single_file_manifest(
63    wasm_path: impl AsRef<Path>,
64) -> anyhow::Result<spin_manifest::schema::v2::AppManifest> {
65    use serde::Deserialize;
66
67    let wasm_path_str = wasm_path
68        .as_ref()
69        .to_str()
70        .context("Failed to stringise Wasm file path")?
71        .to_owned();
72    let app_name = wasm_path
73        .as_ref()
74        .file_stem()
75        .and_then(|s| s.to_str())
76        .unwrap_or("wasm-file")
77        .to_owned();
78
79    let manifest = toml::toml!(
80        spin_manifest_version = 2
81
82        [application]
83        name = app_name
84
85        [[trigger.http]]
86        route = "/..."
87        component = { source = wasm_path_str }
88    );
89
90    let manifest = spin_manifest::schema::v2::AppManifest::deserialize(manifest)?;
91
92    Ok(manifest)
93}