refactor(cli): clean up code
cleared out main moved subcommand handling to a method on each arg struct moved from many, many expects to returning errors
This commit is contained in:
+100
-1
@@ -1,5 +1,11 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
|
||||
use crate::config;
|
||||
use crate::config::Profile;
|
||||
use crate::git;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(version, about = "a cli to change git users")]
|
||||
pub struct Cli {
|
||||
@@ -9,13 +15,47 @@ pub struct Cli {
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum Commands {
|
||||
List,
|
||||
List(ListArgs),
|
||||
Use(UseArgs),
|
||||
Add(AddArgs),
|
||||
Remove(RemoveArgs),
|
||||
Current(CurrentArgs),
|
||||
}
|
||||
|
||||
impl Commands {
|
||||
pub fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
match self {
|
||||
Commands::List(args) => args.execute(),
|
||||
Commands::Use(args) => args.execute(),
|
||||
Commands::Add(args) => args.execute(),
|
||||
Commands::Remove(args) => args.execute(),
|
||||
Commands::Current(args) => args.execute(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ListArgs;
|
||||
|
||||
impl ListArgs {
|
||||
fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
let profiles = config::get_profile_list()?;
|
||||
if profiles.is_empty() {
|
||||
println!("no profiles found");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("{:<15} {:<20} {:<25}", "profile", "name", "email");
|
||||
for profile in profiles {
|
||||
println!(
|
||||
"{:<15} {:<20} {:<25}",
|
||||
profile.name, profile.username, profile.email
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct UseArgs {
|
||||
pub profile_name: String,
|
||||
@@ -23,6 +63,23 @@ pub struct UseArgs {
|
||||
pub global: bool,
|
||||
}
|
||||
|
||||
impl UseArgs {
|
||||
fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
let profiles = config::get_profile_list()?;
|
||||
let profile = profiles.iter().find(|p| p.name == self.profile_name);
|
||||
if profile.is_none() {
|
||||
println!("profile not found");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let profile = profile.unwrap();
|
||||
|
||||
git::set_git_config("user.name", &profile.username, self.global)?;
|
||||
git::set_git_config("user.email", &profile.email, self.global)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct AddArgs {
|
||||
pub profile_name: String,
|
||||
@@ -32,13 +89,55 @@ pub struct AddArgs {
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
impl AddArgs {
|
||||
fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
let mut profiles = config::get_profile_list()?;
|
||||
let existing_profile = profiles.iter().position(|p| p.name == self.profile_name);
|
||||
if existing_profile.is_some() {
|
||||
println!("profile already exists");
|
||||
return Ok(());
|
||||
}
|
||||
profiles.push(Profile {
|
||||
name: self.profile_name,
|
||||
username: self.name,
|
||||
email: self.email,
|
||||
});
|
||||
config::write_profile_list(profiles)?;
|
||||
println!("profile added");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct RemoveArgs {
|
||||
pub profile_name: String,
|
||||
}
|
||||
|
||||
impl RemoveArgs {
|
||||
fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
let mut profiles = config::get_profile_list()?;
|
||||
let index = profiles
|
||||
.iter()
|
||||
.position(|p| p.name == self.profile_name)
|
||||
.expect("unable to find profile");
|
||||
profiles.remove(index);
|
||||
config::write_profile_list(profiles)?;
|
||||
println!("profile removed");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct CurrentArgs {
|
||||
#[arg(short, long)]
|
||||
pub global: bool,
|
||||
}
|
||||
|
||||
impl CurrentArgs {
|
||||
fn execute(self) -> Result<(), Box<dyn Error>> {
|
||||
let name = git::get_git_config("user.name", self.global)?;
|
||||
let email = git::get_git_config("user.email", self.global)?;
|
||||
println!("current user: {} ({})", name, email);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+28
-30
@@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::{self, File},
|
||||
io::{BufReader, BufWriter, Error},
|
||||
io::{BufReader, BufWriter},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
@@ -13,39 +14,36 @@ pub struct Profile {
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
fn get_config_dir() -> PathBuf {
|
||||
let mut config_dir = dirs::config_dir().expect("unable to find config dir");
|
||||
fn get_config_dir() -> Result<PathBuf, Box<dyn Error>> {
|
||||
let mut config_dir = dirs::config_dir().ok_or("unable to get config dir")?;
|
||||
config_dir.push("git-su");
|
||||
config_dir
|
||||
Ok(config_dir)
|
||||
}
|
||||
|
||||
fn create_if_missing(file: &Path, content: &str) -> Result<(), Error> {
|
||||
fn create_if_missing(file: &Path, content: &str) -> Result<(), Box<dyn Error + 'static>> {
|
||||
if !file.exists() {
|
||||
fs::write(file, content)
|
||||
} else {
|
||||
Ok(())
|
||||
fs::write(file, content)?;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_profile_list() -> Result<Vec<Profile>, String> {
|
||||
let config_dir = get_config_dir();
|
||||
fs::create_dir_all(&config_dir).expect("unable to create config directory");
|
||||
let profile_file = config_dir.join("profiles.json");
|
||||
create_if_missing(profile_file.as_path(), "[]").expect("unable to create profile file");
|
||||
let profile_file = File::open(&profile_file).expect("unable to open profile file");
|
||||
let reader = BufReader::new(profile_file);
|
||||
Ok(
|
||||
serde_json::from_reader::<BufReader<File>, Vec<Profile>>(reader)
|
||||
.expect("unable to parse json"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn write_profile_list(profiles: Vec<Profile>) -> Result<(), String> {
|
||||
let config_dir = get_config_dir();
|
||||
fs::create_dir_all(&config_dir).expect("unable to create config directory");
|
||||
let profile_file = config_dir.join("profiles.json");
|
||||
let profile_file = File::create(&profile_file).expect("unable to create profile file");
|
||||
let writer = BufWriter::new(profile_file);
|
||||
serde_json::to_writer_pretty(writer, &profiles).expect("unable to write json");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_profile_list() -> Result<Vec<Profile>, Box<dyn Error>> {
|
||||
let config_dir = get_config_dir()?;
|
||||
fs::create_dir_all(&config_dir)?;
|
||||
let profile_file = config_dir.join("profiles.json");
|
||||
create_if_missing(profile_file.as_path(), "[]")?;
|
||||
let profile_file = File::open(&profile_file)?;
|
||||
let reader = BufReader::new(profile_file);
|
||||
let profiles = serde_json::from_reader::<BufReader<File>, Vec<Profile>>(reader)?;
|
||||
Ok(profiles)
|
||||
}
|
||||
|
||||
pub fn write_profile_list(profiles: Vec<Profile>) -> Result<(), Box<dyn Error>> {
|
||||
let config_dir = get_config_dir()?;
|
||||
fs::create_dir_all(&config_dir)?;
|
||||
let profile_file = config_dir.join("profiles.json");
|
||||
let profile_file = File::create(&profile_file)?;
|
||||
let writer = BufWriter::new(profile_file);
|
||||
serde_json::to_writer_pretty(writer, &profiles)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
use std::{error::Error, process::Command};
|
||||
|
||||
pub fn get_git_config(key: &str, global: bool) -> Result<String, Box<dyn Error>> {
|
||||
let args = if global {
|
||||
vec!["config", "--global", key]
|
||||
} else {
|
||||
vec!["config", key]
|
||||
};
|
||||
|
||||
let result = run_command("git", &args)?;
|
||||
Ok(result.trim().to_string())
|
||||
}
|
||||
|
||||
pub fn set_git_config(key: &str, value: &str, global: bool) -> Result<(), Box<dyn Error>> {
|
||||
let args = if global {
|
||||
vec!["config", "--global", key, value]
|
||||
} else {
|
||||
vec!["config", key, value]
|
||||
};
|
||||
|
||||
let _ = run_command("git", &args)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_command(command: &str, args: &[&str]) -> Result<String, Box<dyn Error>> {
|
||||
let child = Command::new(command).args(args).output()?;
|
||||
|
||||
if child.status.success() {
|
||||
let stdout = String::from_utf8(child.stdout)?;
|
||||
Ok(stdout.to_owned())
|
||||
} else {
|
||||
let stderr = String::from_utf8(child.stderr)?;
|
||||
Ok(stderr.to_owned())
|
||||
}
|
||||
}
|
||||
+4
-89
@@ -1,99 +1,14 @@
|
||||
use clap::Parser;
|
||||
|
||||
use crate::cli::Commands;
|
||||
use crate::config::Profile;
|
||||
|
||||
mod cli;
|
||||
mod config;
|
||||
mod utils;
|
||||
mod git;
|
||||
|
||||
fn main() {
|
||||
let args = cli::Cli::parse();
|
||||
|
||||
match args.command {
|
||||
Commands::List => {
|
||||
let profiles = config::get_profile_list().expect("unable to get list of profiles");
|
||||
if profiles.is_empty() {
|
||||
println!("no profiles found");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("{:<15} {:<20} {:<25}", "profile", "name", "email");
|
||||
for profile in profiles {
|
||||
println!(
|
||||
"{:<15} {:<20} {:<25}",
|
||||
profile.name, profile.username, profile.email
|
||||
);
|
||||
}
|
||||
}
|
||||
Commands::Use(args) => {
|
||||
let profiles = config::get_profile_list().expect("unable to get list of profiles");
|
||||
let profile = profiles.iter().find(|p| p.name == args.profile_name);
|
||||
if profile.is_none() {
|
||||
println!("profile not found");
|
||||
return;
|
||||
}
|
||||
|
||||
let profile = profile.unwrap();
|
||||
|
||||
utils::run_command(
|
||||
"git",
|
||||
&add_global_if(&["config", "user.name", &profile.username], args.global),
|
||||
)
|
||||
.expect("command failed");
|
||||
utils::run_command(
|
||||
"git",
|
||||
&add_global_if(&["config", "user.email", &profile.email], args.global),
|
||||
)
|
||||
.expect("command failed");
|
||||
}
|
||||
Commands::Add(args) => {
|
||||
let mut profiles = config::get_profile_list().expect("unable to get list of profiles");
|
||||
let existing_profile = profiles.iter().position(|p| p.name == args.profile_name);
|
||||
if existing_profile.is_some() {
|
||||
println!("profile already exists");
|
||||
return;
|
||||
}
|
||||
profiles.push(Profile {
|
||||
name: args.profile_name,
|
||||
username: args.name,
|
||||
email: args.email,
|
||||
});
|
||||
config::write_profile_list(profiles).expect("unable to write profile file");
|
||||
println!("profile added")
|
||||
}
|
||||
Commands::Remove(args) => {
|
||||
let mut profiles = config::get_profile_list().expect("unable to get list of profiles");
|
||||
let index = profiles
|
||||
.iter()
|
||||
.position(|p| p.name == args.profile_name)
|
||||
.expect("unable to find profile");
|
||||
profiles.remove(index);
|
||||
config::write_profile_list(profiles).expect("unable to write profile file");
|
||||
println!("profile removed")
|
||||
}
|
||||
Commands::Current(args) => {
|
||||
let mut name =
|
||||
utils::run_command("git", &add_global_if(&["config", "user.name"], args.global))
|
||||
.expect("command failed");
|
||||
let mut email = utils::run_command(
|
||||
"git",
|
||||
&add_global_if(&["config", "user.email"], args.global),
|
||||
)
|
||||
.expect("command failed");
|
||||
|
||||
name.pop();
|
||||
email.pop();
|
||||
|
||||
println!("current user: {} ({})", name, email);
|
||||
}
|
||||
if let Err(why) = args.command.execute() {
|
||||
eprintln!("error: {}", why);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_global_if<'a>(args: &[&'a str], global: bool) -> Vec<&'a str> {
|
||||
let mut result = args.to_vec();
|
||||
if global {
|
||||
result.insert(1, "--global");
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use std::process::Command;
|
||||
|
||||
pub fn run_command(command: &str, args: &[&str]) -> Result<String, String> {
|
||||
let child = Command::new(command)
|
||||
.args(args)
|
||||
.output()
|
||||
.expect("failed to execute process");
|
||||
|
||||
if child.status.success() {
|
||||
let stdout = String::from_utf8(child.stdout).unwrap();
|
||||
Ok(stdout.to_owned())
|
||||
} else {
|
||||
let stderr = String::from_utf8(child.stderr).unwrap();
|
||||
Err(stderr)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user