Merge pull request 'improve organization' (#2) from organize into main

Reviewed-on: https://codeberg.org/Cyborus/forgejo-cli/pulls/2
This commit is contained in:
Cyborus 2023-11-17 19:21:56 +00:00
commit 1a7f0de260
3 changed files with 167 additions and 145 deletions

59
src/auth.rs Normal file
View file

@ -0,0 +1,59 @@
use clap::Subcommand;
#[derive(Subcommand, Clone, Debug)]
pub enum AuthCommand {
Login,
Logout {
host: String,
},
AddKey {
/// The domain name of the forgejo instance.
host: String,
/// The user that the key is associated with
user: String,
/// The key to add. If not present, the key will be read in from stdin.
key: Option<String>,
},
List,
}
impl AuthCommand {
pub async fn run(self, keys: &mut crate::KeyInfo) -> eyre::Result<()> {
match self {
AuthCommand::Login => {
todo!();
// let user = readline("username: ").await?;
// let pass = readline("password: ").await?;
}
AuthCommand::Logout { host } => {
let info_opt = keys.hosts.remove(&host);
if let Some(info) = info_opt {
eprintln!("signed out of {}@{}", &info.username(), host);
} else {
eprintln!("already not signed in to {host}");
}
}
AuthCommand::AddKey { host, user, key } => {
let key = match key {
Some(key) => key,
None => crate::readline("new key: ").await?,
};
if keys.hosts.get(&user).is_none() {
keys.hosts.insert(host, crate::keys::LoginInfo::new(user, key));
} else {
println!("key for {} already exists", host);
}
}
AuthCommand::List => {
if keys.hosts.is_empty() {
println!("No logins.");
}
for (host_url, login_info) in &keys.hosts {
println!("{}@{}", login_info.username(), host_url);
}
}
}
Ok(())
}
}

View file

@ -9,6 +9,9 @@ use url::Url;
mod keys;
use keys::*;
mod repo;
mod auth;
#[derive(Parser, Debug)]
pub struct App {
#[clap(subcommand)]
@ -18,53 +21,13 @@ pub struct App {
#[derive(Subcommand, Clone, Debug)]
pub enum Command {
#[clap(subcommand)]
Repo(RepoCommand),
Repo(repo::RepoCommand),
User {
#[clap(long, short)]
host: Option<String>,
},
#[clap(subcommand)]
Auth(AuthCommand),
}
#[derive(Subcommand, Clone, Debug)]
pub enum RepoCommand {
Create {
host: String,
repo: String,
// flags
#[clap(long, short)]
description: Option<String>,
#[clap(long, short)]
private: bool,
/// Sets the new repo to be the `origin` remote of the current local repo.
#[clap(long, short)]
set_upstream: Option<String>,
/// Pushes the current branch to the default branch on the new repo.
/// Implies `--set-upstream=origin` (setting upstream manual overrides this)
#[clap(long, short)]
push: bool,
},
Info,
Browse,
}
#[derive(Subcommand, Clone, Debug)]
pub enum AuthCommand {
Login,
Logout {
host: String,
},
AddKey {
/// The domain name of the forgejo instance.
host: String,
/// The user that the key is associated with
user: String,
/// The key to add. If not present, the key will be read in from stdin.
key: Option<String>,
},
List,
Auth(auth::AuthCommand),
}
#[tokio::main]
@ -73,75 +36,7 @@ async fn main() -> eyre::Result<()> {
let mut keys = KeyInfo::load().await?;
match args.command {
Command::Repo(repo_subcommand) => match repo_subcommand {
RepoCommand::Create {
host,
repo,
description,
private,
set_upstream,
push,
} => {
let host = Url::parse(&host)?;
let login = keys.get_login(&host)?;
let api = login.api_for(&host)?;
let repo_spec = CreateRepoOption {
auto_init: false,
default_branch: "main".into(),
description,
gitignores: String::new(),
issue_labels: String::new(),
license: String::new(),
name: repo.clone(),
private,
readme: String::new(),
template: false,
trust_model: forgejo_api::TrustModel::Default,
};
let new_repo = api.create_repo(repo_spec).await?;
eprintln!(
"created new repo at {}",
host.join(&format!("{}/{}", login.username(), repo))?
);
let upstream = set_upstream.as_deref().unwrap_or("origin");
let repo = git2::Repository::open(".")?;
let mut remote = if set_upstream.is_some() || push {
repo.remote(upstream, new_repo.clone_url.as_str())?
} else {
repo.find_remote(upstream)?
};
if push {
remote.push::<&str>(&[], None)?;
}
}
RepoCommand::Info => {
let (host, repo) = keys.get_current()?;
let api = host.api()?;
let repo = api.get_repo(repo.owner(), repo.name()).await?;
match repo {
Some(repo) => {
dbg!(repo);
}
None => eprintln!("repo not found"),
}
}
RepoCommand::Browse => {
let (host, repo) = keys.get_current()?;
let mut url = host.url().clone();
let new_path = format!(
"{}/{}/{}",
url.path().strip_suffix("/").unwrap_or(url.path()),
repo.owner(),
repo.name(),
);
url.set_path(&new_path);
open::that(url.as_str())?;
}
},
Command::Repo(repo_subcommand) => repo_subcommand.run(&keys).await?,
Command::User { host } => {
let host = host.map(|host| Url::parse(&host)).transpose()?;
let (url, name) = match host {
@ -153,40 +48,7 @@ async fn main() -> eyre::Result<()> {
};
eprintln!("currently signed in to {name}@{url}");
}
Command::Auth(auth_subcommand) => match auth_subcommand {
AuthCommand::Login => {
todo!();
// let user = readline("username: ").await?;
// let pass = readline("password: ").await?;
}
AuthCommand::Logout { host } => {
let info_opt = keys.hosts.remove(&host);
if let Some(info) = info_opt {
eprintln!("signed out of {}@{}", &info.username(), host);
} else {
eprintln!("already not signed in to {host}");
}
}
AuthCommand::AddKey { host, user, key } => {
let key = match key {
Some(key) => key,
None => readline("new key: ").await?,
};
if keys.hosts.get(&user).is_none() {
keys.hosts.insert(host, LoginInfo::new(user, key));
} else {
println!("key for {} already exists", host);
}
}
AuthCommand::List => {
if keys.hosts.is_empty() {
println!("No logins.");
}
for (host_url, login_info) in &keys.hosts {
println!("{}@{}", login_info.username(), host_url);
}
}
},
Command::Auth(auth_subcommand) => auth_subcommand.run(&mut keys).await?,
}
keys.save().await?;

101
src/repo.rs Normal file
View file

@ -0,0 +1,101 @@
use clap::Subcommand;
use url::Url;
use forgejo_api::CreateRepoOption;
#[derive(Subcommand, Clone, Debug)]
pub enum RepoCommand {
Create {
host: String,
repo: String,
// flags
#[clap(long, short)]
description: Option<String>,
#[clap(long, short)]
private: bool,
/// Sets the new repo to be the `origin` remote of the current local repo.
#[clap(long, short)]
set_upstream: Option<String>,
/// Pushes the current branch to the default branch on the new repo.
/// Implies `--set-upstream=origin` (setting upstream manual overrides this)
#[clap(long, short)]
push: bool,
},
Info,
Browse,
}
impl RepoCommand {
pub async fn run(self, keys: &crate::KeyInfo) -> eyre::Result<()> {
match self {
RepoCommand::Create {
host,
repo,
description,
private,
set_upstream,
push,
} => {
let host = Url::parse(&host)?;
let login = keys.get_login(&host)?;
let api = login.api_for(&host)?;
let repo_spec = CreateRepoOption {
auto_init: false,
default_branch: "main".into(),
description,
gitignores: String::new(),
issue_labels: String::new(),
license: String::new(),
name: repo.clone(),
private,
readme: String::new(),
template: false,
trust_model: forgejo_api::TrustModel::Default,
};
let new_repo = api.create_repo(repo_spec).await?;
eprintln!(
"created new repo at {}",
host.join(&format!("{}/{}", login.username(), repo))?
);
let upstream = set_upstream.as_deref().unwrap_or("origin");
let repo = git2::Repository::open(".")?;
let mut remote = if set_upstream.is_some() || push {
repo.remote(upstream, new_repo.clone_url.as_str())?
} else {
repo.find_remote(upstream)?
};
if push {
remote.push::<&str>(&[], None)?;
}
}
RepoCommand::Info => {
let (host, repo) = keys.get_current()?;
let api = host.api()?;
let repo = api.get_repo(repo.owner(), repo.name()).await?;
match repo {
Some(repo) => {
dbg!(repo);
}
None => eprintln!("repo not found"),
}
}
RepoCommand::Browse => {
let (host, repo) = keys.get_current()?;
let mut url = host.url().clone();
let new_path = format!(
"{}/{}/{}",
url.path().strip_suffix("/").unwrap_or(url.path()),
repo.owner(),
repo.name(),
);
url.set_path(&new_path);
open::that(url.as_str())?;
}
};
Ok(())
}
}