-
-
Notifications
You must be signed in to change notification settings - Fork 317
/
remote.rs
133 lines (123 loc) · 4.08 KB
/
remote.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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(())
}
}