new: port the shell, empty, makefile and go templates to manifests

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.
This commit is contained in:
2026-09-18 14:58:13 +02:00
parent 04a572cd77
commit ffac4d6b57
17 changed files with 204 additions and 250 deletions
+1
View File
@@ -0,0 +1 @@
{name} - empty base tree scaffolded by `pkh new`; there is intentionally no upstream build system here.
+7 -2
View File
@@ -1,6 +1,9 @@
## The `empty` template: a metapackage (non-empty Depends list) or an ## The `empty` template: a metapackage (non-empty Depends list) or an
## empty base package with no build system at all — pure `dh $@` plumbing ## empty base package with no build system at all — pure `dh $@` plumbing
## as a starting point for hand-written rules. ## as a starting point for hand-written rules. Pure data: no hooks, the
## metapackage Depends payload travels in the wizard answers, and the
## only upstream file is the stub README marking the tree as
## intentionally empty.
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -11,4 +14,6 @@ detect:
build_depends: [] build_depends: []
architecture: all architecture: all
rules_dh_line: "dh $@" rules_dh_line: "dh $@"
files: [] files:
- path: README
template: README.tpl
+3
View File
@@ -0,0 +1,3 @@
module {name}
go 1.21
+8
View File
@@ -0,0 +1,8 @@
// Placeholder for {name}, generated by `pkh new`.
package main
import "fmt"
func main() {
fmt.Println("Hello from {command}!")
}
+8 -2
View File
@@ -1,6 +1,8 @@
## The `go` template: a Go module built through dh-golang. The logic half ## The `go` template: a Go module built through dh-golang. The logic half
## — the go.mod module-line probe and the `{go_import_path}` value below — ## — the go.mod module-line probe and the `{go_import_path}` value below —
## lives in src/new/templates/go.rs. ## lives in src/new/templates/go.rs; the skeleton bodies are static data
## (the `go` directive of go.mod stays a literal: nothing about it is
## answer-derived, so it has no {placeholder}).
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -15,4 +17,8 @@ architecture: any
rules_dh_line: "dh $@ --buildsystem=golang" rules_dh_line: "dh $@ --buildsystem=golang"
source_fields: source_fields:
XS-Go-Import-Path: "{go_import_path}" XS-Go-Import-Path: "{go_import_path}"
files: [] files:
- path: go.mod
template: go.mod.tpl
- path: main.go
template: main.go.tpl
+16
View File
@@ -0,0 +1,16 @@
CC ?= cc
CFLAGS ?= -O2 -Wall -Wextra
PREFIX ?= /usr
all: {command}
{command}: hello.c
$(CC) $(CFLAGS) -o $@ hello.c
install: {command}
install -Dm755 {command} $(DESTDIR)$(PREFIX)/bin/{command}
clean:
rm -f {command}
.PHONY: all install clean
+8
View File
@@ -0,0 +1,8 @@
#include <stdio.h>
/* Placeholder for {name}, generated by `pkh new`. */
int main(void)
{
printf("Hello from {command}!\n");
return 0;
}
+1
View File
@@ -0,0 +1 @@
{command} usr/bin/{command}
+13 -2
View File
@@ -2,7 +2,11 @@
## debhelper's makefile buildsystem runs `make` for the build and ## debhelper's makefile buildsystem runs `make` for the build and
## `make install DESTDIR=...` when the Makefile carries an `install:` ## `make install DESTDIR=...` when the Makefile carries an `install:`
## target (missing targets are skipped gracefully), so plain `dh $@` ## target (missing targets are skipped gracefully), so plain `dh $@`
## plumbing is enough here. ## plumbing is enough here. The phony-install hint of
## src/new/templates/makefile.rs (whether dh_auto_install will run
## `make install` for an existing tree) is the only logic; the skeleton
## bodies below are static data (the install mapping is rendered for
## skeletons only, whose phony install target is known by construction).
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -14,4 +18,11 @@ build_depends:
- build-essential - build-essential
architecture: any architecture: any
rules_dh_line: "dh $@" rules_dh_line: "dh $@"
files: [] files:
- path: hello.c
template: hello.c.tpl
- path: Makefile
template: Makefile.tpl
- path: debian/install
template: install.tpl
skeleton_only: true
+1
View File
@@ -0,0 +1 @@
{command}.sh usr/bin/{command}
+11 -2
View File
@@ -2,7 +2,10 @@
## /usr/bin with plain `dh $@` plumbing. Detection is not marker-based: the ## /usr/bin with plain `dh $@` plumbing. Detection is not marker-based: the
## single-script heuristic of src/new/detect.rs (a lone *.sh or shebang ## single-script heuristic of src/new/detect.rs (a lone *.sh or shebang
## file) maps here. The probe pre-filling the wizard answers from the ## file) maps here. The probe pre-filling the wizard answers from the
## script file name lives in src/new/templates/shell.rs. ## script file name lives in src/new/templates/shell.rs; everything else
## is the data below (the skeleton script is executable, the install
## mapping exists for skeletons only — packaging an existing tree leaves
## the mapping to the user).
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -13,4 +16,10 @@ detect:
build_depends: [] build_depends: []
architecture: all architecture: all
rules_dh_line: "dh $@" rules_dh_line: "dh $@"
files: [] files:
- path: "{command}.sh"
template: script.tpl
executable: true
- path: debian/install
template: install.tpl
skeleton_only: true
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
# Placeholder for {name}, generated by `pkh new`.
echo "Hello from {command}!"
-84
View File
@@ -1,84 +0,0 @@
//! The `empty` template: a metapackage or an empty base package with no
//! build system at all.
//!
//! One template with two flavors: a non-empty `Depends` list selects the
//! **metapackage** flavor (the canonical `Architecture: all`, nothing
//! compiled, the Depends list *is* the payload shape), while an empty list
//! selects the **empty base** — pure `dh $@` plumbing as a starting point
//! for hand-written rules. Both flavors are pure manifest data except for
//! the stub `README` of the skeleton, which lives here until its static
//! body moves into the manifest's `files:` list.
use super::{OutputFile, TemplateHooks};
use crate::new::options::NewOptions;
/// The logic half of the empty template.
pub struct Hooks;
/// The empty template's hooks, registered in the template registry.
pub static HOOKS: Hooks = Hooks;
impl TemplateHooks for Hooks {
/// No upstream files beyond a stub `README` marking the tree as
/// intentionally empty.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
vec![OutputFile::new(
"README",
format!(
"{} - empty base tree scaffolded by `pkh new`; there is \
intentionally no upstream build system here.\n",
opts.name
),
)]
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::new::options::{License, SourceDir, TemplateId};
fn opts(depends: Vec<String>) -> NewOptions {
NewOptions {
name: "metapkg".into(),
template: TemplateId::EMPTY,
source_dir: SourceDir::Skeleton,
upstream_version: "0.1.0".into(),
revision: 1,
summary: "A metapackage".into(),
long_description: "A metapackage".into(),
homepage: None,
license: License::Custom("unknown".into()),
command: "ignored".into(),
maintainer: ("Jane".into(), "jane@example.com".into()),
dist: "debian".into(),
series: "sid".into(),
release: false,
depends,
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 empty_template_shape() {
let template = super::super::get(TemplateId::EMPTY).unwrap();
// Metapackage flavor: the depends list travels in the options.
let o = opts(vec!["hello".into(), "hello-data (>= 1.0)".into()]);
assert!(template.debian(&o).is_empty());
assert_eq!(template.architecture(&o), "all");
assert!(template.build_depends(&o).is_empty());
assert!(template.rules_extra(&o).is_empty());
let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 1);
assert_eq!(skeleton[0].path, "README");
assert!(!skeleton[0].executable);
assert!(skeleton[0].contents.contains("metapkg"));
}
}
+9 -39
View File
@@ -1,16 +1,16 @@
//! The `go` template: a Go module built through dh-golang. //! The `go` template: a Go module built through dh-golang.
//! //!
//! The source stanza carries `XS-Go-Import-Path`, declared as the //! The skeleton bodies (`go.mod`, `main.go`) are manifest data
//! `{go_import_path}` placeholder by the manifest and filled from the //! (`data/templates/go/manifest.yml`); the source stanza carries
//! `module` line of `go.mod` when the packaged tree has one, defaulting to //! `XS-Go-Import-Path`, declared as the `{go_import_path}` placeholder by
//! the package name (fresh skeletons embed the package name in their own //! the manifest and filled here from the `module` line of `go.mod` when
//! `go.mod`). The module line is also the probe of an existing project; the //! the packaged tree has one, defaulting to the package name (fresh
//! skeleton bodies stay here until they move into the manifest's `files:` //! skeletons embed the package name in their own `go.mod`). The module
//! list. //! line is also the probe of an existing project.
use std::path::Path; use std::path::Path;
use super::{OutputFile, ProbeResult, TemplateHooks, source_dir_of}; use super::{ProbeResult, TemplateHooks, source_dir_of};
use crate::new::options::NewOptions; use crate::new::options::NewOptions;
/// The logic half of the go template. /// The logic half of the go template.
@@ -20,37 +20,6 @@ pub struct Hooks;
pub static HOOKS: Hooks = Hooks; pub static HOOKS: Hooks = Hooks;
impl TemplateHooks for Hooks { impl TemplateHooks for Hooks {
/// A stdlib-only `main.go` (no archive dependencies needed to build) and
/// the matching `go.mod` whose module path is the package name.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
vec![
OutputFile::new(
"go.mod",
format!(
"module {name}\n\
\n\
go 1.21\n",
name = opts.name,
),
),
OutputFile::new(
"main.go",
format!(
"// Placeholder for {name}, generated by `pkh new`.\n\
package main\n\
\n\
import \"fmt\"\n\
\n\
func main() {{\n\
\tfmt.Println(\"Hello from {command}!\")\n\
}}\n",
name = opts.name,
command = opts.command,
),
),
]
}
/// The `{go_import_path}` value of the manifest's `XS-Go-Import-Path` /// The `{go_import_path}` value of the manifest's `XS-Go-Import-Path`
/// source field (see [`import_path`]). /// source field (see [`import_path`]).
fn context(&self, opts: &NewOptions) -> Vec<(String, String)> { fn context(&self, opts: &NewOptions) -> Vec<(String, String)> {
@@ -143,6 +112,7 @@ mod tests {
assert_eq!(template.rules_dh_line(), "dh $@ --buildsystem=golang"); assert_eq!(template.rules_dh_line(), "dh $@ --buildsystem=golang");
assert!(template.debian(&o).is_empty()); assert!(template.debian(&o).is_empty());
// The skeleton bodies are manifest data now.
let skeleton = template.skeleton(&o); let skeleton = template.skeleton(&o);
assert!( assert!(
skeleton skeleton
+22 -58
View File
@@ -3,16 +3,17 @@
//! debhelper's makefile buildsystem runs `make` for the build and `make //! debhelper's makefile buildsystem runs `make` for the build and `make
//! install DESTDIR=...` when the Makefile carries an `install:` target //! install DESTDIR=...` when the Makefile carries an `install:` target
//! (missing targets are skipped gracefully), so plain `dh $@` plumbing is //! (missing targets are skipped gracefully), so plain `dh $@` plumbing is
//! enough here. The metadata is manifest data; the logic half here is the //! enough here. Everything is manifest data
//! phony-`install:` heuristic advising the user whether `dh_auto_install` //! (`data/templates/makefile/manifest.yml`: the `hello.c`/`Makefile`
//! will run `make install`, plus (until their bodies move into the //! skeleton and the skeleton-only `debian/install` mapping) except the
//! manifest's `files:` list) the `hello.c`/`Makefile` skeleton and its //! hint logged here for an existing tree, which probes its Makefile for a
//! `debian/install` mapping. //! phony `install:` target to tell whether `dh_auto_install` will run
//! `make install` (a skeleton's target is known by construction, so
//! skeletons need no code).
use std::path::Path; use std::path::Path;
use super::meson::hello_c; use super::TemplateHooks;
use super::{OutputFile, TemplateHooks, source_dir_of};
use crate::new::options::{NewOptions, SourceDir}; use crate::new::options::{NewOptions, SourceDir};
/// The logic half of the makefile template. /// The logic half of the makefile template.
@@ -22,53 +23,18 @@ pub struct Hooks;
pub static HOOKS: Hooks = Hooks; pub static HOOKS: Hooks = Hooks;
impl TemplateHooks for Hooks { impl TemplateHooks for Hooks {
/// A `hello.c` plus a `Makefile` with `all`/`install`/`clean` targets; /// No files of its own: the manifest carries the skeleton-only
/// `install` honors `DESTDIR` and copies the binary to /// `debian/install` mapping. When packaging an existing tree, probe
/// `$(DESTDIR)/usr/bin/`. /// its Makefile for a phony `install:` target and say which install
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> { /// step `dh_auto_install` will take (no `debian/install` is emitted
vec![ /// there — the source-relative mapping of an unknown artifact is only
hello_c(opts), /// the project's to write, and `make install` already ran).
OutputFile::new( fn debian_files(&self, opts: &NewOptions) -> Vec<super::OutputFile> {
"Makefile", if matches!(opts.source_dir, SourceDir::Skeleton) {
format!( return Vec::new();
"CC ?= cc\n\
CFLAGS ?= -O2 -Wall -Wextra\n\
PREFIX ?= /usr\n\
\n\
all: {command}\n\
\n\
{command}: hello.c\n\
\t$(CC) $(CFLAGS) -o $@ hello.c\n\
\n\
install: {command}\n\
\tinstall -Dm755 {command} $(DESTDIR)$(PREFIX)/bin/{command}\n\
\n\
clean:\n\
\trm -f {command}\n\
\n\
.PHONY: all install clean\n",
command = opts.command,
),
),
]
} }
let dir = super::source_dir_of(opts);
/// `debian/install` mapping the built binary into `/usr/bin`, generated if let Some(dir) = dir.as_deref()
/// only when the packaged Makefile carries a phony `install:` target:
/// for skeletons that is known by construction; when packaging an
/// existing tree the Makefile is probed instead (no `debian/install` is
/// emitted there — the source-relative mapping of an unknown artifact is
/// only the project's to write, and `make install` already ran).
fn debian_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
match &opts.source_dir {
SourceDir::Skeleton => {
vec![OutputFile::new(
"debian/install",
format!("{} usr/bin/{}\n", opts.command, opts.command),
)]
}
_ => {
if let Some(dir) = source_dir_of(opts)
&& phony_install_target(&dir.join("Makefile")).is_some() && phony_install_target(&dir.join("Makefile")).is_some()
{ {
log::info!( log::info!(
@@ -85,8 +51,6 @@ impl TemplateHooks for Hooks {
Vec::new() Vec::new()
} }
} }
}
}
/// The name of the phony `install:` target of the Makefile at `path`, when /// The name of the phony `install:` target of the Makefile at `path`, when
/// there is one: an unindented `install:` rule whose name also appears in a /// there is one: an unindented `install:` rule whose name also appears in a
@@ -157,8 +121,8 @@ mod tests {
assert_eq!(template.rules_dh_line(), "dh $@"); assert_eq!(template.rules_dh_line(), "dh $@");
assert!(template.rules_extra(&o).is_empty()); assert!(template.rules_extra(&o).is_empty());
// Skeleton: hello.c + Makefile with all/install/clean, and the // Skeleton (manifest data): hello.c + Makefile with all/install/clean
// phony install target maps to debian/install. // targets, and the phony install target maps to debian/install.
let skeleton = template.skeleton(&o); let skeleton = template.skeleton(&o);
assert!(skeleton.iter().any(|f| f.path == "hello.c")); assert!(skeleton.iter().any(|f| f.path == "hello.c"));
let makefile = skeleton let makefile = skeleton
@@ -183,7 +147,7 @@ mod tests {
assert_eq!(debian[0].path, "debian/install"); assert_eq!(debian[0].path, "debian/install");
assert_eq!(debian[0].contents, "mytool usr/bin/mytool\n"); assert_eq!(debian[0].contents, "mytool usr/bin/mytool\n");
// Existing tree: nothing is emitted (probe log only). // Existing tree: nothing is emitted (the probe log only).
let o = opts(SourceDir::Here); let o = opts(SourceDir::Here);
assert!(template.debian(&o).is_empty()); assert!(template.debian(&o).is_empty());
} }
+58 -8
View File
@@ -44,7 +44,6 @@
pub mod autotools; pub mod autotools;
pub mod cmake; pub mod cmake;
pub mod empty;
pub mod go; pub mod go;
pub mod makefile; pub mod makefile;
pub mod meson; pub mod meson;
@@ -370,26 +369,61 @@ static TEMPLATE_SOURCES: &[TemplateSources] = &[
TemplateSources { TemplateSources {
id: TemplateId::GO, id: TemplateId::GO,
manifest: include_str!("../../../data/templates/go/manifest.yml"), manifest: include_str!("../../../data/templates/go/manifest.yml"),
tpls: &[], tpls: &[
(
"go.mod.tpl",
include_str!("../../../data/templates/go/go.mod.tpl"),
),
(
"main.go.tpl",
include_str!("../../../data/templates/go/main.go.tpl"),
),
],
hooks: Some(&go::HOOKS), hooks: Some(&go::HOOKS),
}, },
TemplateSources { TemplateSources {
id: TemplateId::SHELL, id: TemplateId::SHELL,
manifest: include_str!("../../../data/templates/shell/manifest.yml"), manifest: include_str!("../../../data/templates/shell/manifest.yml"),
tpls: &[], tpls: &[
(
"script.tpl",
include_str!("../../../data/templates/shell/script.tpl"),
),
(
"install.tpl",
include_str!("../../../data/templates/shell/install.tpl"),
),
],
hooks: Some(&shell::HOOKS), hooks: Some(&shell::HOOKS),
}, },
TemplateSources { TemplateSources {
id: TemplateId::MAKEFILE, id: TemplateId::MAKEFILE,
manifest: include_str!("../../../data/templates/makefile/manifest.yml"), manifest: include_str!("../../../data/templates/makefile/manifest.yml"),
tpls: &[], tpls: &[
(
"hello.c.tpl",
include_str!("../../../data/templates/makefile/hello.c.tpl"),
),
(
"Makefile.tpl",
include_str!("../../../data/templates/makefile/Makefile.tpl"),
),
(
"install.tpl",
include_str!("../../../data/templates/makefile/install.tpl"),
),
],
hooks: Some(&makefile::HOOKS), hooks: Some(&makefile::HOOKS),
}, },
TemplateSources { TemplateSources {
id: TemplateId::EMPTY, id: TemplateId::EMPTY,
manifest: include_str!("../../../data/templates/empty/manifest.yml"), manifest: include_str!("../../../data/templates/empty/manifest.yml"),
tpls: &[], tpls: &[(
hooks: Some(&empty::HOOKS), "README.tpl",
include_str!("../../../data/templates/empty/README.tpl"),
)],
// Pure data: the empty template ships without any logic half.
hooks: None,
}, },
]; ];
@@ -897,8 +931,8 @@ mod tests {
#[test] #[test]
fn probe_defaults_to_none() { fn probe_defaults_to_none() {
// The empty and shell templates alike: the root directory is no // Hookless (empty) and probe-carrying (shell) templates alike: the
// single-script project. // root directory is no single-script project.
assert!( assert!(
get(TemplateId::EMPTY) get(TemplateId::EMPTY)
.unwrap() .unwrap()
@@ -988,6 +1022,22 @@ mod tests {
assert_eq!(files[2].contents, "extra"); assert_eq!(files[2].contents, "extra");
} }
/// The empty template is pure data: a stub `README` skeleton, no extra
/// debian/ files (the metapackage `Depends` payload travels in the
/// options, not in the template).
#[test]
fn empty_template_shape() {
let o = opts(TemplateId::EMPTY);
let template = get(TemplateId::EMPTY).unwrap();
assert!(template.debian(&o).is_empty());
assert!(template.build_depends(&o).is_empty());
let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 1);
assert_eq!(skeleton[0].path, "README");
assert!(!skeleton[0].executable);
assert!(skeleton[0].contents.contains("mytool"));
}
/// Only the rust template contributes root `.gitignore` entries of its /// Only the rust template contributes root `.gitignore` entries of its
/// own — exactly the vendoring pair, unconditionally (its vendoring /// own — exactly the vendoring pair, unconditionally (its vendoring
/// hook runs in every mode); every other template contributes nothing. /// hook runs in every mode); every other template contributes nothing.
+21 -39
View File
@@ -1,17 +1,17 @@
//! The `shell` template: a single interpreted script installed to //! The `shell` template: a single interpreted script installed to
//! `/usr/bin` with plain `dh $@` plumbing. //! `/usr/bin` with plain `dh $@` plumbing.
//! //!
//! The data half lives in `data/templates/shell/manifest.yml`; the logic //! Everything except the probe is manifest data
//! half here is the single-script probe pre-filling the wizard answers from //! (`data/templates/shell/manifest.yml`: the skeleton script, its
//! the script file name (the same heuristic [`crate::new::detect`] bases //! skeleton-only `debian/install` mapping, the plain `dh $@` plumbing).
//! its shell detection on) plus, for now, the skeleton script and its //! The logic half here pre-fills the wizard answers from the file name of
//! skeleton-only `debian/install` mapping (the manifest `files:` list takes //! the single top-level script — the same heuristic [`crate::new::detect`]
//! those over once their bodies are static data). //! bases its shell detection on.
use std::path::Path; use std::path::Path;
use super::{OutputFile, ProbeResult, TemplateHooks}; use super::{ProbeResult, TemplateHooks};
use crate::new::options::{self, NewOptions, SourceDir}; use crate::new::options;
/// The logic half of the shell template. /// The logic half of the shell template.
pub struct Hooks; pub struct Hooks;
@@ -20,34 +20,6 @@ pub struct Hooks;
pub static HOOKS: Hooks = Hooks; pub static HOOKS: Hooks = Hooks;
impl TemplateHooks for Hooks { impl TemplateHooks for Hooks {
/// A minimal executable script named after the command, with a `#!/bin/sh`
/// shebang and an `echo` placeholder.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
vec![OutputFile::executable(
format!("{}.sh", opts.command),
format!(
"#!/bin/sh\n# Placeholder for {}, generated by `pkh new`.\n\
echo \"Hello from {}!\"\n",
opts.name, opts.command
),
)]
}
/// `debian/install` mapping the script into `/usr/bin/<command>`
/// (debian/install renames when the destination carries a file name).
/// Only for the skeleton mode: when packaging an existing tree the
/// generated mapping would reference the non-existent skeleton script,
/// so the user writes their own install file instead.
fn debian_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
if !matches!(opts.source_dir, SourceDir::Skeleton) {
return Vec::new();
}
vec![OutputFile::new(
"debian/install",
format!("{}.sh usr/bin/{}\n", opts.command, opts.command),
)]
}
/// The file name of the single top-level script (sanitized) pre-fills the /// The file name of the single top-level script (sanitized) pre-fills the
/// package name and command questions. /// package name and command questions.
fn probe(&self, dir: &Path) -> Option<ProbeResult> { fn probe(&self, dir: &Path) -> Option<ProbeResult> {
@@ -64,12 +36,11 @@ impl TemplateHooks for Hooks {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use crate::new::options::{License, SourceDir, TemplateId}; use crate::new::options::{License, SourceDir, TemplateId};
use tempfile::tempdir; use tempfile::tempdir;
fn opts() -> NewOptions { fn opts() -> crate::new::options::NewOptions {
NewOptions { crate::new::options::NewOptions {
name: "mytool".into(), name: "mytool".into(),
template: TemplateId::SHELL, template: TemplateId::SHELL,
source_dir: SourceDir::Skeleton, source_dir: SourceDir::Skeleton,
@@ -103,16 +74,27 @@ mod tests {
assert!(template.build_depends(&o).is_empty()); assert!(template.build_depends(&o).is_empty());
assert!(template.rules_extra(&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); let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 1); assert_eq!(skeleton.len(), 1);
assert_eq!(skeleton[0].path, "mytool.sh"); assert_eq!(skeleton[0].path, "mytool.sh");
assert!(skeleton[0].executable); assert!(skeleton[0].executable);
assert!(skeleton[0].contents.starts_with("#!/bin/sh\n")); assert!(skeleton[0].contents.starts_with("#!/bin/sh\n"));
assert!(skeleton[0].contents.contains("echo \"Hello from mytool!\""));
let debian = template.debian(&o); let debian = template.debian(&o);
assert_eq!(debian.len(), 1); assert_eq!(debian.len(), 1);
assert_eq!(debian[0].path, "debian/install"); assert_eq!(debian[0].path, "debian/install");
assert_eq!(debian[0].contents, "mytool.sh usr/bin/mytool\n"); 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] #[test]