Move the four templates' static file bodies into .tpl files under
data/templates/<id>/, referenced by their manifests' files: lists —
the shell skeleton script (executable, {command}-named) with its
skeleton-only debian/install mapping, the empty template's stub README,
the makefile hello.c/Makefile skeleton with its skeleton-only install
mapping, and go's go.mod/main.go skeleton (the go directive of go.mod
stays a literal: nothing about it is answer-derived).
The empty template ends up hookless — zero Rust, its registry entry
points at no hooks — and src/new/templates/empty.rs is deleted. The
shell and go hooks shrink to their probes (plus go's {go_import_path}
context value); the makefile hooks keep only the existing-tree hint
probing the packaged Makefile for a phony install: target, since that
heuristic reads the tree and cannot be data.
126 lines
4.7 KiB
Rust
126 lines
4.7 KiB
Rust
//! The `shell` template: a single interpreted script installed to
|
|
//! `/usr/bin` with plain `dh $@` plumbing.
|
|
//!
|
|
//! Everything except the probe is manifest data
|
|
//! (`data/templates/shell/manifest.yml`: the skeleton script, its
|
|
//! skeleton-only `debian/install` mapping, the plain `dh $@` plumbing).
|
|
//! The logic half here pre-fills the wizard answers from the file name of
|
|
//! the single top-level script — the same heuristic [`crate::new::detect`]
|
|
//! bases its shell detection on.
|
|
|
|
use std::path::Path;
|
|
|
|
use super::{ProbeResult, TemplateHooks};
|
|
use crate::new::options;
|
|
|
|
/// The logic half of the shell template.
|
|
pub struct Hooks;
|
|
|
|
/// The shell template's hooks, registered in the template registry.
|
|
pub static HOOKS: Hooks = Hooks;
|
|
|
|
impl TemplateHooks for Hooks {
|
|
/// The file name of the single top-level script (sanitized) pre-fills the
|
|
/// package name and command questions.
|
|
fn probe(&self, dir: &Path) -> Option<ProbeResult> {
|
|
let path = crate::new::detect::single_script(dir)?;
|
|
let stem = path.file_stem()?.to_str()?;
|
|
let name = options::sanitize_name(stem)?;
|
|
Some(ProbeResult {
|
|
command: Some(name.clone()),
|
|
name: Some(name),
|
|
..Default::default()
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::new::options::{License, SourceDir, TemplateId};
|
|
use tempfile::tempdir;
|
|
|
|
fn opts() -> crate::new::options::NewOptions {
|
|
crate::new::options::NewOptions {
|
|
name: "mytool".into(),
|
|
template: TemplateId::SHELL,
|
|
source_dir: SourceDir::Skeleton,
|
|
upstream_version: "0.1.0".into(),
|
|
revision: 1,
|
|
summary: "A tool".into(),
|
|
long_description: "A tool".into(),
|
|
homepage: None,
|
|
license: License::Mit,
|
|
command: "mytool".into(),
|
|
maintainer: ("Jane".into(), "jane@example.com".into()),
|
|
dist: "ubuntu".into(),
|
|
series: "resolute".into(),
|
|
release: false,
|
|
depends: Vec::new(),
|
|
source_format: crate::new::options::SourceFormat::Quilt,
|
|
orig: Some(crate::new::options::OrigOrigin::Snapshot),
|
|
git: true,
|
|
autopkgtest: false,
|
|
pkg_config: false,
|
|
watch: None,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn shell_template_shape() {
|
|
let o = opts();
|
|
let template = super::super::get(TemplateId::SHELL).unwrap();
|
|
|
|
assert_eq!(template.architecture(&o), "all");
|
|
assert!(template.build_depends(&o).is_empty());
|
|
assert!(template.rules_extra(&o).is_empty());
|
|
|
|
// The skeleton bodies are manifest data now: the executable script
|
|
// and its skeleton-only install mapping.
|
|
let skeleton = template.skeleton(&o);
|
|
assert_eq!(skeleton.len(), 1);
|
|
assert_eq!(skeleton[0].path, "mytool.sh");
|
|
assert!(skeleton[0].executable);
|
|
assert!(skeleton[0].contents.starts_with("#!/bin/sh\n"));
|
|
assert!(skeleton[0].contents.contains("echo \"Hello from mytool!\""));
|
|
|
|
let debian = template.debian(&o);
|
|
assert_eq!(debian.len(), 1);
|
|
assert_eq!(debian[0].path, "debian/install");
|
|
assert_eq!(debian[0].contents, "mytool.sh usr/bin/mytool\n");
|
|
|
|
// Packaging an existing tree: no install mapping is generated (it
|
|
// would reference the non-existent skeleton script).
|
|
let existing = crate::new::options::NewOptions {
|
|
source_dir: SourceDir::Here,
|
|
..opts()
|
|
};
|
|
assert!(template.debian(&existing).is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn shell_probe_reads_script_file_name() {
|
|
let template = super::super::get(TemplateId::SHELL).unwrap();
|
|
|
|
// The .sh extension is stripped, the stem sanitized into a package
|
|
// name and command.
|
|
let dir = tempdir().unwrap();
|
|
std::fs::write(dir.path().join("My Tool.sh"), "#!/bin/sh\n").unwrap();
|
|
let probe = template.probe(dir.path()).expect("probe result");
|
|
assert_eq!(probe.name.as_deref(), Some("my-tool"));
|
|
assert_eq!(probe.command.as_deref(), Some("my-tool"));
|
|
|
|
// A shebang file without extension works too.
|
|
let dir = tempdir().unwrap();
|
|
std::fs::write(dir.path().join("runtool"), "#!/usr/bin/env bash\n").unwrap();
|
|
let probe = template.probe(dir.path()).expect("probe result");
|
|
assert_eq!(probe.name.as_deref(), Some("runtool"));
|
|
|
|
// Zero or several scripts: silent None.
|
|
let dir = tempdir().unwrap();
|
|
assert!(template.probe(dir.path()).is_none());
|
|
std::fs::write(dir.path().join("a.sh"), "#!/bin/sh\n").unwrap();
|
|
std::fs::write(dir.path().join("b.sh"), "#!/bin/sh\n").unwrap();
|
|
assert!(template.probe(dir.path()).is_none());
|
|
}
|
|
}
|