1use crate::pkg::config;
2use anyhow::Result;
3use anyhow::anyhow;
4use clap::{Parser, Subcommand};
5use colored::*;
6use comfy_table::{Table, presets::UTF8_FULL};
7use std::collections::HashSet;
8
9#[derive(Parser)]
10pub struct RepoCommand {
11 #[arg(
12 short = 'y',
13 long,
14 help = "Automatically answer yes to all prompts",
15 global = true
16 )]
17 yes: bool,
18 #[command(subcommand)]
19 command: Commands,
20}
21
22#[derive(Subcommand)]
23enum Commands {
24 #[command(alias = "a")]
26 Add {
27 repo_or_url: Option<String>,
29 },
30 #[command(alias = "rm")]
32 Remove { repo_name: String },
33 #[command(alias = "ls")]
35 List {
36 #[command(subcommand)]
37 which: Option<ListSub>,
38 },
39 #[command(subcommand)]
41 Git(GitCommand),
42}
43
44pub fn run(args: RepoCommand) -> Result<()> {
45 let yes = args.yes;
46 match args.command {
47 Commands::Add { repo_or_url } => {
48 if let Some(val) = repo_or_url {
49 if val.starts_with("http://")
50 || val.starts_with("https://")
51 || val.ends_with(".git")
52 {
53 config::clone_git_repo(&val)?;
54 } else {
55 config::add_repo(&val)?;
56 println!("Repository '{}' added successfully.", val.green());
57 }
58 } else if yes {
59 return Err(anyhow!(
60 "A repository name or URL is required when using --yes."
61 ));
62 } else {
63 config::interactive_add_repo()?;
64 }
65 }
66 Commands::Remove { repo_name } => {
67 config::remove_repo(&repo_name)?;
68 println!("Repository '{}' removed successfully.", repo_name.green());
69 }
70 Commands::List { which } => match which {
71 None => run_list_active()?,
72 Some(ListSub::All) => run_list_all()?,
73 },
74 Commands::Git(cmd) => match cmd {
75 GitCommand::List => run_list_git_only()?,
76 GitCommand::Rm { repo_name } => config::remove_git_repo(&repo_name)?,
77 },
78 }
79 Ok(())
80}
81
82fn run_list_active() -> Result<()> {
83 let config = config::read_config()?;
84 if config.repos.is_empty() {
85 println!("No active repositories.");
86 return Ok(());
87 }
88
89 let mut table = Table::new();
90 table
91 .load_preset(UTF8_FULL)
92 .set_header(vec!["Active Repositories"]);
93 for repo in config.repos {
94 table.add_row(vec![repo]);
95 }
96 println!("{table}");
97 Ok(())
98}
99
100fn run_list_all() -> Result<()> {
101 let active_repos = config::read_config()?
102 .repos
103 .into_iter()
104 .collect::<HashSet<_>>();
105 let all_repos = config::get_all_repos()?;
106
107 let mut table = Table::new();
108 table
109 .load_preset(UTF8_FULL)
110 .set_header(vec!["Status", "Repository"]);
111
112 for repo in all_repos {
113 let status = if active_repos.contains(&repo.to_lowercase()) {
114 "Added"
115 } else {
116 ""
117 };
118 table.add_row(vec![status.to_string(), repo]);
119 }
120 println!("{table}");
121 Ok(())
122}
123
124#[derive(Subcommand)]
125enum ListSub {
126 All,
128}
129
130#[derive(Subcommand)]
131enum GitCommand {
132 #[command(alias = "ls")]
134 List,
135 Rm { repo_name: String },
137}
138
139fn run_list_git_only() -> Result<()> {
140 let repos = config::list_git_repos()?;
141 if repos.is_empty() {
142 println!("No cloned git repositories.");
143 return Ok(());
144 }
145
146 let mut table = Table::new();
147 table
148 .load_preset(UTF8_FULL)
149 .set_header(vec!["Cloned Git Repositories (~/.zoi/pkgs/git)"]);
150 for repo in repos {
151 table.add_row(vec![repo]);
152 }
153 println!("{table}");
154 Ok(())
155}