new: surface cargo vendor failures and pin the vendoring toolchain
This commit is contained in:
+43
-20
@@ -24,7 +24,7 @@ use std::time::Duration;
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use options::NewOptions;
|
||||
use templates::OutputFile;
|
||||
use templates::{OutputFile, ScaffoldOutcome};
|
||||
|
||||
/// Scaffold a full Debian source tree from `opts`.
|
||||
///
|
||||
@@ -40,7 +40,14 @@ use templates::OutputFile;
|
||||
/// 7. `git init` unless `--no-git` or already inside a repository,
|
||||
/// 8. run the structural verification,
|
||||
/// 9. print the success message with the next steps.
|
||||
pub fn scaffold(opts: NewOptions, multi: &MultiProgress) -> Result<(), Box<dyn Error>> {
|
||||
///
|
||||
/// On success the [`ScaffoldOutcome`] of the post-write hook is returned, so
|
||||
/// the caller can adapt the end of the flow (e.g. the verification offer)
|
||||
/// to what the templates managed to do.
|
||||
pub fn scaffold(
|
||||
opts: NewOptions,
|
||||
multi: &MultiProgress,
|
||||
) -> Result<ScaffoldOutcome, Box<dyn Error>> {
|
||||
let pb = multi.add(ProgressBar::new_spinner());
|
||||
pb.enable_steady_tick(Duration::from_millis(50));
|
||||
pb.set_style(
|
||||
@@ -65,7 +72,7 @@ pub fn scaffold(opts: NewOptions, multi: &MultiProgress) -> Result<(), Box<dyn E
|
||||
|
||||
/// The scaffold steps proper, reporting progress through `pb`. Nothing is
|
||||
/// written to the filesystem before every file rendered successfully.
|
||||
fn scaffold_steps(opts: &NewOptions, pb: &ProgressBar) -> Result<(), Box<dyn Error>> {
|
||||
fn scaffold_steps(opts: &NewOptions, pb: &ProgressBar) -> Result<ScaffoldOutcome, Box<dyn Error>> {
|
||||
// 1. Template resolution: an id without a registered template fails
|
||||
// here with the friendly message instead of a parse error.
|
||||
let template = templates::get(opts.template).ok_or_else(|| {
|
||||
@@ -175,9 +182,10 @@ fn scaffold_steps(opts: &NewOptions, pb: &ProgressBar) -> Result<(), Box<dyn Err
|
||||
|
||||
// 5. Template post-write hook: run before the orig tarball is created,
|
||||
// so files added here (rust: vendor/ + .cargo/config.toml) land
|
||||
// inside it.
|
||||
// inside it. The outcome (e.g. a failed vendoring) is threaded back
|
||||
// to the caller.
|
||||
pb.set_message("Running template hooks");
|
||||
template.post_write(opts, &target)?;
|
||||
let outcome = template.post_write(opts, &target)?;
|
||||
|
||||
// 6. Orig tarball (quilt only).
|
||||
if !opts.native {
|
||||
@@ -193,7 +201,7 @@ fn scaffold_steps(opts: &NewOptions, pb: &ProgressBar) -> Result<(), Box<dyn Err
|
||||
pb.set_message("Verifying");
|
||||
verify::verify(&target)?;
|
||||
|
||||
Ok(())
|
||||
Ok(outcome)
|
||||
}
|
||||
|
||||
/// The success message: what was created and the next steps.
|
||||
@@ -201,13 +209,16 @@ fn print_success(opts: &NewOptions) {
|
||||
let target =
|
||||
opts.target_dir(&std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")));
|
||||
// `display_path` yields an empty string when the target is the cwd
|
||||
// itself (Here mode): show it as `.`.
|
||||
let display = match crate::ui::display_path(&target) {
|
||||
display if display.is_empty() => ".".to_string(),
|
||||
display => display,
|
||||
// itself (Here mode): `Created .` would be cryptic, so spell the
|
||||
// location out; the skeleton/path modes keep the `<dir>` display.
|
||||
let display = crate::ui::display_path(&target);
|
||||
let location = if display.is_empty() {
|
||||
"package in the current directory".to_string()
|
||||
} else {
|
||||
display.clone()
|
||||
};
|
||||
log::info!(
|
||||
"Created {display} — {} ({}-{}) for {}/{}, template '{}'",
|
||||
"Created {location} — {} ({}-{}) for {}/{}, template '{}'",
|
||||
opts.name,
|
||||
opts.upstream_version,
|
||||
opts.revision,
|
||||
@@ -216,7 +227,7 @@ fn print_success(opts: &NewOptions) {
|
||||
opts.template
|
||||
);
|
||||
log::info!("Next steps:");
|
||||
log::info!(" cd {display}");
|
||||
log::info!(" cd {}", if display.is_empty() { "." } else { &display });
|
||||
if opts.release {
|
||||
log::info!(
|
||||
" pkh chlog # for later changes; the entry already targets {}",
|
||||
@@ -264,7 +275,10 @@ mod tests {
|
||||
|
||||
/// Run `scaffold` with the cwd changed to `dir` (restored afterwards);
|
||||
/// must run under `#[serial]` because the cwd is process-global.
|
||||
fn scaffold_in(dir: &std::path::Path, opts: NewOptions) -> Result<(), Box<dyn Error>> {
|
||||
fn scaffold_in(
|
||||
dir: &std::path::Path,
|
||||
opts: NewOptions,
|
||||
) -> Result<ScaffoldOutcome, Box<dyn Error>> {
|
||||
let previous = std::env::current_dir()?;
|
||||
std::env::set_current_dir(dir)?;
|
||||
let result = scaffold(opts, &MultiProgress::new());
|
||||
@@ -558,28 +572,38 @@ mod tests {
|
||||
/// End-to-end rust skeleton: the vendoring hook runs before the orig
|
||||
/// tarball is created, so `.cargo/` (and `vendor/` when dependencies
|
||||
/// exist) travel inside it. The vendoring step needs host cargo; on a
|
||||
/// cargo-less host the scaffold still succeeds with a warning.
|
||||
/// cargo-less host the scaffold still succeeds with a warning and a
|
||||
/// `vendoring_failed` outcome. Keyed against the `RUSTUP_TOOLCHAIN`
|
||||
/// tests of the rust template: they mutate the process-global
|
||||
/// environment the cargo shim would pick up mid-vendoring.
|
||||
#[test]
|
||||
#[serial]
|
||||
#[serial(RUSTUP_TOOLCHAIN)]
|
||||
fn scaffold_rust_skeleton_vendors_before_tarball() {
|
||||
let dir = tempdir().unwrap();
|
||||
scaffold_in(
|
||||
let outcome = scaffold_in(
|
||||
dir.path(),
|
||||
opts(TemplateId::Rust, "mytool", SourceDir::Skeleton),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let has_cargo = crate::new::templates::find_on_path("cargo").is_some();
|
||||
assert_eq!(outcome.vendoring_failed, !has_cargo);
|
||||
|
||||
let tree = dir.path().join("mytool");
|
||||
assert!(tree.join("Cargo.toml").exists());
|
||||
assert!(tree.join("src/main.rs").exists());
|
||||
// The vendoring step is what creates Cargo.lock for a skeleton.
|
||||
assert_eq!(tree.join("Cargo.lock").exists(), has_cargo);
|
||||
|
||||
// rules: the vendored build overrides, no --locked on a fresh
|
||||
// skeleton without Cargo.lock.
|
||||
// rules: the vendored build overrides, and `--locked` exactly when
|
||||
// the vendoring step left a lockfile behind (it appears after the
|
||||
// rules were rendered, so the hook patches it in).
|
||||
let rules = std::fs::read_to_string(tree.join("debian/rules")).unwrap();
|
||||
assert!(rules.contains("%:\n\tdh $@\n"));
|
||||
assert!(rules.contains("override_dh_auto_build:\n\tcargo build --release --offline\n"));
|
||||
assert!(rules.contains("override_dh_auto_build:\n\tcargo build --release --offline"));
|
||||
assert!(rules.contains("override_dh_auto_install:\n\tinstall -Dm755 target/release/mytool debian/mytool/usr/bin/mytool"));
|
||||
assert!(!rules.contains("--locked"));
|
||||
assert_eq!(rules.contains("--locked"), has_cargo);
|
||||
|
||||
// control: Architecture any + the cargo/rustc build-deps.
|
||||
let control = crate::debian::ControlInfo::parse(&tree.join("debian/control")).unwrap();
|
||||
@@ -591,7 +615,6 @@ mod tests {
|
||||
|
||||
// The offline config exists when host cargo vendored the skeleton,
|
||||
// and both it and the skeleton land inside the orig tarball.
|
||||
let has_cargo = crate::new::templates::find_on_path("cargo").is_some();
|
||||
if has_cargo {
|
||||
let config = std::fs::read_to_string(tree.join(".cargo/config.toml")).unwrap();
|
||||
assert!(config.contains("[source.crates-io]"), "{config}");
|
||||
|
||||
Reference in New Issue
Block a user