feat: wiki clone

This commit is contained in:
Cyborus 2024-08-07 19:03:50 -04:00
parent de144f29e6
commit 13b7bf5305
No known key found for this signature in database
2 changed files with 109 additions and 61 deletions

View file

@ -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)
}

View file

@ -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(())
}