@@ -90,9 +90,10 @@ mod with_io {
9090 }
9191 }
9292
93- /// Compute initial arguments based on the given `features`. They are typically provided by the `default_features(…)` method.
94- /// Only useful for V2
95- pub ( crate ) fn initial_arguments ( & self , features : & [ Feature ] ) -> Vec < BString > {
93+ /// Provide the initial arguments based on the given `features`.
94+ /// They are typically provided by the [`Self::default_features`] method.
95+ /// Only useful for V2, and based on heuristics/experimentation.
96+ pub fn initial_v2_arguments ( & self , features : & [ Feature ] ) -> Vec < BString > {
9697 match self {
9798 Command :: Fetch => [ "thin-pack" , "ofs-delta" ]
9899 . iter ( )
@@ -157,20 +158,24 @@ mod with_io {
157158 Command :: LsRefs => vec ! [ ] ,
158159 }
159160 }
160- /// Panics if the given arguments and features don't match what's statically known. It's considered a bug in the delegate .
161- pub ( crate ) fn validate_argument_prefixes_or_panic (
161+ /// Return an error if the given ` arguments` and ` features` don't match what's statically known.
162+ pub fn validate_argument_prefixes (
162163 & self ,
163164 version : gix_transport:: Protocol ,
164165 server : & Capabilities ,
165166 arguments : & [ BString ] ,
166167 features : & [ Feature ] ,
167- ) {
168+ ) -> Result < ( ) , validate_argument_prefixes:: Error > {
169+ use validate_argument_prefixes:: Error ;
168170 let allowed = self . all_argument_prefixes ( ) ;
169171 for arg in arguments {
170172 if allowed. iter ( ) . any ( |allowed| arg. starts_with ( allowed. as_bytes ( ) ) ) {
171173 continue ;
172174 }
173- panic ! ( "{}: argument {} is not known or allowed" , self . as_str( ) , arg) ;
175+ return Err ( Error :: UnsupportedArgument {
176+ command : self . as_str ( ) ,
177+ argument : arg. clone ( ) ,
178+ } ) ;
174179 }
175180 match version {
176181 gix_transport:: Protocol :: V0 | gix_transport:: Protocol :: V1 => {
@@ -181,14 +186,17 @@ mod with_io {
181186 {
182187 continue ;
183188 }
184- panic ! ( "{}: capability {} is not supported" , self . as_str( ) , feature) ;
189+ return Err ( Error :: UnsupportedCapability {
190+ command : self . as_str ( ) ,
191+ feature : feature. to_string ( ) ,
192+ } ) ;
185193 }
186194 }
187195 gix_transport:: Protocol :: V2 => {
188196 let allowed = server
189197 . iter ( )
190198 . find_map ( |c| {
191- if c. name ( ) == self . as_str ( ) . as_bytes ( ) . as_bstr ( ) {
199+ if c. name ( ) == self . as_str ( ) {
192200 c. values ( ) . map ( |v| v. map ( ToString :: to_string) . collect :: < Vec < _ > > ( ) )
193201 } else {
194202 None
@@ -201,14 +209,34 @@ mod with_io {
201209 }
202210 match * feature {
203211 "agent" => { }
204- _ => panic ! ( "{}: V2 feature/capability {} is not supported" , self . as_str( ) , feature) ,
212+ _ => {
213+ return Err ( Error :: UnsupportedCapability {
214+ command : self . as_str ( ) ,
215+ feature : feature. to_string ( ) ,
216+ } )
217+ }
205218 }
206219 }
207220 }
208221 }
222+ Ok ( ( ) )
209223 }
210224 }
211- }
212225
213- #[ cfg( test) ]
214- mod tests;
226+ ///
227+ pub mod validate_argument_prefixes {
228+ use bstr:: BString ;
229+
230+ /// The error returned by [Command::validate_argument_prefixes()](super::Command::validate_argument_prefixes()).
231+ #[ derive( Debug , thiserror:: Error ) ]
232+ #[ allow( missing_docs) ]
233+ pub enum Error {
234+ #[ error( "{command}: argument {argument} is not known or allowed" ) ]
235+ UnsupportedArgument { command : & ' static str , argument : BString } ,
236+ #[ error( "{command}: capability {feature} is not supported" ) ]
237+ UnsupportedCapability { command : & ' static str , feature : String } ,
238+ }
239+ }
240+ }
241+ #[ cfg( any( test, feature = "async-client" , feature = "blocking-client" ) ) ]
242+ pub use with_io:: validate_argument_prefixes;
0 commit comments