History

[git-protocol] move everything into `blocking_io` for later translation…

…into async-io, as usual.

Sebastian Thiel committed 5 years ago

Commit fa033741 parent 0d39b5d12 files · +295 −254Browse files

Showing the changes to git-protocol/src/fetch/command.rs (1 of 12 files). Show all

Unified · Split

git-protocol/src/fetch/command.rs+0−196
@@ -1,196 +0,0 @@
1use crate::fetch::agent;
2use bstr::{BString, ByteSlice};
3use git_transport::client::Capabilities;
4
5/// The kind of command to invoke on the server side.
6#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
7pub enum Command {
8 /// List references.
9 LsRefs,
10 /// Fetch a pack.
11 Fetch,
12}
13
14/// A key value pair of values known at compile time.
15pub type Feature = (&'static str, Option<&'static str>);
16
17impl Command {
18 /// Produce the name of the command as known by the server side.
19 pub fn as_str(&self) -> &'static str {
20 match self {
21 Command::LsRefs => "ls-refs",
22 Command::Fetch => "fetch",
23 }
24 }
25
26 /// Only V2
27 fn all_argument_prefixes(&self) -> &'static [&'static str] {
28 match self {
29 Command::LsRefs => &["symrefs", "peel", "ref-prefix "],
30 Command::Fetch => &[
31 "want ", // hex oid
32 "have ", // hex oid
33 "done",
34 "thin-pack",
35 "no-progress",
36 "include-tag",
37 "ofs-delta",
38 // Shallow feature/capability
39 "shallow ", // hex oid
40 "deepen ", // commit depth
41 "deepen-relative",
42 "deepen-since ", // time-stamp
43 "deepen-not ", // rev
44 // filter feature/capability
45 "filter ", // filter-spec
46 // ref-in-want feature
47 "want-ref ", // ref path
48 "sideband-all",
49 // packfile-uris feature
50 "packfile-uris ", // protocols
51 ],
52 }
53 }
54
55 fn all_features(&self, version: git_transport::Protocol) -> &'static [&'static str] {
56 match self {
57 Command::LsRefs => &[],
58 Command::Fetch => match version {
59 git_transport::Protocol::V1 => &[
60 "multi_ack",
61 "thin-pack",
62 "side-band",
63 "side-band-64k",
64 "ofs-delta",
65 "shallow",
66 "deepen-since",
67 "deepen-not",
68 "deepen-relative",
69 "no-progress",
70 "include-tag",
71 "multi_ack_detailed",
72 "allow-tip-sha1-in-want",
73 "allow-reachable-sha1-in-want",
74 "no-done",
75 "filter",
76 ],
77 git_transport::Protocol::V2 => &["shallow", "filter", "ref-in-want", "sideband-all", "packfile-uris"],
78 },
79 }
80 }
81
82 /// Compute initial arguments based on the given `features`. They are typically provided by the `default_features(…)` method.
83 /// Only useful for V2
84 pub(crate) fn initial_arguments(&self, features: &[Feature]) -> Vec<BString> {
85 match self {
86 Command::Fetch => ["thin-pack", "include-tag", "ofs-delta"]
87 .iter()
88 .map(|s| s.as_bytes().as_bstr().to_owned())
89 .chain(
90 ["sideband-all", "ref-in-want", "packfile-uris"]
91 .iter()
92 .filter(|f| features.iter().any(|(sf, _)| sf == *f))
93 .map(|f| f.as_bytes().as_bstr().to_owned()),
94 )
95 .collect(),
96 Command::LsRefs => vec![b"symrefs".as_bstr().to_owned(), b"peel".as_bstr().to_owned()],
97 }
98 }
99
100 pub(crate) fn default_features(
101 &self,
102 version: git_transport::Protocol,
103 server_capabilities: &Capabilities,
104 ) -> Vec<Feature> {
105 match self {
106 Command::Fetch => match version {
107 git_transport::Protocol::V1 => {
108 let has_multi_ack_detailed = server_capabilities.contains("multi_ack_detailed");
109 let has_sideband_64k = server_capabilities.contains("side-band-64k");
110 self.all_features(version)
111 .iter()
112 .copied()
113 .filter(|feature| match *feature {
114 "side-band" if has_sideband_64k => false,
115 "multi_ack" if has_multi_ack_detailed => false,
116 "include-tag" | "no-progress" => false,
117 feature => server_capabilities.contains(feature),
118 })
119 .map(|s| (s, None))
120 .chain(Some(agent()))
121 .collect()
122 }
123 git_transport::Protocol::V2 => {
124 let supported_features = server_capabilities
125 .iter()
126 .find_map(|c| {
127 if c.name() == Command::Fetch.as_str().as_bytes().as_bstr() {
128 c.values().map(|v| v.map(|f| f.to_owned()).collect())
129 } else {
130 None
131 }
132 })
133 .unwrap_or_else(Vec::new);
134 self.all_features(version)
135 .iter()
136 .copied()
137 .filter(|feature| supported_features.iter().any(|supported| supported == feature))
138 .map(|s| (s, None))
139 .chain(Some(agent()))
140 .collect()
141 }
142 },
143 Command::LsRefs => vec![agent()],
144 }
145 }
146 /// Panics if the given arguments and features don't match what's statically known. It's considered a bug in the delegate.
147 pub(crate) fn validate_argument_prefixes_or_panic(
148 &self,
149 version: git_transport::Protocol,
150 server: &Capabilities,
151 arguments: &[BString],
152 features: &[Feature],
153 ) {
154 let allowed = self.all_argument_prefixes();
155 for arg in arguments {
156 if allowed.iter().any(|allowed| arg.starts_with(allowed.as_bytes())) {
157 continue;
158 }
159 panic!("{}: argument {} is not known or allowed", self.as_str(), arg);
160 }
161 match version {
162 git_transport::Protocol::V1 => {
163 for (feature, _) in features {
164 if server
165 .iter()
166 .any(|c| feature.starts_with(c.name().to_str_lossy().as_ref()))
167 {
168 continue;
169 }
170 panic!("{}: capability {} is not supported", self.as_str(), feature);
171 }
172 }
173 git_transport::Protocol::V2 => {
174 let allowed = server
175 .iter()
176 .find_map(|c| {
177 if c.name() == self.as_str().as_bytes().as_bstr() {
178 c.values().map(|v| v.map(|f| f.to_string()).collect::<Vec<_>>())
179 } else {
180 None
181 }
182 })
183 .unwrap_or_default();
184 for (feature, _) in features {
185 if allowed.iter().any(|allowed| feature == allowed) {
186 continue;
187 }
188 match *feature {
189 "agent" => {}
190 _ => panic!("{}: V2 feature/capability {} is not supported", self.as_str(), feature),
191 }
192 }
193 }
194 }
195 }
196}