1#![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
26pub use local::requires_service_chaining;
27pub use local::WasmLoader;
28
29pub(crate) const MAX_FILE_LOADING_CONCURRENCY: usize = 16;
31
32pub async fn from_file(
36 manifest_path: impl AsRef<Path>,
37 files_mount_strategy: FilesMountStrategy,
38 cache_root: Option<PathBuf>,
39) -> Result<LockedApp> {
40 let path = manifest_path.as_ref();
41 let app_root = parent_dir(path).context("manifest path has no parent directory")?;
42 let loader = LocalLoader::new(&app_root, files_mount_strategy, cache_root).await?;
43 loader.load_file(path).await
44}
45
46pub async fn from_wasm_file(wasm_path: impl AsRef<Path>) -> Result<LockedApp> {
48 let app_root = std::env::current_dir()?;
49 let manifest = single_file_manifest(wasm_path)?;
50 let loader = LocalLoader::new(&app_root, FilesMountStrategy::Direct, None).await?;
51 loader.load_manifest(manifest).await
52}
53
54#[derive(Debug)]
56pub enum FilesMountStrategy {
57 Copy(PathBuf),
59 Direct,
63}
64
65fn single_file_manifest(
66 wasm_path: impl AsRef<Path>,
67) -> anyhow::Result<spin_manifest::schema::v2::AppManifest> {
68 use serde::Deserialize;
69
70 let wasm_path_str = wasm_path
71 .as_ref()
72 .to_str()
73 .context("Failed to stringise Wasm file path")?
74 .to_owned();
75 let app_name = wasm_path
76 .as_ref()
77 .file_stem()
78 .and_then(|s| s.to_str())
79 .unwrap_or("wasm-file")
80 .to_owned();
81
82 let manifest = toml::toml!(
83 spin_manifest_version = 2
84
85 [application]
86 name = app_name
87
88 [[trigger.http]]
89 route = "/..."
90 component = { source = wasm_path_str }
91 );
92
93 let manifest = spin_manifest::schema::v2::AppManifest::deserialize(manifest)?;
94
95 Ok(manifest)
96}