new: port the meson, cmake and autotools template bodies to manifests

This commit is contained in:
2026-09-18 15:08:27 +02:00
parent e6f2012835
commit fa399f64b2
14 changed files with 203 additions and 145 deletions
+2
View File
@@ -0,0 +1,2 @@
bin_PROGRAMS = {command}
{command}_SOURCES = hello.c
@@ -0,0 +1,5 @@
AC_INIT([{name}], [{upstream_version}])
AM_INIT_AUTOMAKE([foreign])
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
+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;
}
+15 -4
View File
@@ -1,8 +1,13 @@
## The `autotools` template: a C project with a configure.ac built through ## The `autotools` template: a C project with a configure.ac built through
## debhelper's auto-detection (dh runs autoreconf itself when it finds ## debhelper's auto-detection (dh runs autoreconf itself when it finds
## configure.ac, debhelper >= 10 — no override needed). The logic half — ## configure.ac, debhelper >= 10 — no override needed). The skeleton bodies
## the AC_INIT probe, the skeleton bodies and the gettext detection ## below are static data (the first source build runs `autoreconf`,
## (appended to Build-Depends) — lives in src/new/templates/autotools.rs. ## integrated in the dh sequence, so no generated configure script is
## committed); the logic half — the AC_INIT probe and the GNU-gettext
## detection (appended to Build-Depends) — lives in
## src/new/templates/autotools.rs. hello.c.tpl duplicates the shared C
## skeleton of the other C/C++ template directories (see
## meson/manifest.yml for why).
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -16,4 +21,10 @@ build_depends:
- libtool - libtool
architecture: any architecture: any
rules_dh_line: "dh $@" rules_dh_line: "dh $@"
files: [] files:
- path: configure.ac
template: configure.ac.tpl
- path: Makefile.am
template: Makefile.am.tpl
- path: hello.c
template: hello.c.tpl
+5
View File
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project({name} VERSION {upstream_version})
add_executable({command} hello.c)
install(TARGETS {command} RUNTIME DESTINATION bin)
+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;
}
+10 -4
View File
@@ -1,7 +1,9 @@
## The `cmake` template: a C/C++ project built with CMake through the ## The `cmake` template: a C/C++ project built with CMake through the
## debhelper cmake buildsystem. The logic half — the project() probe, the ## debhelper cmake buildsystem. The skeleton bodies below are static data;
## skeleton bodies and the wizard's pkg-config opt-in (appended to ## the logic half — the project() probe and the wizard's pkg-config
## Build-Depends) — lives in src/new/templates/cmake.rs. ## opt-in (appended to Build-Depends) — lives in src/new/templates/cmake.rs.
## hello.c.tpl duplicates the shared C skeleton of the other C/C++
## template directories (see meson/manifest.yml for why).
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -13,4 +15,8 @@ build_depends:
- cmake - cmake
architecture: any architecture: any
rules_dh_line: "dh $@ --buildsystem=cmake" rules_dh_line: "dh $@ --buildsystem=cmake"
files: [] files:
- path: CMakeLists.txt
template: CMakeLists.txt.tpl
- path: hello.c
template: hello.c.tpl
+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;
}
+16 -4
View File
@@ -1,7 +1,15 @@
## The `meson` template: a C/C++ project built with Meson through the ## The `meson` template: a C/C++ project built with Meson through the
## debhelper meson buildsystem. The logic half — the project() probe, the ## debhelper meson buildsystem. The skeleton bodies below are static data;
## skeleton bodies and the wizard's pkg-config opt-in (appended to ## the logic half — the project() probe and the wizard's pkg-config
## Build-Depends) — lives in src/new/templates/meson.rs. ## opt-in (appended to Build-Depends) — lives in src/new/templates/meson.rs.
##
## hello.c.tpl is deliberately duplicated (byte-identical) across the
## makefile, cmake and autotools template directories: every template
## directory is self-contained — the registry embeds each directory's
## bodies under its own entry — so a shared body would need
## cross-directory references the manifest schema has no machinery for.
## The duplication replaces the Rust hello_c() helper meson.rs used to
## lend cmake.rs and autotools.rs.
## ##
## Schema: see src/new/templates/mod.rs. ## Schema: see src/new/templates/mod.rs.
@@ -13,4 +21,8 @@ build_depends:
- meson - meson
architecture: any architecture: any
rules_dh_line: "dh $@ --buildsystem=meson" rules_dh_line: "dh $@ --buildsystem=meson"
files: [] files:
- path: meson.build
template: meson.build.tpl
- path: hello.c
template: hello.c.tpl
+3
View File
@@ -0,0 +1,3 @@
project('{name}', version: '{upstream_version}', license: '{license}', default_options: ['c_std=c11'])
executable('{command}', 'hello.c', install: true)
+34 -42
View File
@@ -2,17 +2,16 @@
//! debhelper's auto-detection (dh runs `autoreconf` itself when it finds //! debhelper's auto-detection (dh runs `autoreconf` itself when it finds
//! `configure.ac`, debhelper ≥ 10 — no override needed). //! `configure.ac`, debhelper ≥ 10 — no override needed).
//! //!
//! The metadata is manifest data; the logic half here is the `AC_INIT` //! The metadata and the `configure.ac`/`Makefile.am`/`hello.c` skeleton
//! probe, the GNU-gettext detection (appending `gettext` to the manifest's //! bodies are manifest data (`data/templates/autotools/manifest.yml`); the
//! Build-Depends) and — until the bodies move into the manifest's `files:` //! logic half here is the `AC_INIT` probe and the GNU-gettext detection
//! list — the `configure.ac`/`Makefile.am`/`hello.c` skeleton. //! (appending `gettext` to the manifest's Build-Depends).
use std::path::Path; use std::path::Path;
use regex::Regex; use regex::Regex;
use super::meson::hello_c; use super::{ProbeResult, TemplateHooks, source_dir_of};
use super::{OutputFile, ProbeResult, TemplateHooks, source_dir_of};
use crate::new::options::NewOptions; use crate::new::options::NewOptions;
/// The logic half of the autotools template. /// The logic half of the autotools template.
@@ -22,35 +21,6 @@ pub struct Hooks;
pub static HOOKS: Hooks = Hooks; pub static HOOKS: Hooks = Hooks;
impl TemplateHooks for Hooks { impl TemplateHooks for Hooks {
/// A minimal `configure.ac`, the matching `Makefile.am` and `hello.c`.
/// The first source build runs `autoreconf` (integrated in the dh
/// sequence), so no generated configure script is committed.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
vec![
OutputFile::new(
"configure.ac",
format!(
"AC_INIT([{name}], [{version}])\n\
AM_INIT_AUTOMAKE([foreign])\n\
AC_PROG_CC\n\
AC_CONFIG_FILES([Makefile])\n\
AC_OUTPUT\n",
name = opts.name,
version = opts.upstream_version,
),
),
OutputFile::new(
"Makefile.am",
format!(
"bin_PROGRAMS = {command}\n\
{command}_SOURCES = hello.c\n",
command = opts.command,
),
),
hello_c(opts),
]
}
/// A packaged `configure.ac` that sets up GNU gettext (the /// A packaged `configure.ac` that sets up GNU gettext (the
/// `AM_GNU_GETTEXT` macro, see [`uses_gettext`]) appends `gettext` to /// `AM_GNU_GETTEXT` macro, see [`uses_gettext`]) appends `gettext` to
/// the manifest's Build-Depends. /// the manifest's Build-Depends.
@@ -149,23 +119,45 @@ mod tests {
assert!(template.rules_extra(&o).is_empty()); assert!(template.rules_extra(&o).is_empty());
assert!(template.debian(&o).is_empty()); assert!(template.debian(&o).is_empty());
// Skeleton (manifest data): configure.ac + Makefile.am + hello.c,
// byte-exact.
let skeleton = template.skeleton(&o); let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 3);
let configure = skeleton let configure = skeleton
.iter() .iter()
.find(|f| f.path == "configure.ac") .find(|f| f.path == "configure.ac")
.expect("configure.ac skeleton"); .expect("configure.ac skeleton");
assert!( assert_eq!(
configure configure.contents,
.contents "AC_INIT([mytool], [0.1.0])\n\
.starts_with("AC_INIT([mytool], [0.1.0])\n") AM_INIT_AUTOMAKE([foreign])\n\
AC_PROG_CC\n\
AC_CONFIG_FILES([Makefile])\n\
AC_OUTPUT\n"
); );
let makefile_am = skeleton let makefile_am = skeleton
.iter() .iter()
.find(|f| f.path == "Makefile.am") .find(|f| f.path == "Makefile.am")
.expect("Makefile.am skeleton"); .expect("Makefile.am skeleton");
assert!(makefile_am.contents.contains("bin_PROGRAMS = mytool")); assert_eq!(
assert!(makefile_am.contents.contains("mytool_SOURCES = hello.c")); makefile_am.contents,
assert!(skeleton.iter().any(|f| f.path == "hello.c")); "bin_PROGRAMS = mytool\nmytool_SOURCES = hello.c\n"
);
let hello = skeleton
.iter()
.find(|f| f.path == "hello.c")
.expect("hello.c skeleton");
assert_eq!(
hello.contents,
"#include <stdio.h>\n\
\n\
/* Placeholder for mytool, generated by `pkh new`. */\n\
int main(void)\n\
{\n\
\tprintf(\"Hello from mytool!\\n\");\n\
\treturn 0;\n\
}\n"
);
} }
#[test] #[test]
+27 -35
View File
@@ -1,16 +1,15 @@
//! The `cmake` template: a C/C++ project built with CMake through the //! The `cmake` template: a C/C++ project built with CMake through the
//! debhelper cmake buildsystem. //! debhelper cmake buildsystem.
//! //!
//! The metadata is manifest data; the logic half here is the `project()` //! The metadata and the `CMakeLists.txt`/`hello.c` skeleton bodies are
//! probe, the wizard's pkg-config opt-in (appended to the manifest's //! manifest data (`data/templates/cmake/manifest.yml`); the logic half
//! Build-Depends) and — until the bodies move into the manifest's `files:` //! here is the `project()` probe and the wizard's pkg-config opt-in
//! list — the `CMakeLists.txt`/`hello.c` skeleton. //! (appended to the manifest's Build-Depends).
use std::path::Path; use std::path::Path;
use regex::Regex; use regex::Regex;
use super::meson::hello_c;
use super::{ProbeResult, TemplateHooks}; use super::{ProbeResult, TemplateHooks};
use crate::new::options::NewOptions; use crate::new::options::NewOptions;
@@ -21,27 +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 `CMakeLists.txt` (project declaration + one installed
/// executable) and the classic `hello.c`.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<super::OutputFile> {
vec![
super::OutputFile::new(
"CMakeLists.txt",
format!(
"cmake_minimum_required(VERSION 3.16)\n\
project({name} VERSION {version})\n\
\n\
add_executable({command} hello.c)\n\
install(TARGETS {command} RUNTIME DESTINATION bin)\n",
name = opts.name,
version = opts.upstream_version,
command = opts.command,
),
),
hello_c(opts),
]
}
/// The wizard's pkg-config opt-in ([`NewOptions::pkg_config`], offered /// The wizard's pkg-config opt-in ([`NewOptions::pkg_config`], offered
/// when the project's build file hints at `pkg_check_modules` usage) /// when the project's build file hints at `pkg_check_modules` usage)
/// adds `pkg-config` to the manifest's Build-Depends. /// adds `pkg-config` to the manifest's Build-Depends.
@@ -116,22 +94,36 @@ mod tests {
assert!(template.rules_extra(&o).is_empty()); assert!(template.rules_extra(&o).is_empty());
assert!(template.debian(&o).is_empty()); assert!(template.debian(&o).is_empty());
// Skeleton (manifest data): CMakeLists.txt + hello.c, byte-exact.
let skeleton = template.skeleton(&o); let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 2);
let cmakelists = skeleton let cmakelists = skeleton
.iter() .iter()
.find(|f| f.path == "CMakeLists.txt") .find(|f| f.path == "CMakeLists.txt")
.expect("CMakeLists.txt skeleton"); .expect("CMakeLists.txt skeleton");
assert!( assert_eq!(
cmakelists cmakelists.contents,
.contents "cmake_minimum_required(VERSION 3.16)\n\
.contains("project(mytool VERSION 0.1.0)") project(mytool VERSION 0.1.0)\n\
\n\
add_executable(mytool hello.c)\n\
install(TARGETS mytool RUNTIME DESTINATION bin)\n"
); );
assert!( let hello = skeleton
cmakelists .iter()
.contents .find(|f| f.path == "hello.c")
.contains("add_executable(mytool hello.c)") .expect("hello.c skeleton");
assert_eq!(
hello.contents,
"#include <stdio.h>\n\
\n\
/* Placeholder for mytool, generated by `pkh new`. */\n\
int main(void)\n\
{\n\
\tprintf(\"Hello from mytool!\\n\");\n\
\treturn 0;\n\
}\n"
); );
assert!(skeleton.iter().any(|f| f.path == "hello.c"));
} }
#[test] #[test]
+28 -53
View File
@@ -1,17 +1,16 @@
//! The `meson` template: a C/C++ project built with Meson through the //! The `meson` template: a C/C++ project built with Meson through the
//! debhelper meson buildsystem. //! debhelper meson buildsystem.
//! //!
//! The metadata is manifest data; the logic half here is the `project()` //! The metadata and the `meson.build`/`hello.c` skeleton bodies are
//! probe, the wizard's pkg-config opt-in (appended to the manifest's //! manifest data (`data/templates/meson/manifest.yml`); the logic half
//! Build-Depends) and — until the bodies move into the manifest's `files:` //! here is the `project()` probe and the wizard's pkg-config opt-in
//! list — the `meson.build`/`hello.c` skeleton. [`hello_c`] is the shared //! (appended to the manifest's Build-Depends).
//! placeholder of the C/C++ skeletons.
use std::path::Path; use std::path::Path;
use regex::Regex; use regex::Regex;
use super::{OutputFile, ProbeResult, TemplateHooks}; use super::{ProbeResult, TemplateHooks};
use crate::new::options::NewOptions; use crate::new::options::NewOptions;
/// The logic half of the meson template. /// The logic half of the meson template.
@@ -21,27 +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 `meson.build` (project declaration + one installed
/// executable) and the classic `hello.c`.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
vec![
OutputFile::new(
"meson.build",
format!(
"project('{name}', version: '{version}', license: '{license}', \
default_options: ['c_std=c11'])\n\
\n\
executable('{command}', 'hello.c', install: true)\n",
name = opts.name,
version = opts.upstream_version,
license = opts.license.spdx(),
command = opts.command,
),
),
hello_c(opts),
]
}
/// The wizard's pkg-config opt-in ([`NewOptions::pkg_config`], offered /// The wizard's pkg-config opt-in ([`NewOptions::pkg_config`], offered
/// when the project's build file hints at `dependency(` usage) adds /// when the project's build file hints at `dependency(` usage) adds
/// `pkg-config` to the manifest's Build-Depends. /// `pkg-config` to the manifest's Build-Depends.
@@ -69,25 +47,6 @@ impl TemplateHooks for Hooks {
} }
} }
/// The shared `hello.c` placeholder of the C/C++ skeletons.
pub(super) fn hello_c(opts: &NewOptions) -> OutputFile {
OutputFile::new(
"hello.c",
format!(
"#include <stdio.h>\n\
\n\
/* Placeholder for {name}, generated by `pkh new`. */\n\
int main(void)\n\
{{\n\
\tprintf(\"Hello from {command}!\\n\");\n\
\treturn 0;\n\
}}\n",
name = opts.name,
command = opts.command,
),
)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -131,19 +90,35 @@ mod tests {
assert!(template.rules_extra(&o).is_empty()); assert!(template.rules_extra(&o).is_empty());
assert!(template.debian(&o).is_empty()); assert!(template.debian(&o).is_empty());
// Skeleton (manifest data): meson.build + hello.c, byte-exact.
let skeleton = template.skeleton(&o); let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 2);
let meson_build = skeleton let meson_build = skeleton
.iter() .iter()
.find(|f| f.path == "meson.build") .find(|f| f.path == "meson.build")
.expect("meson.build skeleton"); .expect("meson.build skeleton");
assert!(meson_build.contents.contains("project('mytool'")); assert_eq!(
assert!(meson_build.contents.contains("version: '0.1.0'")); meson_build.contents,
assert!( "project('mytool', version: '0.1.0', license: 'MIT', \
meson_build default_options: ['c_std=c11'])\n\
.contents \n\
.contains("executable('mytool', 'hello.c', install: true)") executable('mytool', 'hello.c', install: true)\n"
);
let hello = skeleton
.iter()
.find(|f| f.path == "hello.c")
.expect("hello.c skeleton");
assert_eq!(
hello.contents,
"#include <stdio.h>\n\
\n\
/* Placeholder for mytool, generated by `pkh new`. */\n\
int main(void)\n\
{\n\
\tprintf(\"Hello from mytool!\\n\");\n\
\treturn 0;\n\
}\n"
); );
assert!(skeleton.iter().any(|f| f.path == "hello.c"));
} }
#[test] #[test]
+34 -3
View File
@@ -362,19 +362,50 @@ static TEMPLATE_SOURCES: &[TemplateSources] = &[
TemplateSources { TemplateSources {
id: TemplateId::MESON, id: TemplateId::MESON,
manifest: include_str!("../../../data/templates/meson/manifest.yml"), manifest: include_str!("../../../data/templates/meson/manifest.yml"),
tpls: &[], tpls: &[
(
"meson.build.tpl",
include_str!("../../../data/templates/meson/meson.build.tpl"),
),
(
"hello.c.tpl",
include_str!("../../../data/templates/meson/hello.c.tpl"),
),
],
hooks: Some(&meson::HOOKS), hooks: Some(&meson::HOOKS),
}, },
TemplateSources { TemplateSources {
id: TemplateId::CMAKE, id: TemplateId::CMAKE,
manifest: include_str!("../../../data/templates/cmake/manifest.yml"), manifest: include_str!("../../../data/templates/cmake/manifest.yml"),
tpls: &[], tpls: &[
(
"CMakeLists.txt.tpl",
include_str!("../../../data/templates/cmake/CMakeLists.txt.tpl"),
),
(
"hello.c.tpl",
include_str!("../../../data/templates/cmake/hello.c.tpl"),
),
],
hooks: Some(&cmake::HOOKS), hooks: Some(&cmake::HOOKS),
}, },
TemplateSources { TemplateSources {
id: TemplateId::AUTOTOOLS, id: TemplateId::AUTOTOOLS,
manifest: include_str!("../../../data/templates/autotools/manifest.yml"), manifest: include_str!("../../../data/templates/autotools/manifest.yml"),
tpls: &[], tpls: &[
(
"configure.ac.tpl",
include_str!("../../../data/templates/autotools/configure.ac.tpl"),
),
(
"Makefile.am.tpl",
include_str!("../../../data/templates/autotools/Makefile.am.tpl"),
),
(
"hello.c.tpl",
include_str!("../../../data/templates/autotools/hello.c.tpl"),
),
],
hooks: Some(&autotools::HOOKS), hooks: Some(&autotools::HOOKS),
}, },
TemplateSources { TemplateSources {