use clap::{Parser, Subcommand, ValueEnum};
#[derive(Debug, Parser)]
#[command(name = "git-multi")]
#[command(author = "CharaD7")]
#[command(version = "0.1.0")]
#[command(about = "A CLI tool for managing multiple Git remotes", long_about = None)]
pub struct Cli {
#[arg(short, long, action = clap::ArgAction::Count)]
pub verbose: u8,
#[arg(short, long)]
pub gui: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
Init,
Remote {
#[command(subcommand)]
command: RemoteCommands,
},
Branch {
#[command(subcommand)]
command: BranchCommands,
},
Fetch {
#[arg(short, long)]
all: bool,
#[arg(value_name = "REMOTE")]
remote: Option<String>,
},
Pull {
#[arg(short, long)]
all: bool,
#[arg(value_name = "REMOTE")]
remote: Option<String>,
#[arg(short, long, value_name = "BRANCH")]
branch: Option<String>,
},
Push {
#[arg(short, long)]
all: bool,
#[arg(value_name = "REMOTE")]
remote: Option<String>,
#[arg(short, long, value_name = "BRANCH")]
branch: Option<String>,
#[arg(short, long)]
force: bool,
},
Checkout {
#[arg(value_name = "BRANCH")]
branch: String,
#[arg(short, long, value_name = "REMOTE")]
remote: Option<String>,
#[arg(short, long)]
new: bool,
},
Sync {
#[arg(value_name = "FROM_REMOTE")]
from_remote: String,
#[arg(value_name = "TO_REMOTE")]
to_remote: String,
#[arg(short, long, value_name = "BRANCH", default_value = "main")]
from_branch: String,
#[arg(short, long, value_name = "BRANCH", default_value = "main")]
to_branch: String,
#[arg(short, long, value_name = "RANGE", default_value = "HEAD")]
commits: String,
#[arg(short, long, value_enum, default_value = "cherry-pick")]
strategy: SyncStrategy,
#[arg(short, long)]
force: bool,
},
Copy {
#[arg(value_name = "FROM")]
from: String,
#[arg(value_name = "TO")]
to: String,
#[arg(value_name = "FILES", num_args = 1..)]
files: Vec<String>,
#[arg(short, long)]
prune: bool,
},
Pr {
#[arg(value_name = "REMOTE")]
remote: String,
#[arg(short, long, value_name = "BRANCH", default_value = "main")]
base: String,
#[arg(short, long, value_name = "BRANCH")]
head: Option<String>,
#[arg(short, long, value_name = "TITLE")]
title: String,
#[arg(short, long, value_name = "DESCRIPTION")]
description: Option<String>,
#[arg(short, long)]
open: bool,
},
Use {
#[arg(value_name = "REMOTE")]
remote: String,
},
Status,
List,
}
#[derive(Debug, Subcommand)]
pub enum RemoteCommands {
Add {
#[arg(value_name = "NAME")]
name: String,
#[arg(value_name = "URL")]
url: String,
#[arg(short, long)]
default: bool,
},
Remove {
#[arg(value_name = "NAME")]
name: String,
#[arg(short, long)]
force: bool,
},
List {
#[arg(short, long)]
urls: bool,
},
Rename {
#[arg(value_name = "OLD_NAME")]
old_name: String,
#[arg(value_name = "NEW_NAME")]
new_name: String,
},
Show {
#[arg(value_name = "NAME")]
name: String,
},
ListNames {},
SetDefault {
#[arg(value_name = "NAME")]
name: String,
},
SetPrimary {
#[arg(value_name = "NAME")]
name: String,
},
}
#[derive(Debug, Subcommand)]
pub enum BranchCommands {
List {
#[arg(short, long)]
all: bool,
#[arg(short, long, value_name = "REMOTE")]
remote: Option<String>,
},
Delete {
#[arg(value_name = "BRANCH")]
branch: String,
#[arg(short, long)]
force: bool,
#[arg(short, long)]
remote: bool,
},
Create {
#[arg(value_name = "BRANCH")]
branch: String,
#[arg(short, long, value_name = "BASE", default_value = "main")]
base: String,
#[arg(short, long, value_name = "REMOTES", num_args = 1..)]
remotes: Option<Vec<String>>,
#[arg(short, long)]
checkout: bool,
},
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
pub enum SyncStrategy {
#[default]
CherryPick,
Merge,
Rebase,
}
impl std::fmt::Display for SyncStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SyncStrategy::CherryPick => write!(f, "cherry-pick"),
SyncStrategy::Merge => write!(f, "merge"),
SyncStrategy::Rebase => write!(f, "rebase"),
}
}
}
impl std::str::FromStr for SyncStrategy {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"cherry-pick" | "cherrypick" | "pick" => Ok(SyncStrategy::CherryPick),
"merge" => Ok(SyncStrategy::Merge),
"rebase" => Ok(SyncStrategy::Rebase),
_ => Err(format!("Unknown strategy: {}", s)),
}
}
}