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
//! **send-pack**, and the receive-pack grammar under it — the half of git that
//! gitoxide does not have.
//!
//! Verified in gix 0.86: `gix-protocol/src/` carries `fetch/`, `ls_refs.rs` and
//! `handshake/`, and **nothing for push**. `Direction::Push` exists only as a
//! refspec direction. So a git client written on gix has to put this on the
//! wire itself, and a git *server* written on gix has to put the other side of
//! it on the wire itself, and until this crate existed those two were written
//! twice — once per direction, in two crates, in two different styles, agreeing
//! only by inspection.
//!
//! # One grammar, both directions
//!
//! That is the load-bearing idea, and it is why this crate is not called
//! `send-pack` alone. Four formats make up the v0 push conversation:
//!
//! | format | client | server |
//! |---|---|---|
//! | [`capabilities`] | parses the remote's, writes its own | writes its own, parses the client's |
//! | [`advertisement`] | [`advertisement::parse`] | [`advertisement::lines`] |
//! | [`command`] | [`command::lines`] | [`command::parse_line`] |
//! | [`report`] | [`report::parse`] | [`report::lines`] |
//!
//! Each row is **one** implementation with two entry points, so an encoder and
//! its decoder cannot drift: there is nothing for them to drift from. A test
//! that round-trips one row exercises both ends of a real conversation rather
//! than one end against a fixture written by the same hand.
//!
//! # Payloads, not packets
//!
//! Every `lines` function returns payloads **without pkt-line framing, without
//! a terminating flush-pkt, and without a trailing newline**, and every parser
//! takes them the same way. git frames these sections as *text* pkt-lines,
//! `<4-hex-length><payload>\n`, and the newline belongs to the framer.
//!
//! That split is what lets a server that already owns a pkt-line framer and a
//! socket use this crate without paying for a second framing layer: with
//! `default-features = false` the whole crate is `gix-hash` + `bstr` +
//! `thiserror`. The `blocking-io` feature — on by default, because a client is
//! the majority consumer — adds [`Transport`], the pkt-line reader and
//! [`send_pack`], framed with [`gix_packetline`].
//!
//! # Example: what a client does
//!
//! ```no_run
//! # fn main() -> Result<(), gunnar_sendpack::Error> {
//! use gunnar_sendpack::{read_advertisement, send_pack, IoPair, PushCommand, SendPackOptions};
//!
//! // Two pipes to a remote `git-receive-pack`.
//! # let (stdout, stdin): (std::fs::File, std::fs::File) = unimplemented!();
//! let mut transport = IoPair::new(stdout, stdin);
//! let (reader, _) = { use gunnar_sendpack::Transport as _; transport.io() };
//! let adv = read_advertisement(reader)?;
//!
//! let tip = adv.oid_of("refs/heads/main");
//! # let new_tip = tip;
//! let commands = vec![PushCommand::update("refs/heads/main", tip, new_tip)];
//! let report = send_pack(
//! &mut transport,
//! &adv,
//! &commands,
//! adv.hash_kind,
//! Some(|w: &mut dyn std::io::Write| Ok(w.write_all(b"PACK...")?)),
//! &SendPackOptions::default(),
//! )?;
//! assert!(report.is_ok(), "{:?}", report.failure_summary());
//! # Ok(())
//! # }
//! ```
//!
//! # Licence
//!
//! `MIT OR Apache-2.0`, to match gitoxide's.
pub use ;
pub use Capabilities;
pub use PushCommand;
pub use ;
pub use SendPackOptions;
pub use ;
pub use ;
pub use ;