88 "path/filepath"
99 "runtime"
1010 "strings"
11+
12+ "io"
1113)
1214
1315// BuildPythonProgramOptions are options for BuildPythonProgram.
@@ -28,6 +30,9 @@ type BuildPythonProgramOptions struct {
2830 // If present, applied to build commands before run. May be called multiple
2931 // times for a single build.
3032 ApplyToCommand func (context.Context , * exec.Cmd ) error
33+ // If present, custom writers that will capture stdout/stderr.
34+ Stdout io.Writer
35+ Stderr io.Writer
3136}
3237
3338// PythonProgram is a Python-specific implementation of Program.
@@ -71,7 +76,7 @@ func BuildPythonProgram(ctx context.Context, options BuildPythonProgramOptions)
7176 executeCommand := func (name string , args ... string ) error {
7277 cmd := exec .CommandContext (ctx , name , args ... )
7378 cmd .Dir = dir
74- cmd . Stdin , cmd .Stdout , cmd .Stderr = os . Stdin , os . Stdout , os . Stderr
79+ setupCommandIO ( cmd , options .Stdout , options .Stderr )
7580 if options .ApplyToCommand != nil {
7681 if err := options .ApplyToCommand (ctx , cmd ); err != nil {
7782 return err
@@ -96,7 +101,7 @@ requires-python = "~=3.9"
96101 executeCommand ("uv" , "add" , options .VersionFromPyProj )
97102 } else if strings .ContainsAny (options .Version , `/\` ) {
98103 // It's a path; install from wheel
99- wheel , err := getWheel (ctx , options .Version )
104+ wheel , err := getWheel (ctx , options .Version , options . Stdout , options . Stderr )
100105 if err != nil {
101106 return nil , err
102107 }
@@ -115,7 +120,7 @@ requires-python = "~=3.9"
115120 return & PythonProgram {dir }, nil
116121}
117122
118- func getWheel (ctx context.Context , version string ) (string , error ) {
123+ func getWheel (ctx context.Context , version string , stdout , stderr io. Writer ) (string , error ) {
119124 // We expect a dist/ directory with a single whl file present
120125 sdkPath , err := filepath .Abs (version )
121126 if err != nil {
@@ -132,13 +137,13 @@ getWheels:
132137 // Try to build the project
133138 cmd := exec .CommandContext (ctx , "uv" , "sync" )
134139 cmd .Dir = sdkPath
135- cmd . Stdin , cmd . Stdout , cmd . Stderr = os . Stdin , os . Stdout , os . Stderr
140+ setupCommandIO ( cmd , stdout , stderr )
136141 if err := cmd .Run (); err != nil {
137142 return "" , fmt .Errorf ("problem installing deps when building sdk by path: %w" , err )
138143 }
139144 cmd = exec .CommandContext (ctx , "uv" , "build" )
140145 cmd .Dir = sdkPath
141- cmd . Stdin , cmd . Stdout , cmd . Stderr = os . Stdin , os . Stdout , os . Stderr
146+ setupCommandIO ( cmd , stdout , stderr )
142147 if err := cmd .Run (); err != nil {
143148 return "" , fmt .Errorf ("problem building sdk by path: %w" , err )
144149 }
@@ -181,6 +186,6 @@ func (p *PythonProgram) NewCommand(ctx context.Context, args ...string) (*exec.C
181186 args = append ([]string {"run" , "python" , "-m" }, args ... )
182187 cmd := exec .CommandContext (ctx , "uv" , args ... )
183188 cmd .Dir = p .dir
184- cmd . Stdin , cmd . Stdout , cmd . Stderr = os . Stdin , os . Stdout , os . Stderr
189+ setupCommandIO ( cmd , nil , nil )
185190 return cmd , nil
186191}
0 commit comments