Skip to content

Commit

Permalink
Merge pull request #2643 from itowlson/templates-silent-new-if-no-ter…
Browse files Browse the repository at this point in the history
…minal

Improve non-interactive behaviour of `spin new`
  • Loading branch information
itowlson authored Jul 15, 2024
2 parents 66ede35 + 12cdb0f commit 086ded6
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 6 deletions.
115 changes: 115 additions & 0 deletions crates/templates/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -816,6 +817,7 @@ mod tests {
values,
accept_defaults: true,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -882,6 +884,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -910,6 +913,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand All @@ -935,6 +939,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -992,6 +997,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1020,6 +1026,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1072,6 +1079,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1100,6 +1108,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand All @@ -1125,6 +1134,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1166,6 +1176,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: true,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1205,6 +1216,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: true,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1238,6 +1250,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: true,
allow_overwrite: false,
};
template.run(options).silent().await.unwrap();
}
Expand Down Expand Up @@ -1288,6 +1301,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1316,6 +1330,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template.run(options).silent().await.unwrap();
Expand Down Expand Up @@ -1377,6 +1392,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template
Expand All @@ -1387,6 +1403,104 @@ mod tests {
}
}

#[tokio::test]
async fn cannot_generate_over_existing_files_by_default() {
let temp_dir = tempdir().unwrap();
let store = TemplateStore::new(temp_dir.path());
let manager = TemplateManager { store };
let source = TemplateSource::File(project_root());

manager
.install(&source, &InstallOptions::default(), &DiscardingReporter)
.await
.unwrap();

let template = manager.get("http-rust").unwrap().unwrap();

let dest_temp_dir = tempdir().unwrap();
let output_dir = dest_temp_dir.path().join("myproj");

tokio::fs::create_dir_all(&output_dir).await.unwrap();
let manifest_path = output_dir.join("spin.toml");
tokio::fs::write(&manifest_path, "cookies").await.unwrap();

let values = [
("project-description".to_owned(), "my desc".to_owned()),
("http-path".to_owned(), "/path/...".to_owned()),
]
.into_iter()
.collect();
let options = RunOptions {
variant: crate::template::TemplateVariantInfo::NewApplication,
output_path: output_dir.clone(),
name: "my project".to_owned(),
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

template
.run(options)
.silent()
.await
.expect_err("generate into existing dir should have failed");

assert!(tokio::fs::read_to_string(&manifest_path)
.await
.unwrap()
.contains("cookies"));
}

#[tokio::test]
async fn can_generate_over_existing_files_if_so_configured() {
let temp_dir = tempdir().unwrap();
let store = TemplateStore::new(temp_dir.path());
let manager = TemplateManager { store };
let source = TemplateSource::File(project_root());

manager
.install(&source, &InstallOptions::default(), &DiscardingReporter)
.await
.unwrap();

let template = manager.get("http-rust").unwrap().unwrap();

let dest_temp_dir = tempdir().unwrap();
let output_dir = dest_temp_dir.path().join("myproj");

tokio::fs::create_dir_all(&output_dir).await.unwrap();
let manifest_path = output_dir.join("spin.toml");
tokio::fs::write(&manifest_path, "cookies").await.unwrap();

let values = [
("project-description".to_owned(), "my desc".to_owned()),
("http-path".to_owned(), "/path/...".to_owned()),
]
.into_iter()
.collect();
let options = RunOptions {
variant: crate::template::TemplateVariantInfo::NewApplication,
output_path: output_dir.clone(),
name: "my project".to_owned(),
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: true,
};

template
.run(options)
.silent()
.await
.expect("generate into existing dir should have succeeded");

assert!(tokio::fs::read_to_string(&manifest_path)
.await
.unwrap()
.contains("[[trigger.http]]"));
}

#[tokio::test]
async fn cannot_new_a_component_only_template() {
let temp_dir = tempdir().unwrap();
Expand Down Expand Up @@ -1447,6 +1561,7 @@ mod tests {
values,
accept_defaults: false,
no_vcs: false,
allow_overwrite: false,
};

let err = template
Expand Down
15 changes: 10 additions & 5 deletions crates/templates/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub struct RunOptions {
pub accept_defaults: bool,
/// If true, do not create a .gitignore file
pub no_vcs: bool,
/// Skip the overwrite prompt if the output directory already contains files
/// (or, if silent, allow overwrite instead of erroring).
pub allow_overwrite: bool,
}

impl Run {
Expand Down Expand Up @@ -93,11 +96,13 @@ impl Run {
// TODO: rationalise `path` and `dir`
let to = self.generation_target_dir();

match interaction.allow_generate_into(&to) {
Cancellable::Cancelled => return Ok(None),
Cancellable::Ok(_) => (),
Cancellable::Err(e) => return Err(e),
};
if !self.options.allow_overwrite {
match interaction.allow_generate_into(&to) {
Cancellable::Cancelled => return Ok(None),
Cancellable::Ok(_) => (),
Cancellable::Err(e) => return Err(e),
};
}

self.validate_provided_values()?;

Expand Down
3 changes: 3 additions & 0 deletions crates/templates/src/test_built_ins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ async fn new_fileserver_creates_assets_dir() -> anyhow::Result<()> {
values: HashMap::new(),
accept_defaults: true,
no_vcs: false,
allow_overwrite: false,
};
manager
.get("static-fileserver")?
Expand Down Expand Up @@ -85,6 +86,7 @@ async fn add_fileserver_creates_assets_dir_next_to_manifest() -> anyhow::Result<
values: HashMap::new(),
accept_defaults: true,
no_vcs: false,
allow_overwrite: false,
};
manager
.get("http-empty")?
Expand All @@ -104,6 +106,7 @@ async fn add_fileserver_creates_assets_dir_next_to_manifest() -> anyhow::Result<
values: fs_settings,
accept_defaults: true,
no_vcs: false,
allow_overwrite: false,
};
manager
.get("static-fileserver")?
Expand Down
19 changes: 18 additions & 1 deletion src/commands/new.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{
collections::HashMap,
io::IsTerminal,
path::{Path, PathBuf},
str::FromStr,
};
Expand Down Expand Up @@ -66,6 +67,15 @@ pub struct TemplateNewCommandCore {
/// An optional argument that allows to skip creating .gitignore
#[clap(long = "no-vcs", takes_value = false)]
pub no_vcs: bool,

/// If the output directory already contains files, generate the new files into
/// it without confirming, overwriting any existing files with the same names.
#[clap(
long = "allow-overwrite",
alias = "allow-overwrites",
takes_value = false
)]
pub allow_overwrite: bool,
}

/// Scaffold a new application based on a template.
Expand Down Expand Up @@ -184,9 +194,16 @@ impl TemplateNewCommandCore {
values,
accept_defaults: self.accept_defaults,
no_vcs: self.no_vcs,
allow_overwrite: self.allow_overwrite,
};

template.run(options).interactive().await
let run = template.run(options);

if std::io::stderr().is_terminal() {
run.interactive().await
} else {
run.silent().await
}
}

// Try to guess if the user is using v1 or v2 syntax, and fix things up so
Expand Down

0 comments on commit 086ded6

Please sign in to comment.