pub mod refs {
use crate::{OutputFormat, Protocol};
use git_features::progress::Progress;
use git_protocol::{
fetch::{Action, Ref},
git_transport,
};
pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=2;
use git_protocol::fetch::{Arguments, Response};
use std::io;
#[derive(Default)]
struct LsRemotes {
refs: Vec<Ref>,
}
impl git_protocol::fetch::Delegate for LsRemotes {
fn prepare_fetch(
&mut self,
_version: git_transport::Protocol,
_server: &git_transport::client::Capabilities,
_features: &mut Vec<(&str, Option<&str>)>,
refs: &[Ref],
) -> Action {
self.refs = refs.into();
Action::Close
}
fn negotiate(
&mut self,
_refs: &[Ref],
_arguments: &mut Arguments,
_previous_result: Option<&Response>,
) -> Action {
unreachable!("not to be called due to Action::Close in `prepare_fetch`")
}
fn receive_pack(
&mut self,
_input: impl io::BufRead,
_progress: impl Progress,
_refs: &[Ref],
_previous: &Response,
) -> io::Result<()> {
unreachable!("not called for ls-refs")
}
}
pub struct Context<W: io::Write> {
pub thread_limit: Option<usize>,
pub format: OutputFormat,
pub out: W,
}
pub fn list(
protocol: Option<Protocol>,
url: &str,
progress: impl Progress,
ctx: Context<impl io::Write>,
) -> anyhow::Result<()> {
let transport = git_transport::client::connect(url.as_bytes(), protocol.unwrap_or_default().into())?;
let mut delegate = LsRemotes::default();
git_protocol::fetch(transport, &mut delegate, git_protocol::credentials::helper, progress)?;
match ctx.format {
OutputFormat::Human => drop(print(ctx.out, &delegate.refs)),
#[cfg(feature = "serde1")]
OutputFormat::Json => serde_json::to_writer_pretty(
ctx.out,
&delegate.refs.into_iter().map(JsonRef::from).collect::<Vec<_>>(),
)?,
};
Ok(())
}
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum JsonRef {
Peeled {
path: String,
tag: String,
object: String,
},
Direct {
path: String,
object: String,
},
Symbolic {
path: String,
target: String,
object: String,
},
}
impl From<Ref> for JsonRef {
fn from(value: Ref) -> Self {
match value {
Ref::Direct { path, object } => JsonRef::Direct {
path: path.to_string(),
object: object.to_string(),
},
Ref::Symbolic { path, target, object } => JsonRef::Symbolic {
path: path.to_string(),
target: target.to_string(),
object: object.to_string(),
},
Ref::Peeled { path, tag, object } => JsonRef::Peeled {
path: path.to_string(),
tag: tag.to_string(),
object: object.to_string(),
},
}
}
}
pub(crate) fn print(mut out: impl io::Write, refs: &[Ref]) -> io::Result<()> {
for r in refs {
match r {
Ref::Direct { path, object } => writeln!(&mut out, "{} {}", object.to_sha1_hex_string(), path),
Ref::Peeled { path, object, tag } => {
writeln!(&mut out, "{} {} tag:{}", object.to_sha1_hex_string(), path, tag)
}
Ref::Symbolic { path, target, object } => writeln!(
&mut out,
"{} {} symref-target:{}",
object.to_sha1_hex_string(),
path,
target
),
}?;
}
Ok(())
}
}