Files
NLnetLabs-dnst/src/lib.rs
T
617b623ba3 Add keygen command. (#9)
* Keygen skeleton.

* [keygen] Implement the basic features

* [keygen] synchronize files before exiting

* [keygen] Add help documentation

* [keygen] Generate '.ds' files for KSKs

* [keygen] Use 'display_as_bind()'

* [keygen] Add support for symlinks (Unix only)

* [keygen] Improve errors and support '.ds' symlinks

* Implement ldns-specific parsing for 'keygen'

* [keygen] Implement '-v' with version info

* [keygen] Add 'cfg(unix)' in ldns-parsing

* [keygen] Correctly handle duplicate options in ldns parsing

* Revert "[keygen] Implement '-v' with version info"

This reverts commit 643ab86bd4.

See: <https://github.com/NLnetLabs/dnst/pull/9#discussion_r1843460496>

* [keygen] Integrate the use of 'Env'

* [workflows/ci] Add OpenSSL installation steps

* [workflows/ci] Integrate OpenSSL for 'minimal_versions'

* [keygen] Improve the 'dnst' interface

* [keygen] Satisfy clippy

* [keygen] Simplify symlink CLI

* Add basic filesystem operations to 'Env'

* [keygen] Use symlink ops provided by 'Env'

* [keygen] Add basic tests for argument parsing

* [keygen] Add tests

* [keygen] Satisfy 'minimal-versions'

* [keygen] Satisfy clippy

* [keygen] Add Windows-specific missing branch

* [keygen] Document parsing for 'symlink'

* [keygen] Report error on '-r'

* [env] Refactor util fns into a 'util' module

* [keygen::symlink] Mark params as used, for Windows

* [keygen] Fix double error message

See: <https://github.com/NLnetLabs/dnst/pull/9#discussion_r1862213985>

* [keygen] Use 'Args::Report'

* [keygen] Allow invalid HTML in docs for Clap

* Use 'domain'-style imports

* [keygen] Use uppercase for expected clap values

* [keygen] use lowercase value names in Clap

---------

Co-authored-by: arya dradjica <arya@nlnetlabs.nl>
2024-12-02 11:20:21 +01:00

94 lines
2.6 KiB
Rust

use std::ffi::OsString;
use std::path::Path;
use clap::Parser;
use commands::{key2ds::Key2ds, keygen::Keygen, nsec3hash::Nsec3Hash, LdnsCommand};
use env::Env;
use error::Error;
pub use self::args::Args;
pub mod args;
pub mod commands;
pub mod env;
pub mod error;
pub mod parse;
pub mod util;
pub fn try_ldns_compatibility<I: IntoIterator<Item = OsString>>(
args: I,
) -> Result<Option<Args>, Error> {
let mut args_iter = args.into_iter();
let binary_path = args_iter.next().ok_or("Missing binary name")?;
let binary_name = extract_binary_name(Path::new(&binary_path))?;
// We only branch on the binary name for the ldns utilities. The rest we
// just handle as regular dnst.
let Some(binary_name) = binary_name.strip_prefix("ldns-") else {
return Ok(None);
};
let res = match binary_name {
"key2ds" => Key2ds::parse_ldns_args(args_iter),
"keygen" => Keygen::parse_ldns_args(args_iter),
"nsec3-hash" => Nsec3Hash::parse_ldns_args(args_iter),
_ => return Err(format!("Unrecognized ldns command 'ldns-{binary_name}'").into()),
};
Ok(Some(res?))
}
/// Get the binary name from a [`Path`].
///
/// The binary name is the file name without any extensions. It is similar
/// to the unstable `Path::file_stem`.
///
/// ```rust
/// use dnst::extract_binary_name;
/// use std::path::Path;
///
/// let bin = extract_binary_name(Path::new("foo/ldns-xxx")).unwrap();
/// assert_eq!(bin, "ldns-xxx");
///
/// let bin = extract_binary_name(Path::new("foo/ldns-xxx.real")).unwrap();
/// assert_eq!(bin, "ldns-xxx");
///
/// let bin = extract_binary_name(Path::new("./ldns-xxx.exe")).unwrap();
/// assert_eq!(bin, "ldns-xxx");
///
/// let bin = extract_binary_name(Path::new("ldns-xxx")).unwrap();
/// assert_eq!(bin, "ldns-xxx");
/// ```
pub fn extract_binary_name(path: &Path) -> Result<&str, Error> {
let filename = path
.file_name()
.ok_or("Missing binary file name")?
.to_str()
.ok_or("Binary file name is not valid unicode")?;
match filename.split_once('.') {
Some((binary, _)) => Ok(binary),
None => Ok(filename),
}
}
fn parse_args(env: impl Env) -> Result<Args, Error> {
if let Some(args) = try_ldns_compatibility(env.args_os())? {
return Ok(args);
}
let args = Args::try_parse_from(env.args_os())?;
Ok(args)
}
pub fn run(env: impl Env) -> u8 {
let res = parse_args(&env).and_then(|args| args.execute(&env));
match res {
Ok(()) => 0,
Err(err) => {
err.pretty_print(&env);
err.exit_code()
}
}
}