ngs 0.4.0

Command line tool for processing next-generation sequencing data.
Documentation
#![warn(rust_2018_idioms)]
#![warn(rust_2021_compatibility)]

use clap::Parser;
use clap::Subcommand;

use git_testament::git_testament;
use git_testament::render_testament;

use ngs::convert;
use ngs::derive;
use ngs::generate;
use ngs::index;
use ngs::list;
use ngs::plot;
use ngs::qc;
use ngs::view;

#[derive(Parser)]
#[command(author, version = render_testament!(TESTAMENT), propagate_version = true, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    pub subcommand: Subcommands,

    /// Only errors are printed to the stderr stream.
    #[arg(short, long, global = true)]
    pub quiet: bool,

    /// All available information, including debug information, is printed to stderr.
    #[arg(short, long, global = true)]
    pub verbose: bool,
}

#[derive(Subcommand)]
#[allow(clippy::large_enum_variant)]
enum Subcommands {
    /// Convert between next-generation sequencing formats.
    Convert(convert::command::ConvertArgs),

    /// Forensic analysis tool for next-generation sequencing data.
    Derive(derive::command::DeriveArgs),

    /// Generates a BAM file from a given reference genome.
    Generate(generate::command::GenerateArgs),

    /// Generates the index file to various next-generation sequencing files.
    Index(index::command::IndexArgs),

    /// Utility to list various supported items in this command line tool.
    List(list::command::ListArgs),

    /// Produces plots for data generated by `ngs qc`.
    Plot(plot::command::PlotArgs),

    /// Generates quality control metrics for BAM files.
    Qc(qc::command::QcArgs),

    /// Views various next-generation sequencing files, sometimes with a query region.
    View(view::command::ViewArgs),
}

git_testament!(TESTAMENT);

fn main() -> anyhow::Result<()> {
    let cli = Cli::parse();

    //===========//
    // Verbosity //
    //===========//

    let level = if cli.verbose {
        tracing::Level::DEBUG
    } else if cli.quiet {
        tracing::Level::ERROR
    } else {
        tracing::Level::INFO
    };

    let subscriber = tracing_subscriber::fmt::Subscriber::builder()
        .with_max_level(level)
        .with_writer(std::io::stderr)
        .finish();
    tracing::subscriber::set_global_default(subscriber)?;

    //=====================//
    // Subcommand matching //
    //=====================//

    match cli.subcommand {
        Subcommands::Convert(args) => convert::command::convert(args)?,
        Subcommands::Derive(args) => match args.subcommand {
            derive::command::DeriveSubcommand::Instrument(args) => {
                derive::command::instrument::derive(args)?
            }
        },
        Subcommands::Generate(args) => generate::command::generate(args)?,
        Subcommands::Index(args) => index::command::index(args)?,
        Subcommands::List(args) => list::command::list(args)?,
        Subcommands::Plot(args) => match args.subcommand {
            plot::command::PlotSubcommand::Cohort(args) => plot::cohort::plot(args)?,
            plot::command::PlotSubcommand::Sample(args) => plot::sample::plot(args)?,
        },
        Subcommands::Qc(args) => qc::command::qc(args)?,
        Subcommands::View(args) => view::command::view(args)?,
    };

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn verify_cli() {
        use clap::CommandFactory;
        Cli::command().debug_assert()
    }
}