Move manpages generation to an xtask

PR #596 brought forward automatic generation of Linux manual pages for
Oxipng, which is executed every time Oxipng is built. However, while
building manpages on every build is convenient for Oxipng development
and doing so didn't catch my attention initially, it introduces
noticeable inefficiencies for crates using Oxipng as a library: during
their build, Oxipng manpages are also built, even though most dependent
crates won't use such artifacts, as they are not considered part of the
public Oxipng crate API or even appropriate for non-human consumption.

Moreover, generating manpages depends on `clap`, which is a heavyweight
dependency: according to a fresh `cargo build --timings --release` on my
development workstation, its `clap_builder` dependency is the third most
time consuming unit to build, totalling 1.5 s (out of 11.7 s, or 12.8%).
And there is no way for dependent crates to turn this off:
[`build-dependencies` cannot be conditional on crate
features](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#platform-specific-dependencies).
Potentially using other `cfg` hacks to either enable or disable
manpage generation is unergonomic, if not outright disallowed. Besides
reducing their compilation time cost, dependent crates may also want to
trim the size of their dependency tree, avoiding unnecessary dependency
downloads in the process.

Therefore, a better solution to conditionally build manpages in a way
convenient for both Oxipng maintainers and downstream consumers is
needed. My proposal implemented in this PR is to leverage the
[`cargo-xtask`](https://github.com/matklad/cargo-xtask) convention to
define an auxiliary crate to move the manpage generation logic and
dependencies to, which is to be used exclusively by Oxipng maintainers
and not part of the `oxipng` crate published on `crates.io`. That way
Oxipng maintainers and packagers can still generate manpages at request
with ease, without any automation being noticeable to uninterested crate
consumers. And as a side benefit, Oxipng maintainers can also benefit
from slightly faster iteration times due to the lack of a build script
for the main crate.

The new `mangen` xtask can be run at any time with `cargo xtask mangen`.
The generated manpages are now available at `target/xtask/mangen/manpages`.
Existing deployment scripts were updated accordingly.
This commit is contained in:
Alejandro González 2024-11-19 22:49:57 +01:00
parent e7f1c04488
commit 4c310c1ebd
No known key found for this signature in database
9 changed files with 242 additions and 63 deletions

View file

@ -1,3 +1,6 @@
[alias]
xtask = "run --manifest-path xtask/Cargo.toml --"
[target.'cfg(all(target_os = "linux", target_arch = "aarch64"))']
runner = "qemu-aarch64" # May need to remove this if targeting AArch64 from an AArch64 Linux box

View file

@ -90,7 +90,7 @@ jobs:
run: |
mkdir -p "target/${{ matrix.target }}/release"
mv target/oxipng "target/${{ matrix.target }}/release"
mv target/debug/assets "target/${{ matrix.target }}/release"
mv target/xtask/mangen/manpages "target/${{ matrix.target }}/release"
cargo install --locked cargo-deb
cargo deb --target "${{ matrix.target }}" --no-build --no-strip

17
Cargo.lock generated
View file

@ -148,16 +148,6 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]]
name = "clap_mangen"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbae9cbfdc5d4fa8711c09bd7b83f644cb48281ac35bf97af3e47b0675864bdf"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
@ -412,7 +402,6 @@ version = "9.1.2"
dependencies = [
"bitvec",
"clap",
"clap_mangen",
"crossbeam-channel",
"env_logger",
"filetime",
@ -484,12 +473,6 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "rustc-hash"
version = "2.0.0"

View file

@ -13,6 +13,7 @@ exclude = [
"Dockerfile",
"scripts/*",
"tests/*",
"xtask/*",
]
homepage = "https://github.com/shssoichiro/oxipng"
license = "MIT"
@ -77,10 +78,6 @@ default-features = false
features = ["png"]
version = "0.25.5"
[build-dependencies]
clap = "4.5.21"
clap_mangen = "0.2.24"
[features]
binary = ["dep:clap", "dep:glob", "dep:env_logger"]
default = ["binary", "parallel", "zopfli", "filetime"]
@ -105,7 +102,7 @@ panic = "abort"
[package.metadata.deb]
assets = [
["target/release/oxipng", "usr/bin/", "755"],
["target/release/assets/oxipng.1", "usr/share/man/man1/", "644"],
["target/release/manpages/oxipng.1", "usr/share/man/man1/", "644"],
["README.md", "usr/share/doc/oxipng/", "644"],
["CHANGELOG.md", "usr/share/doc/oxipng/", "644"],
]

View file

@ -1,40 +0,0 @@
use std::{
env,
fs::File,
io::{BufWriter, Error},
path::Path,
};
use clap_mangen::Man;
include!("src/cli.rs");
fn build_manpages(outdir: &Path) -> Result<(), Error> {
let app = build_command();
let file = Path::new(&outdir).join("oxipng.1");
let mut file = BufWriter::new(File::create(file)?);
Man::new(app).render(&mut file)?;
Ok(())
}
fn main() -> Result<(), Error> {
println!("cargo:rerun-if-changed=src/cli.rs");
println!("cargo:rerun-if-changed=src/display_chunks.rs");
// Create `target/<debug|release>/assets/` folder.
let outdir = match env::var_os("OUT_DIR") {
None => return Ok(()),
Some(outdir) => outdir,
};
let out_path = PathBuf::from(outdir);
let mut path = out_path.ancestors().nth(3).unwrap().to_owned();
path.push("assets");
std::fs::create_dir_all(&path).unwrap();
build_manpages(&path)?;
Ok(())
}

View file

@ -1,5 +1,6 @@
#!/bin/bash
cargo build
cargo xstask mangen
./target/debug/oxipng -V > MANUAL.txt
#Redirect all streams to prevent detection of the terminal width and force an internal default of 100

200
xtask/Cargo.lock generated Normal file
View file

@ -0,0 +1,200 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]]
name = "clap_mangen"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbae9cbfdc5d4fa8711c09bd7b83f644cb48281ac35bf97af3e47b0675864bdf"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "xtask"
version = "0.0.0"
dependencies = [
"clap",
"clap_mangen",
]

9
xtask/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "xtask"
description = "xtasks for the Oxipng project: https://github.com/matklad/cargo-xtask"
edition = "2021"
publish = false
[dependencies]
clap = "4.5.21"
clap_mangen = "0.2.24"

26
xtask/src/main.rs Normal file
View file

@ -0,0 +1,26 @@
use std::{env, error::Error, fs, fs::File, io::BufWriter};
use clap_mangen::Man;
include!("../../src/cli.rs");
fn main() -> Result<(), Box<dyn Error>> {
match &*env::args().nth(1).ok_or("No xtask to run provided")? {
"mangen" => build_manpages(),
_ => Err("Unknown xtask".into()),
}
}
fn build_manpages() -> Result<(), Box<dyn Error>> {
// Put manpages in <working directory>/target/xtask/mangen/manpages. Our working directory is
// expected to be the root of the repository due to the xtask invocation alias
let manpages_dir = env::current_dir()?.join("target/xtask/mangen/manpages");
fs::create_dir_all(&manpages_dir)?;
let mut man_file = BufWriter::new(File::create(manpages_dir.join("oxipng.1"))?);
Man::new(build_command()).render(&mut man_file)?;
println!("Manpages generated in {}", manpages_dir.display());
Ok(())
}