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(crate) const MAX_FILE_LOADING_CONCURRENCY: usize = 16;
28
29pub 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
43pub 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#[derive(Debug)]
53pub enum FilesMountStrategy {
54 Copy(PathBuf),
56 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}