@@ -76,26 +76,75 @@ func MakeDefaultConfig() config.Config {
76
76
}
77
77
78
78
// RunBazelisk runs the main Bazelisk logic for the given arguments and Bazel repositories.
79
+ //
80
+ // This will run Bazel in a subprocess and return its exit code.
79
81
func RunBazelisk (args []string , repos * Repositories ) (int , error ) {
80
82
return RunBazeliskWithArgsFunc (func (_ string ) []string { return args }, repos )
81
83
}
82
84
83
85
// RunBazeliskWithArgsFunc runs the main Bazelisk logic for the given ArgsFunc and Bazel
84
86
// repositories.
87
+ //
88
+ // This will run Bazel in a subprocess and return its exit code.
85
89
func RunBazeliskWithArgsFunc (argsFunc ArgsFunc , repos * Repositories ) (int , error ) {
86
-
87
90
return RunBazeliskWithArgsFuncAndConfig (argsFunc , repos , MakeDefaultConfig ())
88
91
}
89
92
90
93
// RunBazeliskWithArgsFuncAndConfig runs the main Bazelisk logic for the given ArgsFunc and Bazel
91
94
// repositories and config.
95
+ //
96
+ // This will run Bazel in a subprocess and return its exit code.
92
97
func RunBazeliskWithArgsFuncAndConfig (argsFunc ArgsFunc , repos * Repositories , config config.Config ) (int , error ) {
93
98
return RunBazeliskWithArgsFuncAndConfigAndOut (argsFunc , repos , config , nil )
94
99
}
95
100
96
101
// RunBazeliskWithArgsFuncAndConfigAndOut runs the main Bazelisk logic for the given ArgsFunc and Bazel
97
102
// repositories and config, writing its stdout to the passed writer.
103
+ //
104
+ // This will run Bazel in a subprocess and return its exit code.
98
105
func RunBazeliskWithArgsFuncAndConfigAndOut (argsFunc ArgsFunc , repos * Repositories , config config.Config , out io.Writer ) (int , error ) {
106
+ return RunOrExecBazeliskWithArgsFuncAndConfigAndOut (argsFunc , repos , config , out , false )
107
+ }
108
+
109
+ // ExecBazelisk runs the main Bazelisk logic for the given arguments and Bazel repositories.
110
+ //
111
+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
112
+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
113
+ // code.
114
+ func ExecBazelisk (args []string , repos * Repositories ) (int , error ) {
115
+ return ExecBazeliskWithArgsFunc (func (_ string ) []string { return args }, repos )
116
+ }
117
+
118
+ // ExecBazeliskWithArgsFunc runs the main Bazelisk logic for the given ArgsFunc and Bazel
119
+ // repositories.
120
+ //
121
+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
122
+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
123
+ // code.
124
+ func ExecBazeliskWithArgsFunc (argsFunc ArgsFunc , repos * Repositories ) (int , error ) {
125
+ return ExecBazeliskWithArgsFuncAndConfig (argsFunc , repos , MakeDefaultConfig ())
126
+ }
127
+
128
+ // ExecBazeliskWithArgsFuncAndConfig runs the main Bazelisk logic for the given ArgsFunc and Bazel
129
+ // repositories and config.
130
+ //
131
+ // If possible (i.e. on non-Windows platforms), this will replace the current process with Bazel
132
+ // and will not return. On Windows, this will execute Bazel in a new process and return its exit
133
+ // code.
134
+ func ExecBazeliskWithArgsFuncAndConfig (argsFunc ArgsFunc , repos * Repositories , config config.Config ) (int , error ) {
135
+ return RunOrExecBazeliskWithArgsFuncAndConfigAndOut (argsFunc , repos , config , nil , true )
136
+ }
137
+
138
+ // RunOrExecBazeliskWithArgsFuncAndConfigAndOut runs the main Bazelisk logic for the given ArgsFunc and Bazel
139
+ // repositories and config.
140
+ //
141
+ // If exec is true, this will replace the current process with Bazel and will not return (this is
142
+ // not possible on Windows; on Windows this will execute Bazel in a new process and return its exit
143
+ // code even if exec is true). `out` is not supported in exec mode.
144
+ //
145
+ // If exec is false, this will run Bazel in a subprocess and return its exit code, writing its stdout
146
+ // to the passed writer if provided.
147
+ func RunOrExecBazeliskWithArgsFuncAndConfigAndOut (argsFunc ArgsFunc , repos * Repositories , config config.Config , out io.Writer , bool exec ) (int , error ) {
99
148
httputil .UserAgent = getUserAgent (config )
100
149
101
150
bazelInstallation , err := GetBazelInstallation (repos , config )
@@ -108,8 +157,8 @@ func RunBazeliskWithArgsFuncAndConfigAndOut(argsFunc ArgsFunc, repos *Repositori
108
157
// --print_env must be the first argument.
109
158
if len (args ) > 0 && args [0 ] == "--print_env" {
110
159
// print environment variables for sub-processes
111
- cmd := makeBazelCmd (bazelInstallation .Path , args , nil , config )
112
- for _ , val := range cmd . Env {
160
+ _ , _ , env := makeBazelCmd (bazelInstallation .Path , args , config )
161
+ for _ , val := range env {
113
162
fmt .Println (val )
114
163
}
115
164
return 0 , nil
@@ -161,11 +210,22 @@ func RunBazeliskWithArgsFuncAndConfigAndOut(argsFunc ArgsFunc, repos *Repositori
161
210
}
162
211
}
163
212
164
- exitCode , err := runBazel (bazelInstallation .Path , args , out , config )
165
- if err != nil {
166
- return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
213
+ if exec {
214
+ if out != nil {
215
+ return - 1 , fmt .Errorf ("cannot run bazelisk in exec mode with a non-nil output writer" )
216
+ }
217
+ exitCode , err := execBazel (bazelInstallation .Path , args , config )
218
+ if err != nil {
219
+ return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
220
+ }
221
+ return exitCode , nil
222
+ } else {
223
+ exitCode , err := runBazel (bazelInstallation .Path , args , out , config )
224
+ if err != nil {
225
+ return - 1 , fmt .Errorf ("could not run Bazel: %v" , err )
226
+ }
227
+ return exitCode , nil
167
228
}
168
- return exitCode , nil
169
229
}
170
230
171
231
func isVersionCommand (args []string ) (result bool , gnuFormat bool ) {
@@ -636,50 +696,68 @@ func maybeDelegateToWrapper(bazel string, config config.Config) string {
636
696
return maybeDelegateToWrapperFromDir (bazel , wd , config )
637
697
}
638
698
639
- func prependDirToPathList (cmd * exec. Cmd , dir string ) {
699
+ func prependDirToPathList (env [] string , dir string ) {
640
700
found := false
641
- for idx , val := range cmd . Env {
701
+ for idx , val := range env {
642
702
splits := strings .Split (val , "=" )
643
703
if len (splits ) != 2 {
644
704
continue
645
705
}
646
706
if strings .EqualFold (splits [0 ], "PATH" ) {
647
707
found = true
648
- cmd . Env [idx ] = fmt .Sprintf ("PATH=%s%s%s" , dir , string (os .PathListSeparator ), splits [1 ])
708
+ env [idx ] = fmt .Sprintf ("PATH=%s%s%s" , dir , string (os .PathListSeparator ), splits [1 ])
649
709
break
650
710
}
651
711
}
652
712
653
713
if ! found {
654
- cmd . Env = append (cmd . Env , fmt .Sprintf ("PATH=%s" , dir ))
714
+ env = append (env , fmt .Sprintf ("PATH=%s" , dir ))
655
715
}
656
716
}
657
717
658
- func makeBazelCmd (bazel string , args []string , out io. Writer , config config.Config ) * exec. Cmd {
718
+ func makeBazelCmd (bazel string , args []string , config config.Config ) ( string , [] string , [] string ) {
659
719
execPath := maybeDelegateToWrapper (bazel , config )
660
720
661
- cmd := exec .Command (execPath , args ... )
662
- cmd .Env = append (os .Environ (), skipWrapperEnv + "=true" )
721
+ env := append (os .Environ (), skipWrapperEnv + "=true" )
663
722
if execPath != bazel {
664
- cmd . Env = append (cmd . Env , fmt .Sprintf ("%s=%s" , bazelReal , bazel ))
723
+ env = append (env , fmt .Sprintf ("%s=%s" , bazelReal , bazel ))
665
724
}
666
725
selfPath , err := os .Executable ()
667
726
if err != nil {
668
- cmd . Env = append (cmd . Env , bazeliskEnv + "=" + selfPath )
727
+ env = append (env , bazeliskEnv + "=" + selfPath )
669
728
}
670
- prependDirToPathList (cmd , filepath .Dir (execPath ))
729
+ prependDirToPathList (env , filepath .Dir (execPath ))
730
+
731
+ commandLine := []string {execPath }
732
+ commandLine = append (commandLine , args ... )
733
+ return execPath , commandLine , env
734
+ }
735
+
736
+ func execBazel (bazel string , args []string , config config.Config ) (int , error ) {
737
+ if runtime .GOOS == "windows" {
738
+ // syscall.Exec is not supported on windows
739
+ return runBazel (bazel , args , nil , config )
740
+ }
741
+
742
+ execPath , args , env := makeBazelCmd (bazel , args , config )
743
+
744
+ err := syscall .Exec (execPath , args , env )
745
+ return 1 , fmt .Errorf ("could not start Bazel: %v" , err )
746
+ }
747
+
748
+ func runBazel (bazel string , args []string , out io.Writer , config config.Config ) (int , error ) {
749
+ execPath , commandLine , env := makeBazelCmd (bazel , args , config )
750
+
751
+ cmd := exec .Command (execPath , commandLine [1 :]... )
752
+ cmd .Env = env
671
753
cmd .Stdin = os .Stdin
672
754
if out == nil {
673
755
cmd .Stdout = os .Stdout
674
756
} else {
675
757
cmd .Stdout = out
676
758
}
677
759
cmd .Stderr = os .Stderr
678
- return cmd
679
- }
680
760
681
- func runBazel (bazel string , args []string , out io.Writer , config config.Config ) (int , error ) {
682
- cmd := makeBazelCmd (bazel , args , out , config )
683
761
err := cmd .Start ()
684
762
if err != nil {
685
763
return 1 , fmt .Errorf ("could not start Bazel: %v" , err )
0 commit comments