Skip to content

Commit f9cdce7

Browse files
committed
spin add should check existing targets for templates
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
1 parent 96cd7e7 commit f9cdce7

2 files changed

Lines changed: 79 additions & 13 deletions

File tree

crates/manifest/src/schema/v2.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,16 @@ pub enum TargetEnvironmentRef {
754754
},
755755
}
756756

757+
impl std::fmt::Display for TargetEnvironmentRef {
758+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
759+
match self {
760+
Self::Catalogue(e) => e.fmt(f),
761+
Self::Http { url } => url.fmt(f),
762+
Self::File { path } => path.display().fmt(f),
763+
}
764+
}
765+
}
766+
757767
mod kebab_or_snake_case {
758768
use serde::{Deserialize, Serialize};
759769
pub use spin_serde::{KebabId, SnakeId};

src/commands/new.rs

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl TemplateNewCommandCore {
150150
variant: TemplateVariantInfo,
151151
) -> Result<()> {
152152
let (template_manager, suggested_plugins) =
153-
env_templates_and_plugins(target_environment).await?;
153+
env_templates_and_plugins(target_environment, &variant).await?;
154154

155155
let (name, template_id) = self.resolve_name_template_syntax(&template_manager, &variant)?;
156156

@@ -284,11 +284,25 @@ impl TemplateNewCommandCore {
284284

285285
async fn env_templates_and_plugins(
286286
target_environment: Option<&String>,
287+
variant: &TemplateVariantInfo,
287288
) -> anyhow::Result<(TemplateManager, Vec<String>)> {
288-
Ok(match target_environment {
289-
Some(env) => {
290-
// - resolve the TE
291-
let env_ref = parse_env(env);
289+
let target_env_ref = match variant {
290+
TemplateVariantInfo::NewApplication => target_environment.map(|te| parse_env(te)),
291+
TemplateVariantInfo::AddComponent { manifest_path } => {
292+
match infer_target_env_from_file(manifest_path) {
293+
Ok(t) => t,
294+
Err(_) => {
295+
terminal::warn!(
296+
"Couldn't determine target environment; using your installed templates.\n"
297+
);
298+
None
299+
}
300+
}
301+
}
302+
};
303+
304+
Ok(match target_env_ref {
305+
Some(env_ref) => {
292306
let loaded_env =
293307
spin_environments::load_environment_def(&env_ref, &std::env::current_dir()?)
294308
.await?;
@@ -313,11 +327,28 @@ async fn env_templates_and_plugins(
313327
.await?;
314328
}
315329
if is_empty(&template_manager).await {
316-
anyhow::bail!(
317-
"The {env} environment doesn't list any associated templates. Run `spin new` without `-E` to use generic templates."
318-
);
330+
match variant {
331+
TemplateVariantInfo::NewApplication => {
332+
anyhow::bail!(
333+
"The {env_ref} environment doesn't list any associated templates. Run `spin new` without `-E` to use generic templates."
334+
);
335+
}
336+
TemplateVariantInfo::AddComponent { .. } => {
337+
// `spin add` doesn't have an option for skipping a templateless env (the equivalent of `spin new` without `-E`).
338+
// Fall back to the installed templates.
339+
terminal::warn!(
340+
"The application targets the {env_ref} environment, but that doesn't list any associated templates."
341+
);
342+
eprintln!(
343+
"Templates will instead be taken from the installed template set."
344+
);
345+
eprintln!();
346+
(TemplateManager::try_default()?, vec![])
347+
}
348+
}
349+
} else {
350+
(template_manager, env_def.plugins().to_vec())
319351
}
320-
(template_manager, env_def.plugins().to_vec())
321352
}
322353
None => {
323354
let template_manager = TemplateManager::try_default()
@@ -327,6 +358,25 @@ async fn env_templates_and_plugins(
327358
})
328359
}
329360

361+
fn infer_target_env_from_file(
362+
manifest_path: impl AsRef<Path>,
363+
) -> anyhow::Result<Option<spin_manifest::schema::v2::TargetEnvironmentRef>> {
364+
let manifest = spin_manifest::manifest_from_file(manifest_path)?;
365+
match manifest.application.targets.len() {
366+
0 => Ok(None),
367+
1 => Ok(Some(manifest.application.targets[0].clone())),
368+
_ => {
369+
terminal::warn!("This application targets multiple environments.");
370+
eprintln!(
371+
"Spin doesn't currently support environment-specific templates for multiple environments."
372+
);
373+
eprintln!("Templates will instead be taken from the installed template set.");
374+
eprintln!();
375+
Ok(None)
376+
}
377+
}
378+
}
379+
330380
#[derive(Clone, Debug)]
331381
pub struct ParameterValue {
332382
pub name: String,
@@ -385,10 +435,16 @@ async fn prompt_template(
385435
.collect::<Vec<_>>();
386436

387437
if templates.is_empty() {
388-
if tags.len() == 1 {
389-
bail!("No templates matched '{}'", tags[0]);
390-
} else {
391-
bail!("No templates matched all tags");
438+
match tags.len() {
439+
0 => {
440+
bail!("No suitable templates found");
441+
} // can happen if `spin add` has env, env has templates, but no templates are add-able
442+
1 => {
443+
bail!("No templates matched '{}'", tags[0]);
444+
}
445+
_ => {
446+
bail!("No templates matched all tags");
447+
}
392448
}
393449
}
394450

0 commit comments

Comments
 (0)