Skip to content

Commit

Permalink
feat: parse args for an actual working version!
Browse files Browse the repository at this point in the history
Parse command line arguments. gitrc-rs is now actually usable!

TODO: Add support to list repositories, add init option to repositories,
test Keyring auth method, ask for confirmation (unless --force arg is
provided) - maybe also list the last 5 commits? The total number of
commits would also be great, but AFAIK GitHub doesn't really provide a
nice metric for that (like the Gitea X-Total header), so we'd need to
manually query a single commit and count the total pages.
  • Loading branch information
benpueschel committed Jul 5, 2024
1 parent 6520bb2 commit e735c17
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 12 deletions.
137 changes: 136 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ serde_json = "1.0.120"
tokio = { version = "1.38.0", features = ["full", "macros"] }
toml = "0.8.14"
keyring = "2.3.3"
structopt = { version = "0.3.26", features = ["color"] }
115 changes: 104 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,60 @@
use std::error::Error;

use config::{Config, ConfigErrorKind};
use remote::create_remote;
use remote::{create_remote, Remote, RepoCreateInfo};
use structopt::StructOpt;

pub mod config;
pub mod remote;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let remote_name = "gitea".to_string();
#[derive(Debug, Clone, StructOpt)]
#[structopt(name = "gitrc-rs", about = "A tool to manage remote git repositories.")]
pub enum Args {
#[structopt(about = "List repositories on a remote")]
List {
#[structopt(help = "Name of the remote as defined in the config (ex: 'github')")]
remote: String,
},
#[structopt(about = "Create a repository on a remote")]
Create {
#[structopt(short, long, help = "Create a private repository")]
private: bool,
#[structopt(short, long, help = "Initialize the repository with a README.md")]
init: bool,
#[structopt(
short,
long,
help = concat!("License to use for the repository (ex: 'MIT'). ",
"If not provided, or --init is not specified, no license will be addeed.")
)]
license: Option<String>,
#[structopt(help = "Name of the repository")]
name: String,
#[structopt(help = "Name of the remote as defined in the config (ex: 'github')")]
remote: String,
},
#[structopt(about = "Delete a repository on a remote")]
Delete {
#[structopt(help = "Name of the repository")]
name: String,
#[structopt(help = "Name of the remote as defined in the config (ex: 'github')")]
remote: String,
},
#[structopt(about = "Authenticate with a remote")]
Auth {
#[structopt(help = "Name of the remote as defined in the config (ex: 'github')")]
remote: String,
#[structopt(help = concat!("Username (or token) to authenticate with.",
"If using basic HTTP auth, provide the username. Otherwise, provide a token."))]
username_or_token: String,
#[structopt(help = "Password to authenticate with if using basic HTTP auth.")]
password: Option<String>,
},
}

let config = match Config::load_from_file(None) {
Ok(config) => config,
fn load_config() -> Result<Config, Box<dyn Error>> {
match Config::load_from_file(None) {
Ok(config) => Ok(config),
Err(err) => match err.kind {
ConfigErrorKind::ConfigNotFound => {
eprintln!("{}", err.message);
Expand All @@ -24,14 +67,64 @@ async fn main() -> Result<(), Box<dyn Error>> {
std::process::exit(1);
}
},
};
}
}

let provider = config.get_remote_provider(&remote_name)?;
let remote_config = config.get_remote_config(&remote_name)?;
async fn load_remote(remote_name: &str) -> Result<Box<dyn Remote>, Box<dyn Error>> {
let config = load_config()?;
let provider = config.get_remote_provider(remote_name)?;
let remote_config = config.get_remote_config(remote_name)?;
Ok(create_remote(&remote_config, provider).await)
}

let _remote = create_remote(&remote_config, provider).await;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Parse command line arguments
let command = Args::from_args();

// TODO: parse args and call appropriate function
match command {
Args::List { remote: _ } => {
println!("Listing repositories...");
todo!()
}
Args::Create {
private,
init: _,
license: _,
name,
remote,
} => {
println!("Creating repository '{name}'...");
let remote = load_remote(&remote).await?;
let info = RepoCreateInfo {
name,
description: None,
private,
};
let url = remote.create_repo(info).await?;
println!("Repository created at: {}", url);
}
Args::Delete { name, remote: remote_name } => {
println!("Deleting repository '{name}'...");
let remote = load_remote(&remote_name).await?;
remote.delete_repo(&name).await?;
println!("Repository '{name}' deleted on remote '{remote_name}'.");
}
Args::Auth {
remote,
username_or_token,
password,
} => {
println!("Adding authentication to remote '{remote}'...");
let mut config = load_config()?;
if password.is_some() {
todo!("Basic HTTP auth is not yet supported.");
}
config.store_token(&remote, &username_or_token)?;
config.save()?;
println!("Authentication added to remote '{remote}'.");
}
}

Ok(())
}

0 comments on commit e735c17

Please sign in to comment.