bookyard 0.1.1

Build and locally edit a bookshelf for multiple mdBook projects.
use std::path::PathBuf;

use clap::{Parser, Subcommand};

#[derive(Debug, Parser)]
#[command(
    name = "bookyard",
    version,
    about = "Build and edit a local bookshelf for multiple mdBook projects."
)]
pub struct Cli {
    #[command(subcommand)]
    command: Command,
}

#[derive(Debug, Subcommand)]
pub enum Command {
    #[command(about = "Create a bookyard.toml shelf config in the current directory.")]
    Init {
        #[arg(long, default_value = "Bookyard", help = "Shelf title written to bookyard.toml.")]
        title: String,
        #[arg(long, help = "Replace an existing bookyard.toml.")]
        force: bool,
    },
    #[command(about = "Add an existing mdBook to the shelf.")]
    Add {
        #[arg(help = "Path to an existing mdBook directory.")]
        source: PathBuf,
        #[arg(long, help = "Logical folder path inside the shelf.")]
        folder: String,
        #[arg(long, help = "Book title stored in the shelf config.")]
        title: Option<String>,
        #[arg(long, help = "Stable book id used in generated URLs.")]
        id: Option<String>,
        #[arg(long = "tag", help = "Tag to attach to the book; repeat for multiple tags.")]
        tags: Vec<String>,
    },
    #[command(about = "Create a new mdBook and add it to the shelf.")]
    New {
        #[arg(help = "Path where the new mdBook will be created.")]
        source: PathBuf,
        #[arg(long, help = "Logical folder path inside the shelf.")]
        folder: String,
        #[arg(long, help = "Book title for book.toml and the shelf config.")]
        title: Option<String>,
        #[arg(long, help = "Stable book id used in generated URLs.")]
        id: Option<String>,
        #[arg(long = "tag", help = "Tag to attach to the book; repeat for multiple tags.")]
        tags: Vec<String>,
        #[arg(long, help = "Replace generated files if they already exist.")]
        force: bool,
    },
    #[command(about = "Build the bookshelf site.")]
    Build {
        #[arg(long, hide = true, help = "Skip mdBook builds and only render the shelf.")]
        no_mdbook: bool,
    },
    #[command(about = "Serve the generated shelf, optionally with the local editor.")]
    Serve {
        #[arg(long, default_value = "127.0.0.1", help = "Host interface to bind.")]
        host: String,
        #[arg(long, default_value_t = 3000, help = "Port to listen on.")]
        port: u16,
        #[arg(long, help = "Enable the local config editor at /__bookyard/edit.")]
        edit: bool,
    },
    #[command(about = "Check the local Bookyard configuration.")]
    Doctor,
}

pub async fn run() -> anyhow::Result<()> {
    match Cli::parse().command {
        Command::Init { title, force } => crate::commands::init::run(&title, force),
        Command::Add {
            source,
            folder,
            title,
            id,
            tags,
        } => crate::commands::add::run(source, folder, title, id, tags),
        Command::New {
            source,
            folder,
            title,
            id,
            tags,
            force,
        } => crate::commands::new::run(source, folder, title, id, tags, force),
        Command::Build { no_mdbook } => crate::commands::build::run(no_mdbook),
        Command::Serve { host, port, edit } => crate::commands::serve::run(host, port, edit).await,
        Command::Doctor => crate::commands::doctor::run(),
    }
}