@@ -76,25 +76,41 @@ func MakeDefaultConfig() config.Config {
7676}
7777
7878// RunBazelisk runs the main Bazelisk logic for the given arguments and Bazel repositories.
79+ //
80+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
81+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
82+ // code.
7983func RunBazelisk (args []string , repos * Repositories ) (int , error ) {
8084 return RunBazeliskWithArgsFunc (func (_ string ) []string { return args }, repos )
8185}
8286
8387// RunBazeliskWithArgsFunc runs the main Bazelisk logic for the given ArgsFunc and Bazel
8488// repositories.
89+ //
90+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
91+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
92+ // code.
8593func RunBazeliskWithArgsFunc (argsFunc ArgsFunc , repos * Repositories ) (int , error ) {
8694
8795 return RunBazeliskWithArgsFuncAndConfig (argsFunc , repos , MakeDefaultConfig ())
8896}
8997
9098// RunBazeliskWithArgsFuncAndConfig runs the main Bazelisk logic for the given ArgsFunc and Bazel
9199// repositories and config.
100+ //
101+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
102+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
103+ // code.
92104func RunBazeliskWithArgsFuncAndConfig (argsFunc ArgsFunc , repos * Repositories , config config.Config ) (int , error ) {
93105 return RunBazeliskWithArgsFuncAndConfigAndOut (argsFunc , repos , config , nil )
94106}
95107
96108// RunBazeliskWithArgsFuncAndConfigAndOut runs the main Bazelisk logic for the given ArgsFunc and Bazel
97109// repositories and config, writing its stdout to the passed writer.
110+ //
111+ // If possible (i.e. on non-Windows platforms when `out` is nil), this will replace the current
112+ // process with Bazel and will not return. If that's not possible, this will execute Bazel in a new
113+ // process and return its exit code.
98114func RunBazeliskWithArgsFuncAndConfigAndOut (argsFunc ArgsFunc , repos * Repositories , config config.Config , out io.Writer ) (int , error ) {
99115 httputil .UserAgent = getUserAgent (config )
100116
@@ -108,8 +124,8 @@ func RunBazeliskWithArgsFuncAndConfigAndOut(argsFunc ArgsFunc, repos *Repositori
108124 // --print_env must be the first argument.
109125 if len (args ) > 0 && args [0 ] == "--print_env" {
110126 // print environment variables for sub-processes
111- cmd := makeBazelCmd (bazelInstallation .Path , args , nil , config )
112- for _ , val := range cmd . Env {
127+ _ , _ , env := makeBazelCmd (bazelInstallation .Path , args , config )
128+ for _ , val := range env {
113129 fmt .Println (val )
114130 }
115131 return 0 , nil
@@ -161,11 +177,19 @@ func RunBazeliskWithArgsFuncAndConfigAndOut(argsFunc ArgsFunc, repos *Repositori
161177 }
162178 }
163179
164- exitCode , err := runBazel (bazelInstallation .Path , args , out , config )
165- if err != nil {
166- return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
180+ if out == nil {
181+ exitCode , err := execBazel (bazelInstallation .Path , args , config )
182+ if err != nil {
183+ return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
184+ }
185+ return exitCode , nil
186+ } else {
187+ exitCode , err := runBazel (bazelInstallation .Path , args , out , config )
188+ if err != nil {
189+ return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
190+ }
191+ return exitCode , nil
167192 }
168- return exitCode , nil
169193}
170194
171195func isVersionCommand (args []string ) (result bool , gnuFormat bool ) {
@@ -636,50 +660,68 @@ func maybeDelegateToWrapper(bazel string, config config.Config) string {
636660 return maybeDelegateToWrapperFromDir (bazel , wd , config )
637661}
638662
639- func prependDirToPathList (cmd * exec. Cmd , dir string ) {
663+ func prependDirToPathList (env [] string , dir string ) {
640664 found := false
641- for idx , val := range cmd . Env {
665+ for idx , val := range env {
642666 splits := strings .Split (val , "=" )
643667 if len (splits ) != 2 {
644668 continue
645669 }
646670 if strings .EqualFold (splits [0 ], "PATH" ) {
647671 found = true
648- cmd . Env [idx ] = fmt .Sprintf ("PATH=%s%s%s" , dir , string (os .PathListSeparator ), splits [1 ])
672+ env [idx ] = fmt .Sprintf ("PATH=%s%s%s" , dir , string (os .PathListSeparator ), splits [1 ])
649673 break
650674 }
651675 }
652676
653677 if ! found {
654- cmd . Env = append (cmd . Env , fmt .Sprintf ("PATH=%s" , dir ))
678+ env = append (env , fmt .Sprintf ("PATH=%s" , dir ))
655679 }
656680}
657681
658- func makeBazelCmd (bazel string , args []string , out io. Writer , config config.Config ) * exec. Cmd {
682+ func makeBazelCmd (bazel string , args []string , config config.Config ) ( string , [] string , [] string ) {
659683 execPath := maybeDelegateToWrapper (bazel , config )
660684
661- cmd := exec .Command (execPath , args ... )
662- cmd .Env = append (os .Environ (), skipWrapperEnv + "=true" )
685+ env := append (os .Environ (), skipWrapperEnv + "=true" )
663686 if execPath != bazel {
664- cmd . Env = append (cmd . Env , fmt .Sprintf ("%s=%s" , bazelReal , bazel ))
687+ env = append (env , fmt .Sprintf ("%s=%s" , bazelReal , bazel ))
665688 }
666689 selfPath , err := os .Executable ()
667690 if err != nil {
668- cmd . Env = append (cmd . Env , bazeliskEnv + "=" + selfPath )
691+ env = append (env , bazeliskEnv + "=" + selfPath )
669692 }
670- prependDirToPathList (cmd , filepath .Dir (execPath ))
693+ prependDirToPathList (env , filepath .Dir (execPath ))
694+
695+ commandLine := []string {execPath }
696+ commandLine = append (commandLine , args ... )
697+ return execPath , commandLine , env
698+ }
699+
700+ func execBazel (bazel string , args []string , config config.Config ) (int , error ) {
701+ if runtime .GOOS == "windows" {
702+ // syscall.Exec is not supported on windows
703+ return runBazel (bazel , args , nil , config )
704+ }
705+
706+ execPath , args , env := makeBazelCmd (bazel , args , config )
707+
708+ err := syscall .Exec (execPath , args , env )
709+ return 1 , fmt .Errorf ("could not start Bazel: %v" , err )
710+ }
711+
712+ func runBazel (bazel string , args []string , out io.Writer , config config.Config ) (int , error ) {
713+ execPath , commandLine , env := makeBazelCmd (bazel , args , config )
714+
715+ cmd := exec .Command (execPath , commandLine [1 :]... )
716+ cmd .Env = env
671717 cmd .Stdin = os .Stdin
672718 if out == nil {
673719 cmd .Stdout = os .Stdout
674720 } else {
675721 cmd .Stdout = out
676722 }
677723 cmd .Stderr = os .Stderr
678- return cmd
679- }
680724
681- func runBazel (bazel string , args []string , out io.Writer , config config.Config ) (int , error ) {
682- cmd := makeBazelCmd (bazel , args , out , config )
683725 err := cmd .Start ()
684726 if err != nil {
685727 return 1 , fmt .Errorf ("could not start Bazel: %v" , err )
0 commit comments