Skip to content

Commit c3edef1

Browse files
committed
feat!: make it possible to trace incoming and outgoing packetlines.
Due to the way this is (and has to be) setup, unfortunately one has to integrate that with two crates, instead of just one. This changes touches multiple crates, most of which receive a single boolean as last argument to indicate whether the tracing should happen in the first place.
1 parent f9ae1bc commit c3edef1

File tree

50 files changed

+358
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+358
-80
lines changed

Diff for: Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: gitoxide-core/src/pack/receive.rs

+14
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ impl<W> protocol::fetch::DelegateBlocking for CloneDelegate<W> {
116116
mod blocking_io {
117117
use std::{io, io::BufRead, path::PathBuf};
118118

119+
use gix::config::tree::Key;
119120
use gix::{
120121
bstr::BString,
121122
protocol,
@@ -180,6 +181,12 @@ mod blocking_io {
180181
progress,
181182
protocol::FetchConnection::TerminateOnSuccessfulCompletion,
182183
gix::env::agent(),
184+
std::env::var_os(
185+
gix::config::tree::Gitoxide::TRACE_PACKET
186+
.environment_override()
187+
.expect("set"),
188+
)
189+
.is_some(),
183190
)?;
184191
Ok(())
185192
}
@@ -196,6 +203,7 @@ mod async_io {
196203

197204
use async_trait::async_trait;
198205
use futures_io::AsyncBufRead;
206+
use gix::config::tree::Key;
199207
use gix::{
200208
bstr::{BString, ByteSlice},
201209
odb::pack,
@@ -264,6 +272,12 @@ mod async_io {
264272
progress,
265273
protocol::FetchConnection::TerminateOnSuccessfulCompletion,
266274
gix::env::agent(),
275+
std::env::var_os(
276+
gix::config::tree::Gitoxide::TRACE_PACKET
277+
.environment_override()
278+
.expect("set"),
279+
)
280+
.is_some(),
267281
))
268282
})
269283
.await?;

Diff for: gix-filter/src/driver/process/client.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl Client {
7676
let mut input = gix_packetline::StreamingPeekableIter::new(
7777
process.stdout.take().expect("configured stdout when spawning"),
7878
&[gix_packetline::PacketLineRef::Flush],
79+
false, /* packet tracing */
7980
);
8081
let mut read = input.as_read();
8182
let mut buf = String::new();

Diff for: gix-filter/src/driver/process/server.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ impl Server {
6363
pick_version: &mut dyn FnMut(&[usize]) -> Option<usize>,
6464
available_capabilities: &[&str],
6565
) -> Result<Self, handshake::Error> {
66-
let mut input =
67-
gix_packetline::StreamingPeekableIter::new(stdin.lock(), &[gix_packetline::PacketLineRef::Flush]);
66+
let mut input = gix_packetline::StreamingPeekableIter::new(
67+
stdin.lock(),
68+
&[gix_packetline::PacketLineRef::Flush],
69+
false, /* packet tracing */
70+
);
6871
let mut read = input.as_read();
6972
let mut buf = String::new();
7073
read.read_line_to_string(&mut buf)?;

Diff for: gix-packetline-blocking/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ blocking-io = []
2424
serde = ["dep:serde", "bstr/serde"]
2525

2626
[dependencies]
27+
gix-trace = { version = "^0.1.3", path = "../gix-trace" }
28+
2729
serde = { version = "1.0.114", optional = true, default-features = false, features = ["std", "derive"]}
2830
thiserror = "1.0.34"
2931
faster-hex = "0.8.0"

Diff for: gix-packetline/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ path = "tests/blocking-packetline.rs"
3939
required-features = ["blocking-io", "maybe-async/is_sync"]
4040

4141
[dependencies]
42+
gix-trace = { version = "^0.1.3", path = "../gix-trace" }
43+
4244
serde = { version = "1.0.114", optional = true, default-features = false, features = ["std", "derive"]}
4345
thiserror = "1.0.34"
4446
faster-hex = "0.8.0"

Diff for: gix-packetline/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ pub struct StreamingPeekableIter<T> {
9191
delimiters: &'static [PacketLineRef<'static>],
9292
is_done: bool,
9393
stopped_at: Option<PacketLineRef<'static>>,
94+
#[cfg_attr(all(not(feature = "async-io"), not(feature = "blocking-io")), allow(dead_code))]
95+
trace: bool,
9496
}
9597

9698
/// Utilities to help decoding packet lines

Diff for: gix-packetline/src/read/async_io.rs

+20
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,30 @@ where
4444
delimiters: &[PacketLineRef<'static>],
4545
fail_on_err_lines: bool,
4646
buf_resize: bool,
47+
trace: bool,
4748
) -> ExhaustiveOutcome<'a> {
4849
(
4950
false,
5051
None,
5152
Some(match Self::read_line_inner(reader, buf).await {
5253
Ok(Ok(line)) => {
54+
if trace {
55+
match line {
56+
#[allow(unused_variables)]
57+
PacketLineRef::Data(d) => {
58+
gix_trace::trace!("<< {}", d.as_bstr().trim().as_bstr());
59+
}
60+
PacketLineRef::Flush => {
61+
gix_trace::trace!("<< FLUSH");
62+
}
63+
PacketLineRef::Delimiter => {
64+
gix_trace::trace!("<< DELIM");
65+
}
66+
PacketLineRef::ResponseEnd => {
67+
gix_trace::trace!("<< RESPONSE_END");
68+
}
69+
}
70+
}
5371
if delimiters.contains(&line) {
5472
let stopped_at = delimiters.iter().find(|l| **l == line).copied();
5573
buf.clear();
@@ -111,6 +129,7 @@ where
111129
self.delimiters,
112130
self.fail_on_err_lines,
113131
false,
132+
self.trace,
114133
)
115134
.await;
116135
self.is_done = is_done;
@@ -134,6 +153,7 @@ where
134153
self.delimiters,
135154
self.fail_on_err_lines,
136155
true,
156+
self.trace,
137157
)
138158
.await;
139159
self.is_done = is_done;

Diff for: gix-packetline/src/read/blocking_io.rs

+21
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,30 @@ where
3838
delimiters: &[PacketLineRef<'static>],
3939
fail_on_err_lines: bool,
4040
buf_resize: bool,
41+
trace: bool,
4142
) -> ExhaustiveOutcome<'a> {
4243
(
4344
false,
4445
None,
4546
Some(match Self::read_line_inner(reader, buf) {
4647
Ok(Ok(line)) => {
48+
if trace {
49+
match line {
50+
#[allow(unused_variables)]
51+
PacketLineRef::Data(d) => {
52+
gix_trace::trace!("<< {}", d.as_bstr().trim().as_bstr());
53+
}
54+
PacketLineRef::Flush => {
55+
gix_trace::trace!("<< FLUSH");
56+
}
57+
PacketLineRef::Delimiter => {
58+
gix_trace::trace!("<< DELIM");
59+
}
60+
PacketLineRef::ResponseEnd => {
61+
gix_trace::trace!("<< RESPONSE_END");
62+
}
63+
}
64+
}
4765
if delimiters.contains(&line) {
4866
let stopped_at = delimiters.iter().find(|l| **l == line).copied();
4967
buf.clear();
@@ -66,6 +84,7 @@ where
6684
if buf_resize {
6785
buf.resize(len, 0);
6886
}
87+
// TODO(borrowchk): remove additional decoding of internal buffer which is needed only to make it past borrowchk
6988
Ok(Ok(crate::decode(buf).expect("only valid data here")))
7089
}
7190
Ok(Err(err)) => {
@@ -105,6 +124,7 @@ where
105124
self.delimiters,
106125
self.fail_on_err_lines,
107126
false,
127+
self.trace,
108128
);
109129
self.is_done = is_done;
110130
self.stopped_at = stopped_at;
@@ -127,6 +147,7 @@ where
127147
self.delimiters,
128148
self.fail_on_err_lines,
129149
true,
150+
self.trace,
130151
);
131152
self.is_done = is_done;
132153
self.stopped_at = stopped_at;

Diff for: gix-packetline/src/read/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ pub use error::Error;
4343

4444
impl<T> StreamingPeekableIter<T> {
4545
/// Return a new instance from `read` which will stop decoding packet lines when receiving one of the given `delimiters`.
46-
pub fn new(read: T, delimiters: &'static [PacketLineRef<'static>]) -> Self {
46+
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
47+
pub fn new(read: T, delimiters: &'static [PacketLineRef<'static>], trace: bool) -> Self {
4748
StreamingPeekableIter {
4849
read,
4950
#[cfg(any(feature = "blocking-io", feature = "async-io"))]
@@ -53,6 +54,7 @@ impl<T> StreamingPeekableIter<T> {
5354
fail_on_err_lines: false,
5455
is_done: false,
5556
stopped_at: None,
57+
trace,
5658
}
5759
}
5860

Diff for: gix-packetline/src/read/sidebands/async_io.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ mod tests {
8080
/// We want to declare items containing pointers of `StreamingPeekableIter` `Send` as well, so it must be `Send` itself.
8181
#[test]
8282
fn streaming_peekable_iter_is_send() {
83-
receiver(StreamingPeekableIter::new(Vec::<u8>::new(), &[]));
83+
receiver(StreamingPeekableIter::new(Vec::<u8>::new(), &[], false));
8484
}
8585

8686
#[test]
8787
fn state_is_send() {
88-
let mut s = StreamingPeekableIter::new(Vec::<u8>::new(), &[]);
88+
let mut s = StreamingPeekableIter::new(Vec::<u8>::new(), &[], false);
8989
receiver(State::Idle { parent: Some(&mut s) });
9090
}
9191
}

Diff for: gix-packetline/tests/read/mod.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub mod streaming_peek_iter {
2020

2121
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
2222
async fn peek_follows_read_line_delimiter_logic() -> crate::Result {
23-
let mut rd = gix_packetline::StreamingPeekableIter::new(&b"0005a00000005b"[..], &[PacketLineRef::Flush]);
23+
let mut rd = gix_packetline::StreamingPeekableIter::new(&b"0005a00000005b"[..], &[PacketLineRef::Flush], false);
2424
let res = rd.peek_line().await;
2525
assert_eq!(res.expect("line")??, PacketLineRef::Data(b"a"));
2626
rd.read_line().await;
@@ -46,7 +46,8 @@ pub mod streaming_peek_iter {
4646

4747
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
4848
async fn peek_follows_read_line_err_logic() -> crate::Result {
49-
let mut rd = gix_packetline::StreamingPeekableIter::new(&b"0005a0009ERR e0000"[..], &[PacketLineRef::Flush]);
49+
let mut rd =
50+
gix_packetline::StreamingPeekableIter::new(&b"0005a0009ERR e0000"[..], &[PacketLineRef::Flush], false);
5051
rd.fail_on_err_lines(true);
5152
let res = rd.peek_line().await;
5253
assert_eq!(res.expect("line")??, PacketLineRef::Data(b"a"));
@@ -73,7 +74,8 @@ pub mod streaming_peek_iter {
7374

7475
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
7576
async fn peek_non_data() -> crate::Result {
76-
let mut rd = gix_packetline::StreamingPeekableIter::new(&b"000000010002"[..], &[PacketLineRef::ResponseEnd]);
77+
let mut rd =
78+
gix_packetline::StreamingPeekableIter::new(&b"000000010002"[..], &[PacketLineRef::ResponseEnd], false);
7779
let res = rd.read_line().await;
7880
assert_eq!(res.expect("line")??, PacketLineRef::Flush);
7981
let res = rd.read_line().await;
@@ -100,7 +102,7 @@ pub mod streaming_peek_iter {
100102
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
101103
async fn fail_on_err_lines() -> crate::Result {
102104
let input = b"00010009ERR e0002";
103-
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[]);
105+
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[], false);
104106
let res = rd.read_line().await;
105107
assert_eq!(res.expect("line")??, PacketLineRef::Delimiter);
106108
let res = rd.read_line().await;
@@ -110,7 +112,7 @@ pub mod streaming_peek_iter {
110112
"by default no special handling"
111113
);
112114

113-
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[]);
115+
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[], false);
114116
rd.fail_on_err_lines(true);
115117
let res = rd.read_line().await;
116118
assert_eq!(res.expect("line")??, PacketLineRef::Delimiter);
@@ -138,7 +140,7 @@ pub mod streaming_peek_iter {
138140
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
139141
async fn peek() -> crate::Result {
140142
let bytes = fixture_bytes("v1/fetch/01-many-refs.response");
141-
let mut rd = gix_packetline::StreamingPeekableIter::new(&bytes[..], &[PacketLineRef::Flush]);
143+
let mut rd = gix_packetline::StreamingPeekableIter::new(&bytes[..], &[PacketLineRef::Flush], false);
142144
let res = rd.peek_line().await;
143145
assert_eq!(res.expect("line")??, first_line(), "peek returns first line");
144146
let res = rd.peek_line().await;
@@ -175,7 +177,7 @@ pub mod streaming_peek_iter {
175177
async fn read_from_file_and_reader_advancement() -> crate::Result {
176178
let mut bytes = fixture_bytes("v1/fetch/01-many-refs.response");
177179
bytes.extend(fixture_bytes("v1/fetch/01-many-refs.response"));
178-
let mut rd = gix_packetline::StreamingPeekableIter::new(&bytes[..], &[PacketLineRef::Flush]);
180+
let mut rd = gix_packetline::StreamingPeekableIter::new(&bytes[..], &[PacketLineRef::Flush], false);
179181
let res = rd.read_line().await;
180182
assert_eq!(res.expect("line")??, first_line());
181183
let res = exhaust(&mut rd).await;

Diff for: gix-packetline/tests/read/sideband.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ mod util {
3838
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
3939
async fn read_pack_with_progress_extraction() -> crate::Result {
4040
let buf = fixture_bytes("v1/01-clone.combined-output");
41-
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush]);
41+
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush], false);
4242

4343
// Read without sideband decoding
4444
let mut out = Vec::new();
@@ -103,7 +103,7 @@ async fn read_pack_with_progress_extraction() -> crate::Result {
103103
async fn read_line_trait_method_reads_one_packet_line_at_a_time() -> crate::Result {
104104
let buf = fixture_bytes("v1/01-clone.combined-output-no-binary");
105105

106-
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush]);
106+
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush], false);
107107

108108
let mut out = String::new();
109109
let mut r = rd.as_read();
@@ -149,7 +149,7 @@ async fn read_line_trait_method_reads_one_packet_line_at_a_time() -> crate::Resu
149149
async fn readline_reads_one_packet_line_at_a_time() -> crate::Result {
150150
let buf = fixture_bytes("v1/01-clone.combined-output-no-binary");
151151

152-
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush]);
152+
let mut rd = gix_packetline::StreamingPeekableIter::new(&buf[..], &[PacketLineRef::Flush], false);
153153

154154
let mut r = rd.as_read();
155155
let line = r.read_data_line().await.unwrap()??.as_bstr().unwrap();
@@ -194,7 +194,7 @@ async fn readline_reads_one_packet_line_at_a_time() -> crate::Result {
194194
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
195195
async fn peek_past_an_actual_eof_is_an_error() -> crate::Result {
196196
let input = b"0009ERR e";
197-
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[]);
197+
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[], false);
198198
let mut reader = rd.as_read();
199199
let res = reader.peek_data_line().await;
200200
assert_eq!(res.expect("one line")??, b"ERR e");
@@ -218,7 +218,7 @@ async fn peek_past_an_actual_eof_is_an_error() -> crate::Result {
218218
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
219219
async fn peek_past_a_delimiter_is_no_error() -> crate::Result {
220220
let input = b"0009hello0000";
221-
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[PacketLineRef::Flush]);
221+
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[PacketLineRef::Flush], false);
222222
let mut reader = rd.as_read();
223223
let res = reader.peek_data_line().await;
224224
assert_eq!(res.expect("one line")??, b"hello");
@@ -238,7 +238,7 @@ async fn peek_past_a_delimiter_is_no_error() -> crate::Result {
238238
#[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))]
239239
async fn handling_of_err_lines() {
240240
let input = b"0009ERR e0009ERR x0000";
241-
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[]);
241+
let mut rd = gix_packetline::StreamingPeekableIter::new(&input[..], &[], false);
242242
rd.fail_on_err_lines(true);
243243
let mut buf = [0u8; 2];
244244
let mut reader = rd.as_read();

Diff for: gix-protocol/src/fetch/arguments/async_io.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ impl Arguments {
1919
transport.connection_persists_across_multiple_requests(),
2020
add_done_argument,
2121
)?;
22-
let mut line_writer =
23-
transport.request(client::WriteMode::OneLfTerminatedLinePerWriteCall, on_into_read)?;
22+
let mut line_writer = transport.request(
23+
client::WriteMode::OneLfTerminatedLinePerWriteCall,
24+
on_into_read,
25+
self.trace,
26+
)?;
2427
let had_args = !self.args.is_empty();
2528
for arg in self.args.drain(..) {
2629
line_writer.write_all(&arg).await?;
@@ -47,6 +50,7 @@ impl Arguments {
4750
Command::Fetch.as_str(),
4851
self.features.iter().filter(|(_, v)| v.is_some()).cloned(),
4952
Some(std::mem::replace(&mut self.args, retained_state).into_iter()),
53+
self.trace,
5054
)
5155
.await
5256
}

0 commit comments

Comments
 (0)