summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyborus <cyborus@cyborus.xyz>2024-08-08 01:03:50 +0200
committerCyborus <cyborus@cyborus.xyz>2024-08-08 01:35:51 +0200
commit13b7bf53053fb7fb518108e1886ba1f33d7b28b7 (patch)
treea85352a4e4776ab6d7165f10ee5807d8e208ac55
parentfeat: `wiki browse` (diff)
downloadforgejo-cli-13b7bf53053fb7fb518108e1886ba1f33d7b28b7.tar.xz
forgejo-cli-13b7bf53053fb7fb518108e1886ba1f33d7b28b7.zip
feat: `wiki clone`
-rw-r--r--src/repo.rs127
-rw-r--r--src/wiki.rs43
2 files changed, 109 insertions, 61 deletions
diff --git a/src/repo.rs b/src/repo.rs
index ee67b9b..593caba 100644
--- a/src/repo.rs
+++ b/src/repo.rs
@@ -600,65 +600,7 @@ impl RepoCommand {
let path = path.unwrap_or_else(|| PathBuf::from(format!("./{repo_name}")));
- let SpecialRender {
- fancy,
- hide_cursor,
- show_cursor,
- clear_line,
- ..
- } = *crate::special_render();
-
- let auth = auth_git2::GitAuthenticator::new();
- let git_config = git2::Config::open_default()?;
-
- let mut options = git2::FetchOptions::new();
- let mut callbacks = git2::RemoteCallbacks::new();
- callbacks.credentials(auth.credentials(&git_config));
-
- if fancy {
- print!("{hide_cursor}");
- print!(" Preparing...");
- let _ = std::io::stdout().flush();
-
- callbacks.transfer_progress(|progress| {
- print!("{clear_line}\r");
- if progress.received_objects() == progress.total_objects() {
- if progress.indexed_deltas() == progress.total_deltas() {
- print!("Finishing up...");
- } else {
- let percent = 100.0 * (progress.indexed_deltas() as f64)
- / (progress.total_deltas() as f64);
- print!(" Resolving... {percent:.01}%");
- }
- } else {
- let bytes = progress.received_bytes();
- let percent = 100.0 * (progress.received_objects() as f64)
- / (progress.total_objects() as f64);
- print!(" Downloading... {percent:.01}%");
- match bytes {
- 0..=1023 => print!(" ({}b)", bytes),
- 1024..=1048575 => print!(" ({:.01}kb)", (bytes as f64) / 1024.0),
- 1048576..=1073741823 => {
- print!(" ({:.01}mb)", (bytes as f64) / 1048576.0)
- }
- 1073741824.. => {
- print!(" ({:.01}gb)", (bytes as f64) / 1073741824.0)
- }
- }
- }
- let _ = std::io::stdout().flush();
- true
- });
- options.remote_callbacks(callbacks);
- }
-
- let local_repo = git2::build::RepoBuilder::new()
- .fetch_options(options)
- .clone(clone_url.as_str(), &path)?;
- if fancy {
- print!("{clear_line}{show_cursor}\r");
- }
- println!("Cloned {} into {}", repo_full_name, path.display());
+ let local_repo = clone_repo(&repo_full_name, &clone_url, &path)?;
if let Some(parent) = repo_data.parent.as_deref() {
let parent_clone_url = parent
@@ -717,3 +659,70 @@ impl RepoCommand {
Ok(())
}
}
+
+pub fn clone_repo(
+ repo_name: &str,
+ url: &url::Url,
+ path: &std::path::Path,
+) -> eyre::Result<git2::Repository> {
+ let SpecialRender {
+ fancy,
+ hide_cursor,
+ show_cursor,
+ clear_line,
+ ..
+ } = *crate::special_render();
+
+ let auth = auth_git2::GitAuthenticator::new();
+ let git_config = git2::Config::open_default()?;
+
+ let mut options = git2::FetchOptions::new();
+ let mut callbacks = git2::RemoteCallbacks::new();
+ callbacks.credentials(auth.credentials(&git_config));
+
+ if fancy {
+ print!("{hide_cursor}");
+ print!(" Preparing...");
+ let _ = std::io::stdout().flush();
+
+ callbacks.transfer_progress(|progress| {
+ print!("{clear_line}\r");
+ if progress.received_objects() == progress.total_objects() {
+ if progress.indexed_deltas() == progress.total_deltas() {
+ print!("Finishing up...");
+ } else {
+ let percent = 100.0 * (progress.indexed_deltas() as f64)
+ / (progress.total_deltas() as f64);
+ print!(" Resolving... {percent:.01}%");
+ }
+ } else {
+ let bytes = progress.received_bytes();
+ let percent = 100.0 * (progress.received_objects() as f64)
+ / (progress.total_objects() as f64);
+ print!(" Downloading... {percent:.01}%");
+ match bytes {
+ 0..=1023 => print!(" ({}b)", bytes),
+ 1024..=1048575 => print!(" ({:.01}kb)", (bytes as f64) / 1024.0),
+ 1048576..=1073741823 => {
+ print!(" ({:.01}mb)", (bytes as f64) / 1048576.0)
+ }
+ 1073741824.. => {
+ print!(" ({:.01}gb)", (bytes as f64) / 1073741824.0)
+ }
+ }
+ }
+ let _ = std::io::stdout().flush();
+ true
+ });
+ options.remote_callbacks(callbacks);
+ }
+
+ let local_repo = git2::build::RepoBuilder::new()
+ .fetch_options(options)
+ .clone(url.as_str(), &path)?;
+ if fancy {
+ print!("{clear_line}{show_cursor}\r");
+ }
+ println!("Cloned {} into {}", repo_name, path.display());
+ Ok(local_repo)
+}
diff --git a/src/wiki.rs b/src/wiki.rs
index 4aff76c..3f31023 100644
--- a/src/wiki.rs
+++ b/src/wiki.rs
@@ -1,3 +1,5 @@
+use std::path::PathBuf;
+
use base64ct::Encoding;
use clap::{Args, Subcommand};
use eyre::{Context, OptionExt};
@@ -27,6 +29,11 @@ pub enum WikiSubcommand {
repo: Option<RepoArg>,
page: String,
},
+ Clone {
+ repo: Option<RepoArg>,
+ #[clap(long, short)]
+ path: Option<PathBuf>,
+ },
Browse {
#[clap(long, short)]
repo: Option<RepoArg>,
@@ -45,6 +52,7 @@ impl WikiCommand {
match self.command {
Contents { repo: _ } => wiki_contents(&repo, &api).await?,
View { repo: _, page } => view_wiki_page(&repo, &api, &*page).await?,
+ Clone { repo: _, path } => clone_wiki(&repo, &api, path).await?,
Browse { repo: _, page } => browse_wiki_page(&repo, &api, &*page).await?,
}
Ok(())
@@ -53,14 +61,16 @@ impl WikiCommand {
fn repo(&self) -> Option<&RepoArg> {
use WikiSubcommand::*;
match &self.command {
- Contents { repo } | View { repo, .. } | Browse { repo, .. } => repo.as_ref(),
+ Contents { repo } | View { repo, .. } | Clone { repo, .. } | Browse { repo, .. } => {
+ repo.as_ref()
+ }
}
}
fn no_repo_error(&self) -> eyre::Error {
use WikiSubcommand::*;
match &self.command {
- Contents { repo: _ } | View { .. } | Browse { .. } => {
+ Contents { repo: _ } | View { .. } | Clone { .. } | Browse { .. } => {
eyre::eyre!("couldn't guess repo")
}
}
@@ -124,3 +134,32 @@ async fn browse_wiki_page(repo: &RepoName, api: &Forgejo, page: &str) -> eyre::R
open::that(html_url.as_str())?;
Ok(())
}
+
+async fn clone_wiki(repo: &RepoName, api: &Forgejo, path: Option<PathBuf>) -> eyre::Result<()> {
+ let repo_data = api.repo_get(repo.owner(), repo.name()).await?;
+ let clone_url = repo_data
+ .clone_url
+ .as_ref()
+ .ok_or_eyre("repo does not have clone url")?;
+ let git_stripped = clone_url
+ .as_str()
+ .strip_suffix(".git")
+ .unwrap_or(clone_url.as_str());
+ let clone_url = url::Url::parse(&format!("{}.wiki.git", git_stripped))?;
+
+ let repo_name = repo_data
+ .name
+ .as_deref()
+ .ok_or_eyre("repo does not have name")?;
+ let repo_full_name = repo_data
+ .full_name
+ .as_deref()
+ .ok_or_eyre("repo does not have full name")?;
+ let name = format!("{}'s wiki", repo_full_name);
+
+ let path = path.unwrap_or_else(|| PathBuf::from(format!("./{repo_name}-wiki")));
+
+ crate::repo::clone_repo(&name, &clone_url, &path)?;
+
+ Ok(())
+}