Skip to content

Commit

Permalink
feat: gix remote refs to list all remote references of a suitable r…
Browse files Browse the repository at this point in the history
…emote. (#450)

This takes into account either a named remote, or the remote associated
with the current branch, or the default remote it could deduce or obtain
from the configuration.
  • Loading branch information
Byron committed Aug 22, 2022
1 parent bb6813a commit 5d6d5ca
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 13 deletions.
2 changes: 1 addition & 1 deletion gitoxide-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ estimate-hours = ["itertools", "rayon", "fs-err"]
blocking-client = ["git-repository/blocking-network-client"]
## The client to connect to git servers will be async, while supporting only the 'git' transport itself.
## It's the most limited and can be seen as example on how to use custom transports for custom servers.
async-client = ["git-repository/async-network-client", "git-transport-configuration-only/async-std", "async-trait", "futures-io", "async-net", "async-io", "futures-lite", "blocking"]
async-client = ["git-repository/async-network-client-async-std", "git-transport-configuration-only/async-std", "async-trait", "futures-io", "async-net", "async-io", "futures-lite", "blocking"]

#! ### Other
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
Expand Down
95 changes: 89 additions & 6 deletions gitoxide-core/src/repository/remote.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,100 @@
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
mod net {
use crate::OutputFormat;
use anyhow::Context;
use git_repository as git;
use git_repository::protocol::fetch;

#[git::protocol::maybe_async::maybe_async]
pub async fn refs(
_repo: git::Repository,
_name: &str,
_format: OutputFormat,
_progress: impl git::Progress,
_out: impl std::io::Write,
repo: git::Repository,
name: Option<&str>,
format: OutputFormat,
mut progress: impl git::Progress,
out: impl std::io::Write,
) -> anyhow::Result<()> {
todo!()
let remote = match name {
Some(name) => repo.find_remote(name)?,
None => repo
.head()?
.into_remote(git::remote::Direction::Fetch)
.context("Cannot find a remote for unborn branch")??,
};
progress.info(format!(
"Connecting to {:?}",
remote
.url(git::remote::Direction::Fetch)
.context("Remote didn't have a URL to connect to")?
.to_bstring()
));
let refs = remote
.connect(git::remote::Direction::Fetch, progress)
.await?
.list_refs()
.await?;

match format {
OutputFormat::Human => drop(print(out, &refs)),
#[cfg(feature = "serde1")]
OutputFormat::Json => {
serde_json::to_writer_pretty(out, &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<fetch::Ref> for JsonRef {
fn from(value: fetch::Ref) -> Self {
match value {
fetch::Ref::Direct { path, object } => JsonRef::Direct {
path: path.to_string(),
object: object.to_string(),
},
fetch::Ref::Symbolic { path, target, object } => JsonRef::Symbolic {
path: path.to_string(),
target: target.to_string(),
object: object.to_string(),
},
fetch::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 std::io::Write, refs: &[fetch::Ref]) -> std::io::Result<()> {
for r in refs {
match r {
fetch::Ref::Direct { path, object } => writeln!(&mut out, "{} {}", object.to_hex(), path),
fetch::Ref::Peeled { path, object, tag } => {
writeln!(&mut out, "{} {} tag:{}", object.to_hex(), path, tag)
}
fetch::Ref::Symbolic { path, target, object } => {
writeln!(&mut out, "{} {} symref-target:{}", object.to_hex(), path, target)
}
}?;
}
Ok(())
}
}
#[cfg(any(feature = "blocking-client", feature = "async-client"))]
Expand Down
14 changes: 10 additions & 4 deletions src/plumbing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,23 +98,29 @@ pub fn main() -> Result<()> {
#[cfg(feature = "gitoxide-core-blocking-client")]
{
prepare_and_run(
"config-list",
"remote-refs",
verbose,
progress,
progress_keep_open,
None,
move |progress, out, _err| {
core::repository::remote::refs(repository(Mode::Lenient)?, &name, format, progress, out)
core::repository::remote::refs(
repository(Mode::Lenient)?,
name.as_deref(),
format,
progress,
out,
)
},
)
}
#[cfg(feature = "gitoxide-core-async-client")]
{
let (_handle, progress) =
async_util::prepare(verbose, "remote-ref-list", Some(core::remote::refs::PROGRESS_RANGE));
async_util::prepare(verbose, "remote-refs", Some(core::remote::refs::PROGRESS_RANGE));
futures_lite::future::block_on(core::repository::remote::refs(
repository(Mode::Lenient)?,
&name,
name.as_deref(),
format,
progress,
std::io::stdout(),
Expand Down
6 changes: 4 additions & 2 deletions src/plumbing/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ pub mod remote {
#[derive(Debug, clap::Parser)]
pub struct Platform {
/// The name of the remote to connect to.
#[clap(long, short = 'n', default_value = "origin")]
pub name: String,
///
/// If unset, the current branch will determine the remote.
#[clap(long, short = 'n')]
pub name: Option<String>,

/// Subcommands
#[clap(subcommand)]
Expand Down

0 comments on commit 5d6d5ca

Please sign in to comment.