Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions crates/loader/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,20 @@ pub async fn from_file(
app: impl AsRef<Path>,
base_dst: Option<impl AsRef<Path>>,
bindle_connection: &Option<BindleConnectionInfo>,
include_components: Vec<String>,
) -> Result<Application> {
let app = absolutize(app)?;
let manifest = raw_manifest_from_file(&app).await?;
validate_raw_app_manifest(&manifest)?;

prepare_any_version(manifest, app, base_dst, bindle_connection).await
prepare_any_version(
manifest,
app,
base_dst,
bindle_connection,
include_components,
)
.await
}

/// Reads the spin.toml file as a raw manifest.
Expand Down Expand Up @@ -93,9 +101,12 @@ async fn prepare_any_version(
src: impl AsRef<Path>,
base_dst: Option<impl AsRef<Path>>,
bindle_connection: &Option<BindleConnectionInfo>,
include_components: Vec<String>,
) -> Result<Application> {
match raw {
RawAppManifestAnyVersion::V1(raw) => prepare(raw, src, base_dst, bindle_connection).await,
RawAppManifestAnyVersion::V1(raw) => {
prepare(raw, src, base_dst, bindle_connection, include_components).await
}
}
}

Expand Down Expand Up @@ -125,26 +136,38 @@ pub fn validate_raw_app_manifest(raw: &RawAppManifestAnyVersion) -> Result<()> {
Ok(())
}

fn include_component(components: &Vec<String>, component_id: &String) -> bool {
if components.is_empty() {
true
} else {
components.contains(component_id)
}
}

/// Converts a raw application manifest into Spin configuration.
async fn prepare(
raw: RawAppManifest,
src: impl AsRef<Path>,
base_dst: Option<impl AsRef<Path>>,
bindle_connection: &Option<BindleConnectionInfo>,
include_components: Vec<String>,
) -> Result<Application> {
let info = info(raw.info, &src);

error_on_duplicate_ids(raw.components.clone())?;

let component_triggers = raw
.components
.iter()
.map(|c| (c.id.clone(), c.trigger.clone()))
.clone()
.into_iter()
.filter(|c| include_component(&include_components, &c.id))
.map(|c| (c.id.clone(), c.trigger))
.collect();

let components = future::join_all(
raw.components
.into_iter()
.filter(|c| include_component(&include_components, &c.id))
.map(|c| async { core(c, &src, base_dst.as_ref(), bindle_connection).await })
.collect::<Vec<_>>(),
)
Expand All @@ -153,6 +176,16 @@ async fn prepare(
.collect::<Result<Vec<_>>>()
.context("Failed to prepare configuration")?;

if components.is_empty() {
match include_components.is_empty() {
true => bail!("No components found in manifest"),
false => bail!(
"No components found in manifest matching '{}'",
include_components.join(", "),
),
}
}

let variables = raw
.variables
.into_iter()
Expand Down
55 changes: 50 additions & 5 deletions crates/loader/src/local/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ async fn test_from_local_source() -> Result<()> {

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None).await?;
let app = from_file(MANIFEST, Some(dir), &None, vec![]).await?;

assert_eq!(app.info.name, "spin-local-source-test");
assert_eq!(app.info.version, "1.0.0");
Expand Down Expand Up @@ -157,7 +157,7 @@ async fn test_invalid_manifest() -> Result<()> {

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None).await;
let app = from_file(MANIFEST, Some(dir), &None, vec![]).await;

let e = app.unwrap_err().to_string();
assert!(
Expand Down Expand Up @@ -214,7 +214,7 @@ async fn test_duplicate_component_id_is_rejected() -> Result<()> {

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None).await;
let app = from_file(MANIFEST, Some(dir), &None, vec![]).await;

assert!(
app.is_err(),
Expand All @@ -236,7 +236,7 @@ async fn test_insecure_allow_all_with_invalid_url() -> Result<()> {

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None).await;
let app = from_file(MANIFEST, Some(dir), &None, vec![]).await;

assert!(
app.is_ok(),
Expand All @@ -252,7 +252,7 @@ async fn test_invalid_url_in_allowed_http_hosts_is_rejected() -> Result<()> {

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None).await;
let app = from_file(MANIFEST, Some(dir), &None, vec![]).await;

assert!(app.is_err(), "Expected allowed_http_hosts parsing error");

Expand All @@ -268,3 +268,48 @@ async fn test_invalid_url_in_allowed_http_hosts_is_rejected() -> Result<()> {

Ok(())
}

#[tokio::test]
async fn test_can_include_specific_components() -> Result<()> {
const MANIFEST: &str = "tests/valid-with-files/spin.toml";

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(MANIFEST, Some(dir), &None, vec!["fs2".to_string()]).await;

let _ = app.unwrap().components.len() == 1;

let app = from_file(
MANIFEST,
Some(dir),
&None,
vec!["fs".to_string(), "fs2".to_string()],
)
.await;

let _ = app.unwrap().components.len() == 2;

Ok(())
}

#[tokio::test]
async fn test_handles_unknown_include_component() -> Result<()> {
const MANIFEST: &str = "tests/valid-with-files/spin.toml";

let temp_dir = tempfile::tempdir()?;
let dir = temp_dir.path();
let app = from_file(
MANIFEST,
Some(dir),
&None,
vec!["random_fake_component".to_string()],
)
.await;

assert!(
app.is_err(),
"No components found in manifest matching 'random_fake_component'"
);

Ok(())
}
16 changes: 13 additions & 3 deletions crates/loader/tests/valid-manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,42 @@ spin_version = "1"
authors = ["Gul Madred", "Edward Jellico", "JL"]
description = "A simple application that returns the number of lights"
name = "chain-of-command"
trigger = {type = "http", base = "/"}
trigger = { type = "http", base = "/" }
version = "6.11.2"

[[component]]
files = ["file.txt", { source = "valid-with-files", destination = "/vwf" }, "subdir/another.txt"]
files = [
"file.txt",
{ source = "valid-with-files", destination = "/vwf" },
"subdir/another.txt"
]
id = "four-lights"
source = "path/to/wasm/file.wasm"

[component.trigger]
executor = {type = "spin"}
executor = { type = "spin" }
route = "/lights"

[component.environment]
env1 = "first"
env2 = "second"

[[component]]
id = "abc"

[component.source]
parcel = "parcel"
reference = "bindle reference"

[component.trigger]
route = "/test"

[[component]]
id = "web"

[component.source]
url = "https://example.com/wasm.wasm.wasm"
digest = "sha256:12345"

[component.trigger]
route = "/dont/test"
13 changes: 11 additions & 2 deletions crates/loader/tests/valid-with-files/spin.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
spin_version = "1"
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
name = "spin-local-source-test"
trigger = {type = "http", base = "/"}
trigger = { type = "http", base = "/" }
version = "1.0.0"

[[component]]
Expand All @@ -10,5 +10,14 @@ id = "fs"
source = "spin-fs.wasm"

[component.trigger]
executor = {type = "spin"}
executor = { type = "spin" }
route = "/..."

[[component]]
files = ["**/*"]
id = "fs2"
source = "spin-fs.wasm"

[component.trigger]
executor = { type = "spin" }
route = "/fs2"
2 changes: 1 addition & 1 deletion crates/trigger/src/locked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ mod tests {
std::fs::write("spin.toml", TEST_MANIFEST).expect("write manifest");
std::fs::write("test-source.wasm", "not actual wasm").expect("write source");
std::fs::write("static.txt", "content").expect("write static");
let app = spin_loader::local::from_file("spin.toml", Some(&tempdir), &None)
let app = spin_loader::local::from_file("spin.toml", Some(&tempdir), &None, vec![])
.await
.expect("load app");
(app, tempdir)
Expand Down
18 changes: 17 additions & 1 deletion src/commands/up.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ pub struct UpCommand {
/// All other args, to be passed through to the trigger
#[clap(hide = true)]
pub trigger_args: Vec<OsString>,

/// Only run a subset of the components
#[clap(
long = "include_components",
short = 'c',
conflicts_with = "BINDLE_ID_OPT"
)]
pub include_components: Vec<String>,
}

impl UpCommand {
Expand Down Expand Up @@ -135,12 +143,20 @@ impl UpCommand {
.as_deref()
.unwrap_or_else(|| DEFAULT_MANIFEST_FILE.as_ref());
let bindle_connection = self.bindle_connection();

let asset_dst = if self.direct_mounts {
None
} else {
Some(&working_dir)
};
spin_loader::from_file(manifest_file, asset_dst, &bindle_connection).await?

spin_loader::from_file(
manifest_file,
asset_dst,
&bindle_connection,
self.include_components.clone(),
)
.await?
}
(None, Some(bindle)) => match &self.server {
Some(server) => {
Expand Down