shellock-homes 0.1.0

opinonated dotfile manager
Documentation
use std::path::PathBuf;

use clap::{Args, Parser, Subcommand};
use shellock_homes::{Backend, ConfigWithBackend};
use shellock_homes::{Config, FileSystemBackend};

use log::debug;
use log::error;
use log::info;

#[derive(Debug, Parser)]
#[clap(name = "shellock-homes")]
#[clap(version)]
#[clap(about = "Manage dotfiles like a pro")]
struct Cli {
    #[clap(subcommand)]
    command: Commands,
}

#[derive(Debug, Subcommand)]
enum Commands {
    Monitor,
    Init(Init),
    List,
    #[clap(arg_required_else_help = true)]
    Sync(Sync),
    #[clap(arg_required_else_help = true)]
    Add {
        #[clap(required = true)]
        path: Vec<PathBuf>,
    },
    #[clap(arg_required_else_help = true)]
    Remove {
        #[clap(required = true)]
        path: Vec<PathBuf>,
    },
}

#[derive(Args, Debug)]
struct Init {
    #[clap(long, possible_values = ["git", "file-system"])]
    backend: String,
    #[clap(long)]
    remote: Option<String>,
    #[clap(long)]
    branch: Option<String>,
    #[clap(long)]
    dir_name: Option<String>,
    #[clap(long)]
    auto_commit: bool,
    #[clap(long)]
    auto_push: bool,
}

#[derive(Args, Debug)]
struct Sync {
    #[clap(long, conflicts_with = "to-home")]
    from_home: bool,
    #[clap(long)]
    to_home: bool,
}

fn main() {
    env_logger::init();
    let args = Cli::parse();

    match args.command {
        Commands::Monitor => {
            info!("Starting monitor.")
        }
        Commands::Init(init) => {
            let config: Box<dyn ConfigWithBackend> = match init.backend.as_str() {
                //"git" => Box::new(Config::<GitBackend>::default()),
                "git" => {
                    error!("Git backend is not yet implemented");
                    return;
                }
                "file-system" => Box::new(Config::<FileSystemBackend>::default()),
                _ => {
                    // clap should ensure this branch is never hit
                    error!("Unknown backend: {}", init.backend);
                    return;
                }
            };
            match config.init() {
                Err(e) => {
                    error!("Could not init: {}", e);
                    return;
                }
                _ => {
                    debug!("config initialized");
                }
            };
        }
        Commands::Sync(direction) => {
            let config = get_config();
            info!("direction: {:?}", direction);
            let d = if direction.from_home {
                shellock_homes::Direction::FromHome
            } else {
                shellock_homes::Direction::FromRepo
            };
            match config
                .backend
                .sync(d, config.sync.files, config.sync.ignore)
            {
                Err(e) => error!("failed to sync: {e}"),
                _ => {}
            }
        }
        Commands::Add { path } => match get_config().add_path(path) {
            Err(e) => error!("failed to add path: {e}"),
            _ => {}
        },
        Commands::Remove { path } => match get_config().remove_path(path) {
            Err(e) => error!("failed to remove path: {e}"),
            _ => {}
        },
        Commands::List => {
            for entry in get_config().backend.list() {
                println!("{}", entry.into_os_string().into_string().unwrap());
            }
        }
    }
}

fn get_config() -> Config<FileSystemBackend> {
    let mut config = Config::<FileSystemBackend>::default();
    match config.load() {
        Err(e) => {
            panic!("could not load config file: {}", e);
        }
        _ => {}
    }
    config
}