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 { + 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, page: String, }, + Clone { + repo: Option, + #[clap(long, short)] + path: Option, + }, Browse { #[clap(long, short)] repo: Option, @@ -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) -> 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(()) +}