@@ -258,13 +258,16 @@ pub fn assert_matches_path(
258258 . matches_path ( expected_path, buf) ;
259259}
260260
261- pub fn register_example ( name : & str , shell : completest:: Shell ) {
261+ pub fn register_example < R : completest:: RuntimeBuilder > ( context : & str , name : & str ) {
262+ use completest:: Runtime as _;
263+
262264 let scratch = snapbox:: path:: PathFixture :: mutable_temp ( ) . unwrap ( ) ;
263265 let scratch_path = scratch. path ( ) . unwrap ( ) ;
264266
265- let shell_name = shell . name ( ) ;
267+ let shell_name = R :: name ( ) ;
266268 let home = std:: path:: Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) )
267269 . join ( "tests/snapshots/home" )
270+ . join ( context)
268271 . join ( name)
269272 . join ( shell_name) ;
270273 println ! ( "Compiling" ) ;
@@ -275,10 +278,17 @@ pub fn register_example(name: &str, shell: completest::Shell) {
275278 println ! ( "Compiled" ) ;
276279 let bin_root = bin_path. parent ( ) . unwrap ( ) . to_owned ( ) ;
277280
278- let registration = std:: process:: Command :: new ( & bin_path)
279- . arg ( format ! ( "--generate={shell_name}" ) )
280- . output ( )
281- . unwrap ( ) ;
281+ let mut registration = std:: process:: Command :: new ( & bin_path) ;
282+ match context {
283+ "static" => registration. args ( [ format ! ( "--generate={shell_name}" ) ] ) ,
284+ "dynamic" => registration. args ( [
285+ "complete" . to_owned ( ) ,
286+ "--register=-" . to_owned ( ) ,
287+ format ! ( "--shell={shell_name}" ) ,
288+ ] ) ,
289+ _ => unreachable ! ( "unsupported context {}" , context) ,
290+ } ;
291+ let registration = registration. output ( ) . unwrap ( ) ;
282292 assert ! (
283293 registration. status. success( ) ,
284294 "{}" ,
@@ -287,7 +297,7 @@ pub fn register_example(name: &str, shell: completest::Shell) {
287297 let registration = std:: str:: from_utf8 ( & registration. stdout ) . unwrap ( ) ;
288298 assert ! ( !registration. is_empty( ) ) ;
289299
290- let mut runtime = shell . init ( bin_root, scratch_path. to_owned ( ) ) . unwrap ( ) ;
300+ let mut runtime = R :: new ( bin_root, scratch_path. to_owned ( ) ) . unwrap ( ) ;
291301
292302 runtime. register ( name, registration) . unwrap ( ) ;
293303
@@ -296,14 +306,23 @@ pub fn register_example(name: &str, shell: completest::Shell) {
296306 scratch. close ( ) . unwrap ( ) ;
297307}
298308
299- pub fn load_runtime ( name : & str , shell : completest:: Shell ) -> Box < dyn completest:: Runtime > {
300- let shell_name = shell. name ( ) ;
309+ pub fn load_runtime < R : completest:: RuntimeBuilder > (
310+ context : & str ,
311+ name : & str ,
312+ ) -> Box < dyn completest:: Runtime >
313+ where
314+ <R as completest:: RuntimeBuilder >:: Runtime : ' static ,
315+ {
316+ let shell_name = R :: name ( ) ;
301317 let home = std:: path:: Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) )
302318 . join ( "tests/snapshots/home" )
319+ . join ( context)
303320 . join ( name)
304321 . join ( shell_name) ;
305- std:: fs:: create_dir_all ( & home) . unwrap ( ) ;
306- let scratch = snapbox:: path:: PathFixture :: immutable ( & home) ;
322+ let scratch = snapbox:: path:: PathFixture :: mutable_temp ( )
323+ . unwrap ( )
324+ . with_template ( & home)
325+ . unwrap ( ) ;
307326 let home = scratch. path ( ) . unwrap ( ) . to_owned ( ) ;
308327 println ! ( "Compiling" ) ;
309328 let manifest_path = std:: path:: Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "Cargo.toml" ) ;
@@ -313,11 +332,11 @@ pub fn load_runtime(name: &str, shell: completest::Shell) -> Box<dyn completest:
313332 println ! ( "Compiled" ) ;
314333 let bin_root = bin_path. parent ( ) . unwrap ( ) . to_owned ( ) ;
315334
316- let runtime = shell . with_home ( bin_root, home) . unwrap ( ) ;
335+ let runtime = R :: with_home ( bin_root, home) . unwrap ( ) ;
317336
318337 Box :: new ( ScratchRuntime {
319338 _scratch : scratch,
320- runtime,
339+ runtime : Box :: new ( runtime ) ,
321340 } )
322341}
323342
@@ -345,3 +364,56 @@ impl completest::Runtime for ScratchRuntime {
345364 Ok ( output)
346365 }
347366}
367+
368+ pub fn has_command ( command : & str ) -> bool {
369+ let output = match std:: process:: Command :: new ( command)
370+ . arg ( "--version" )
371+ . output ( )
372+ {
373+ Ok ( output) => output,
374+ Err ( e) => {
375+ // CI is expected to support all of the commands
376+ if is_ci ( ) && cfg ! ( linux) {
377+ panic ! (
378+ "expected command `{}` to be somewhere in PATH: {}" ,
379+ command, e
380+ ) ;
381+ }
382+ return false ;
383+ }
384+ } ;
385+ if !output. status . success ( ) {
386+ panic ! (
387+ "expected command `{}` to be runnable, got error {}:\n \
388+ stderr:{}\n \
389+ stdout:{}\n ",
390+ command,
391+ output. status,
392+ String :: from_utf8_lossy( & output. stderr) ,
393+ String :: from_utf8_lossy( & output. stdout)
394+ ) ;
395+ }
396+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
397+ println ! (
398+ "$ {command} --version
399+ {}" ,
400+ stdout
401+ ) ;
402+ if cfg ! ( target_os = "macos" ) && stdout. starts_with ( "GNU bash, version 3" ) {
403+ return false ;
404+ }
405+ if cfg ! ( target_os = "macos" ) && command == "zsh" {
406+ // HACK: At least on CI, the prompt override is not working
407+ return false ;
408+ }
409+
410+ true
411+ }
412+
413+ /// Whether or not this running in a Continuous Integration environment.
414+ fn is_ci ( ) -> bool {
415+ // Consider using `tracked_env` instead of option_env! when it is stabilized.
416+ // `tracked_env` will handle changes, but not require rebuilding the macro
417+ // itself like option_env does.
418+ option_env ! ( "CI" ) . is_some ( ) || option_env ! ( "TF_BUILD" ) . is_some ( )
419+ }
0 commit comments