use std::borrow::Cow;
use std::collections::BTreeSet;
use std::io;
use gix_features::progress::Progress;
use gix_protocol::handshake::Ref;
use gix_protocol::transport::Protocol;
use gix_protocol::{ls_refs, Handshake};
use gix_transport::bstr::BString;
use crate::stage::RefPrefix;
use super::{agent_name, Connection};
pub struct Config {
#[allow(dead_code)]
pub repo: BString,
pub prefixes: BTreeSet<RefPrefix>,
}
pub(crate) fn run<R, W>(
config: Config,
handshake: &Handshake,
mut conn: Connection<R, W>,
progress: &mut impl Progress,
) -> Result<Vec<Ref>, ls_refs::Error>
where
R: io::Read,
W: io::Write,
{
log::trace!("Performing ls-refs: {:?}", config.prefixes);
let Handshake {
server_protocol_version: protocol,
capabilities,
..
} = handshake;
if protocol != &Protocol::V2 {
return Err(ls_refs::Error::Io(io::Error::other(
"expected protocol version 2",
)));
}
let (refspecs, prefixes) = {
let n = config.prefixes.len();
config.prefixes.into_iter().fold(
(Vec::with_capacity(n), Vec::with_capacity(n)),
|(mut specs, mut prefixes), prefix| {
specs.push(prefix.as_refspec());
prefixes.push(prefix.into_bstring());
(specs, prefixes)
},
)
};
log::trace!("ls-refs prefixes: {:#?}", refspecs);
let ls_refs = gix_protocol::LsRefsCommand::new(
Some(&refspecs),
capabilities,
("agent", Some(Cow::Owned(agent_name()))),
);
let refs = ls_refs
.invoke_blocking(&mut conn, progress, false)?
.into_iter()
.filter(|r| {
let (refname, _, _) = r.unpack();
prefixes.iter().any(|prefix| refname.starts_with(prefix))
})
.collect();
log::trace!("ls-refs received: {refs:#?}");
Ok(refs)
}