new: add interactive wizard and remaining ecosystem templates

This commit is contained in:
2026-09-16 13:49:29 +02:00
parent d044f757e9
commit 9b98f5c7c3
17 changed files with 3930 additions and 99 deletions
+90 -8
View File
@@ -50,16 +50,45 @@ pub fn files(opts: &NewOptions, template: &dyn Template) -> Vec<OutputFile> {
source_format(opts),
changelog(opts),
control(opts, template),
rules(template),
rules(opts, template),
copyright(opts),
debian_gitignore(opts),
];
if !opts.native {
files.push(local_options());
}
if opts.autopkgtest {
files.push(autopkgtest_control());
files.push(autopkgtest_smoke(opts));
}
if let Some(watch) = &opts.watch {
files.push(OutputFile::new("debian/watch", watch.clone()));
}
files
}
/// `debian/tests/control`: the autopkgtest smoke test definition.
fn autopkgtest_control() -> OutputFile {
OutputFile::new(
"debian/tests/control",
"Tests: smoke\nDepends: @\nRestrictions: allow-stderr\n",
)
}
/// `debian/tests/smoke`: run the installed command once; `--help` first,
/// `--version` as the fallback (some tools only answer one of them).
fn autopkgtest_smoke(opts: &NewOptions) -> OutputFile {
OutputFile::executable(
"debian/tests/smoke",
format!(
"#!/bin/sh\n\
set -e\n\
{command} --help >/dev/null 2>&1 || {command} --version\n",
command = opts.command,
),
)
}
/// `debian/source/format`: `3.0 (quilt)` by default, `3.0 (native)` with
/// `--native`.
fn source_format(opts: &NewOptions) -> OutputFile {
@@ -173,6 +202,10 @@ fn control(opts: &NewOptions, template: &dyn Template) -> OutputFile {
build_depends.extend(template.build_depends(opts));
control.push_str(&render_field("Build-Depends", &build_depends));
for (key, value) in template.source_fields(opts) {
control.push_str(&format!("{key}: {value}\n"));
}
if let Some(homepage) = &opts.homepage {
control.push_str(&format!("Homepage: {homepage}\n"));
}
@@ -181,7 +214,7 @@ fn control(opts: &NewOptions, template: &dyn Template) -> OutputFile {
// Binary stanza.
control.push_str(&format!("Package: {}\n", opts.name));
control.push_str(&format!("Architecture: {}\n", template.architecture()));
control.push_str(&format!("Architecture: {}\n", template.architecture(opts)));
if !opts.depends.is_empty() {
control.push_str(&render_field("Depends", &opts.depends));
}
@@ -191,11 +224,12 @@ fn control(opts: &NewOptions, template: &dyn Template) -> OutputFile {
OutputFile::new("debian/control", control)
}
/// `debian/rules`: the minimal `dh $@` makefile (plus the template's extra
/// overrides, when any), written with the executable bit.
fn rules(template: &dyn Template) -> OutputFile {
let mut contents = String::from("#!/usr/bin/make -f\n%:\n\tdh $@\n");
let extra = template.rules_extra();
/// `debian/rules`: the shebang and `%:` target whose recipe is the
/// template's dh line (plus the template's extra overrides, when any),
/// written with the executable bit.
fn rules(opts: &NewOptions, template: &dyn Template) -> OutputFile {
let mut contents = format!("#!/usr/bin/make -f\n%:\n\t{}\n", template.rules_dh_line());
let extra = template.rules_extra(opts);
if !extra.is_empty() {
contents.push('\n');
contents.push_str(&extra);
@@ -464,6 +498,9 @@ mod tests {
depends: Vec::new(),
native: false,
git: true,
autopkgtest: false,
pkg_config: false,
watch: None,
}
}
@@ -591,11 +628,56 @@ mod tests {
#[test]
fn rules_is_executable_minimal_makefile() {
let rules = super::rules(crate::new::templates::get(TemplateId::Shell).unwrap());
let o = opts();
let rules = super::rules(&o, crate::new::templates::get(TemplateId::Shell).unwrap());
assert!(rules.executable);
assert_eq!(rules.contents, "#!/usr/bin/make -f\n%:\n\tdh $@\n");
}
#[test]
fn extra_files_autopkgtest_and_watch() {
let mut o = opts();
o.autopkgtest = true;
o.watch = Some(
"version=4\nhttps://github.com/example/mytool/releases .*/v?@ANY_VERSION@\\.tar\\.gz\n"
.to_string(),
);
let files = super::files(&o, crate::new::templates::get(TemplateId::Shell).unwrap());
let find = |path: &str| {
files
.iter()
.find(|f| f.path == path)
.unwrap_or_else(|| panic!("{path} missing"))
};
let control = find("debian/tests/control");
assert_eq!(
control.contents,
"Tests: smoke\nDepends: @\nRestrictions: allow-stderr\n"
);
let smoke = find("debian/tests/smoke");
assert!(smoke.executable);
assert!(smoke.contents.starts_with("#!/bin/sh\nset -e\n"));
assert!(
smoke
.contents
.contains("mytool --help >/dev/null 2>&1 || mytool --version")
);
assert_eq!(
find("debian/watch").contents,
"version=4\nhttps://github.com/example/mytool/releases .*/v?@ANY_VERSION@\\.tar\\.gz\n"
);
// Without the extras none of the files are rendered.
let plain = super::files(
&opts(),
crate::new::templates::get(TemplateId::Shell).unwrap(),
);
assert!(!plain.iter().any(|f| f.path.starts_with("debian/tests")));
assert!(!plain.iter().any(|f| f.path == "debian/watch"));
}
#[test]
fn copyright_is_dep5() {
let c = super::copyright(&opts());