@@ -52,7 +52,7 @@ fn main() {
5252}
5353
5454#[ allow( clippy:: print_stdout, clippy:: print_stderr) ]
55- async fn run ( opts : cli:: Options ) -> i32 {
55+ async fn run ( mut opts : cli:: Options ) -> i32 {
5656 let install_dir = match resolve_install_dir ( & opts) {
5757 Ok ( dir) => dir,
5858 Err ( e) => {
@@ -63,7 +63,7 @@ async fn run(opts: cli::Options) -> i32 {
6363 let install_dir_display = install_dir. as_path ( ) . to_string_lossy ( ) . to_string ( ) ;
6464
6565 if !opts. yes {
66- let proceed = show_interactive_menu ( & opts, & install_dir_display) ;
66+ let proceed = show_interactive_menu ( & mut opts, & install_dir_display) ;
6767 if !proceed {
6868 println ! ( "Installation cancelled." ) ;
6969 return 0 ;
@@ -170,6 +170,9 @@ async fn do_install(
170170 print_info ( "setting up Node.js version manager..." ) ;
171171 }
172172 install:: refresh_shims ( install_dir) . await ?;
173+ } else {
174+ // When skipping Node.js manager, still create shell env files
175+ create_env_files ( install_dir) . await ;
173176 }
174177
175178 if let Err ( e) = install:: cleanup_old_versions (
@@ -281,6 +284,25 @@ async fn download_with_progress(
281284 Ok ( data)
282285}
283286
287+ /// Create shell env files by spawning `vp env setup --env-only`.
288+ async fn create_env_files ( install_dir : & vite_path:: AbsolutePath ) {
289+ let vp_binary =
290+ install_dir. join ( "current" ) . join ( "bin" ) . join ( if cfg ! ( windows) { "vp.exe" } else { "vp" } ) ;
291+
292+ if !tokio:: fs:: try_exists ( & vp_binary) . await . unwrap_or ( false ) {
293+ return ;
294+ }
295+
296+ let output = tokio:: process:: Command :: new ( vp_binary. as_path ( ) )
297+ . args ( [ "env" , "setup" , "--env-only" ] )
298+ . output ( )
299+ . await ;
300+
301+ if let Err ( e) = output {
302+ tracing:: warn!( "Failed to create env files (non-fatal): {e}" ) ;
303+ }
304+ }
305+
284306fn resolve_install_dir ( opts : & cli:: Options ) -> Result < AbsolutePathBuf , Box < dyn std:: error:: Error > > {
285307 if let Some ( ref dir) = opts. install_dir {
286308 let path = std:: path:: PathBuf :: from ( dir) ;
@@ -312,44 +334,98 @@ fn modify_path(bin_dir: &str, quiet: bool) -> Result<(), Box<dyn std::error::Err
312334}
313335
314336#[ allow( clippy:: print_stdout) ]
315- fn show_interactive_menu ( opts : & cli:: Options , install_dir : & str ) -> bool {
316- let version = opts. version . as_deref ( ) . unwrap_or ( "latest" ) ;
317- let bin_dir = format ! ( "{install_dir}{sep}bin" , sep = std:: path:: MAIN_SEPARATOR ) ;
318-
319- println ! ( ) ;
320- println ! ( " {}" , "Welcome to Vite+ Installer!" . bold( ) ) ;
321- println ! ( ) ;
322- println ! ( " This will install the {} CLI and monorepo task runner." , "vp" . cyan( ) ) ;
323- println ! ( ) ;
324- println ! ( " Install directory: {}" , install_dir. cyan( ) ) ;
325- println ! (
326- " PATH modification: {}" ,
327- if opts. no_modify_path {
328- "no" . to_string( )
329- } else {
330- format!( "{bin_dir} \u{2192} User PATH" )
337+ fn show_interactive_menu ( opts : & mut cli:: Options , install_dir : & str ) -> bool {
338+ loop {
339+ let version = opts. version . as_deref ( ) . unwrap_or ( "latest" ) ;
340+ let bin_dir = format ! ( "{install_dir}{sep}bin" , sep = std:: path:: MAIN_SEPARATOR ) ;
341+
342+ println ! ( ) ;
343+ println ! ( " {}" , "Welcome to Vite+ Installer!" . bold( ) ) ;
344+ println ! ( ) ;
345+ println ! ( " This will install the {} CLI and monorepo task runner." , "vp" . cyan( ) ) ;
346+ println ! ( ) ;
347+ println ! ( " Install directory: {}" , install_dir. cyan( ) ) ;
348+ println ! (
349+ " PATH modification: {}" ,
350+ if opts. no_modify_path {
351+ "no" . to_string( )
352+ } else {
353+ format!( "{bin_dir} \u{2192} User PATH" )
354+ }
355+ . cyan( )
356+ ) ;
357+ println ! ( " Version: {}" , version. cyan( ) ) ;
358+ println ! (
359+ " Node.js manager: {}" ,
360+ if opts. no_node_manager { "disabled" } else { "auto-detect" } . cyan( )
361+ ) ;
362+ println ! ( ) ;
363+ println ! ( " 1) {} (default)" , "Proceed with installation" . bold( ) ) ;
364+ println ! ( " 2) Customize installation" ) ;
365+ println ! ( " 3) Cancel" ) ;
366+ println ! ( ) ;
367+
368+ let choice = read_input ( " > " ) ;
369+ match choice. as_str ( ) {
370+ "" | "1" => return true ,
371+ "2" => show_customize_menu ( opts) ,
372+ "3" => return false ,
373+ _ => {
374+ println ! ( " Invalid choice. Please enter 1, 2, or 3." ) ;
375+ }
331376 }
332- . cyan( )
333- ) ;
334- println ! ( " Version: {}" , version. cyan( ) ) ;
335- println ! (
336- " Node.js manager: {}" ,
337- if opts. no_node_manager { "disabled" } else { "auto-detect" } . cyan( )
338- ) ;
339- println ! ( ) ;
340- println ! ( " 1) {} (default)" , "Proceed with installation" . bold( ) ) ;
341- println ! ( " 2) Cancel" ) ;
342- println ! ( ) ;
343- print ! ( " > " ) ;
344- let _ = io:: stdout ( ) . flush ( ) ;
377+ }
378+ }
345379
346- let mut input = String :: new ( ) ;
347- if io:: stdin ( ) . read_line ( & mut input) . is_err ( ) {
348- return false ;
380+ #[ allow( clippy:: print_stdout) ]
381+ fn show_customize_menu ( opts : & mut cli:: Options ) {
382+ loop {
383+ let version_display = opts. version . as_deref ( ) . unwrap_or ( "latest" ) ;
384+ let registry_display = opts. registry . as_deref ( ) . unwrap_or ( "(default)" ) ;
385+
386+ println ! ( ) ;
387+ println ! ( " {}" , "Customize installation:" . bold( ) ) ;
388+ println ! ( ) ;
389+ println ! ( " 1) Version: [{}]" , version_display. cyan( ) ) ;
390+ println ! ( " 2) npm registry: [{}]" , registry_display. cyan( ) ) ;
391+ println ! (
392+ " 3) Node.js manager: [{}]" ,
393+ if opts. no_node_manager { "disabled" } else { "auto-detect" } . cyan( )
394+ ) ;
395+ println ! (
396+ " 4) Modify PATH: [{}]" ,
397+ if opts. no_modify_path { "no" } else { "yes" } . cyan( )
398+ ) ;
399+ println ! ( ) ;
400+
401+ let choice = read_input ( " Enter option number to change, or press Enter to go back: " ) ;
402+ match choice. as_str ( ) {
403+ "" => return ,
404+ "1" => {
405+ let v = read_input ( " Version (e.g. 0.3.0, or 'latest'): " ) ;
406+ if v == "latest" || v. is_empty ( ) {
407+ opts. version = None ;
408+ } else {
409+ opts. version = Some ( v) ;
410+ }
411+ }
412+ "2" => {
413+ let r = read_input ( " npm registry URL (or empty for default): " ) ;
414+ opts. registry = if r. is_empty ( ) { None } else { Some ( r) } ;
415+ }
416+ "3" => opts. no_node_manager = !opts. no_node_manager ,
417+ "4" => opts. no_modify_path = !opts. no_modify_path ,
418+ _ => println ! ( " Invalid option." ) ,
419+ }
349420 }
421+ }
350422
351- let choice = input. trim ( ) ;
352- choice. is_empty ( ) || choice == "1"
423+ fn read_input ( prompt : & str ) -> String {
424+ print ! ( "{prompt}" ) ;
425+ let _ = io:: stdout ( ) . flush ( ) ;
426+ let mut input = String :: new ( ) ;
427+ let _ = io:: stdin ( ) . read_line ( & mut input) ;
428+ input. trim ( ) . to_string ( )
353429}
354430
355431#[ allow( clippy:: print_stdout) ]
0 commit comments