use std::collections::HashSet;
use anyhow::{Result, anyhow};
use clap::{Parser, Subcommand};
use colored::Colorize;
use comfy_table::Table;
use comfy_table::presets::UTF8_FULL;
use crate::pkg::config;
#[derive(Parser)]
pub struct RepoCommand {
#[arg(
short = 'y',
long,
help = "Automatically answer yes to all prompts",
global = true
)]
yes: bool,
#[command(subcommand)]
command: Commands
}
#[derive(Subcommand)]
enum Commands {
#[command(alias = "a")]
Add {
repo_or_url: Option<String>
},
#[command(alias = "rm")]
Remove {
repo_name: String
},
#[command(alias = "ls")]
List {
#[command(subcommand)]
which: Option<ListSub>
},
#[command(subcommand)]
Git(GitCommand)
}
pub fn run(args: RepoCommand) -> Result<()> {
let yes = args.yes;
match args.command {
Commands::Add { repo_or_url } => {
if let Some(val) = repo_or_url {
if val.starts_with("http://")
|| val.starts_with("https://")
|| std::path::Path::new(&val)
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("git"))
{
config::clone_git_repo(&val)?;
} else {
config::add_repo(&val)?;
println!(
"Repository '{}' added successfully.",
val.green()
);
}
} else if yes {
return Err(anyhow!(
"A repository name or URL is required when using --yes."
));
} else {
config::interactive_add_repo()?;
}
}
Commands::Remove { repo_name } => {
config::remove_repo(&repo_name)?;
println!(
"Repository '{}' removed successfully.",
repo_name.green()
);
}
Commands::List { which } => match which {
None => run_list_active()?,
Some(ListSub::All) => run_list_all()?
},
Commands::Git(cmd) => match cmd {
GitCommand::List => run_list_git_only()?,
GitCommand::Rm { repo_name } => {
config::remove_git_repo(&repo_name)?;
}
}
}
Ok(())
}
fn run_list_active() -> Result<()> {
let config = config::read_config()?;
if config.repos.is_empty() {
println!("No active repositories.");
return Ok(());
}
println!("{} Active repositories:", "::".bold().blue());
let mut table = Table::new();
table.load_style(UTF8_FULL).set_header(vec!["Repository"]);
for repo in config.repos {
table.add_row(vec![repo]);
}
println!("{table}");
Ok(())
}
fn run_list_all() -> Result<()> {
let active_repos = config::read_config()?
.repos
.into_iter()
.collect::<HashSet<_>>();
let all_repos = config::get_all_repos()?;
println!("{} All available repositories:", "::".bold().blue());
let mut table = Table::new();
table
.load_style(UTF8_FULL)
.set_header(vec!["Status", "Repository"]);
for repo in all_repos {
let status = if active_repos.contains(&repo.to_lowercase()) {
"Added"
} else {
""
};
table.add_row(vec![status.to_string(), repo]);
}
println!("{table}");
Ok(())
}
#[derive(Subcommand)]
enum ListSub {
All
}
#[derive(Subcommand)]
enum GitCommand {
#[command(alias = "ls")]
List,
Rm {
repo_name: String
}
}
fn run_list_git_only() -> Result<()> {
let repos = config::list_git_repos()?;
if repos.is_empty() {
println!("No cloned git repositories.");
return Ok(());
}
println!(
"{} Cloned git repositories (~/.zoi/pkgs/git):",
"::".bold().blue()
);
let mut table = Table::new();
table.load_style(UTF8_FULL).set_header(vec!["Repository"]);
for repo in repos {
table.add_row(vec![repo]);
}
println!("{table}");
Ok(())
}