feat: add --list-formats command, support auto-generated man pages
Release / check-release (push) Successful in 16s
Release / build_gnu (push) Skipped
Release / build_musl (push) Skipped
Release / build_windows (push) Skipped
Release / package_gnu (deb) (push) Skipped
Release / package_gnu (rpm) (push) Skipped
Release / package_musl (deb) (push) Skipped
Release / package_musl (rpm) (push) Skipped
Release / publish-release (push) Skipped
CI / Test (push) Successful in 1m43s
CI / Build Linux (push) Successful in 2m21s

This commit is contained in:
Elias Wendland
2026-07-16 13:26:49 +02:00
parent f58f73194e
commit a372937854
4 changed files with 70 additions and 11 deletions
+12 -1
View File
@@ -24,15 +24,26 @@ extended-description = "A program attempting to be a universal file converter"
depends = "ffmpeg, $auto"
section = "utility"
priority = "optional"
assets = [
["target/release/convertis", "usr/bin/", "755"],
["README.md", "usr/share/doc/convertis/README", "644"],
["target/man/convertis.1", "usr/share/man/man1/convertis.1", "644"]
]
[package.metadata.generate-rpm]
assets = [
{ source = "target/release/convertis", dest = "/usr/bin/convertis", mode = "755" }
{ source = "target/release/convertis", dest = "/usr/bin/convertis", mode = "755" },
{ source = "target/man/convertis.1", dest = "/usr/share/man/man1/convertis.1", mode = "644" }
]
[package.metadata.generate-rpm.requires]
ffmpeg = "*"
[build-dependencies]
clap = { version = "4.6.1", features = ["derive"] }
clap_mangen = "0.2"
tracing = "0.1.44"
[dependencies]
clap = { version = "4.6.1", features = ["derive"] }
image = "0.25.10"
+14
View File
@@ -16,6 +16,10 @@ use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;
use clap::CommandFactory;
#[path = "src/args.rs"]
mod args;
fn run_command(cmd: &str, args: &[&str]) -> Option<String> {
let output = Command::new(cmd).args(args).output().ok()?;
@@ -104,4 +108,14 @@ fn main() {
let version_path = Path::new(&out_dir).join("version.txt");
fs::write(&version_path, &version_string).unwrap();
// Generate man page
let man_dir = Path::new("target").join("man");
fs::create_dir_all(&man_dir).unwrap();
let mut cmd = args::Args::command();
cmd = cmd.name("convertis").version(env!("CARGO_PKG_VERSION"));
let man = clap_mangen::Man::new(cmd);
let mut buffer: Vec<u8> = Default::default();
man.render(&mut buffer).unwrap();
fs::write(man_dir.join("convertis.1"), buffer).unwrap();
}
+8 -4
View File
@@ -15,11 +15,15 @@
use clap::Parser;
use std::path::PathBuf;
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
#[derive(Parser, Debug)]
#[command(version = VERSION, about = "A file converter program.", long_about = None)]
#[command(about = "A file converter program.", long_about = None)]
pub struct Args {
#[arg(
long,
help = "List all supported formats.",
exclusive = true
)]
pub list_formats: bool,
#[arg(
short = 'v',
long,
@@ -58,7 +62,7 @@ pub struct Args {
pub priority: String,
#[arg(help = "The input file path.")]
pub input_path: String,
pub input_path: Option<String>,
#[arg(help = "The output file path (optional).")]
pub output_path: Option<String>,
+36 -6
View File
@@ -21,13 +21,18 @@ pub mod runner;
include!(concat!(env!("OUT_DIR"), "/plugins_gen.rs"));
use args::Args;
use clap::Parser;
use clap::{Parser, CommandFactory, FromArgMatches};
use std::fs;
use std::io::{self, IsTerminal, Write};
use std::process;
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
fn main() {
let args = Args::parse();
let mut command = Args::command();
command = command.version(VERSION);
let matches = command.get_matches();
let args = Args::from_arg_matches(&matches).expect("Failed to parse arguments");
let level_filter = if args.quiet {
tracing_subscriber::filter::LevelFilter::OFF
@@ -39,8 +44,35 @@ fn main() {
.with_max_level(level_filter)
.init();
let plugins = get_plugins();
if args.list_formats {
let mut formats: std::collections::HashSet<&str> = std::collections::HashSet::new();
for p in &plugins {
formats.extend(p.from_formats());
formats.extend(p.to_formats());
}
let mut formats_vec: Vec<_> = formats.into_iter().collect();
formats_vec.sort();
println!("Supported Formats:");
for chunk in formats_vec.chunks(6) {
let row = chunk.iter().map(|s| format!("{:<10}", s)).collect::<Vec<_>>().join(" ");
println!(" {}", row);
}
return;
}
let input_path = match &args.input_path {
Some(path) => path,
None => {
tracing::error!("Input file path is required unless --list-formats is used.");
process::exit(1);
}
};
// Read input file
let input_bytes = match fs::read(&args.input_path) {
let input_bytes = match fs::read(input_path) {
Ok(b) => b,
Err(e) => {
tracing::error!("Error reading input file: {}", e);
@@ -48,9 +80,7 @@ fn main() {
}
};
let plugins = get_plugins();
let from_format = match identifier::identify_format(&args.input_path, &plugins) {
let from_format = match identifier::identify_format(input_path, &plugins) {
Some(f) => f,
None => {
tracing::error!("Unknown input format.");