Skip to content

Commit cde1b52

Browse files
aignasrickeylev
andauthored
fix(gazelle): make cmd.Wait more idiomatic (#1550)
It seems that the documentation for the `cmd.Wait` explicitly asks the users to not wait on the command immediately after starting because it may close pipes too early and cause unintended side-effects as described in #1546. Fixes #1546. Co-authored-by: Richard Levasseur <rlevasseur@google.com>
1 parent 679ba7c commit cde1b52

File tree

3 files changed

+24
-25
lines changed

3 files changed

+24
-25
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ Breaking changes:
9797
* (gazelle) Generate a single `py_test` target when `gazelle:python_generation_mode project`
9898
is used.
9999

100+
* (gazelle) Move waiting for the Python interpreter process to exit to the shutdown hook
101+
to make the usage of the `exec.Command` more idiomatic.
102+
100103
* (toolchains) Keep tcl subdirectory in Windows build of hermetic interpreter.
101104

102105
* (bzlmod) sub-modules now don't have the `//conditions:default` clause in the

gazelle/python/parser.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
)
3333

3434
var (
35+
parserCmd *exec.Cmd
3536
parserStdin io.WriteCloser
3637
parserStdout io.Reader
3738
parserMutex sync.Mutex
@@ -40,40 +41,37 @@ var (
4041
func startParserProcess(ctx context.Context) {
4142
// due to #691, we need a system interpreter to boostrap, part of which is
4243
// to locate the hermetic interpreter.
43-
cmd := exec.CommandContext(ctx, "python3", helperPath, "parse")
44-
cmd.Stderr = os.Stderr
44+
parserCmd = exec.CommandContext(ctx, "python3", helperPath, "parse")
45+
parserCmd.Stderr = os.Stderr
4546

46-
stdin, err := cmd.StdinPipe()
47+
stdin, err := parserCmd.StdinPipe()
4748
if err != nil {
4849
log.Printf("failed to initialize parser: %v\n", err)
4950
os.Exit(1)
5051
}
5152
parserStdin = stdin
5253

53-
stdout, err := cmd.StdoutPipe()
54+
stdout, err := parserCmd.StdoutPipe()
5455
if err != nil {
5556
log.Printf("failed to initialize parser: %v\n", err)
5657
os.Exit(1)
5758
}
5859
parserStdout = stdout
5960

60-
if err := cmd.Start(); err != nil {
61+
if err := parserCmd.Start(); err != nil {
6162
log.Printf("failed to initialize parser: %v\n", err)
6263
os.Exit(1)
6364
}
64-
65-
go func() {
66-
if err := cmd.Wait(); err != nil {
67-
log.Printf("failed to wait for parser: %v\n", err)
68-
os.Exit(1)
69-
}
70-
}()
7165
}
7266

7367
func shutdownParserProcess() {
7468
if err := parserStdin.Close(); err != nil {
7569
fmt.Fprintf(os.Stderr, "error closing parser: %v", err)
7670
}
71+
72+
if err := parserCmd.Wait(); err != nil {
73+
log.Printf("failed to wait for parser: %v\n", err)
74+
}
7775
}
7876

7977
// python3Parser implements a parser for Python files that extracts the modules

gazelle/python/std_modules.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
)
3030

3131
var (
32+
stdModulesCmd *exec.Cmd
3233
stdModulesStdin io.WriteCloser
3334
stdModulesStdout io.Reader
3435
stdModulesMutex sync.Mutex
@@ -40,42 +41,39 @@ func startStdModuleProcess(ctx context.Context) {
4041

4142
// due to #691, we need a system interpreter to boostrap, part of which is
4243
// to locate the hermetic interpreter.
43-
cmd := exec.CommandContext(ctx, "python3", helperPath, "std_modules")
44-
cmd.Stderr = os.Stderr
44+
stdModulesCmd = exec.CommandContext(ctx, "python3", helperPath, "std_modules")
45+
stdModulesCmd.Stderr = os.Stderr
4546
// All userland site-packages should be ignored.
46-
cmd.Env = []string{"PYTHONNOUSERSITE=1"}
47+
stdModulesCmd.Env = []string{"PYTHONNOUSERSITE=1"}
4748

48-
stdin, err := cmd.StdinPipe()
49+
stdin, err := stdModulesCmd.StdinPipe()
4950
if err != nil {
5051
log.Printf("failed to initialize std_modules: %v\n", err)
5152
os.Exit(1)
5253
}
5354
stdModulesStdin = stdin
5455

55-
stdout, err := cmd.StdoutPipe()
56+
stdout, err := stdModulesCmd.StdoutPipe()
5657
if err != nil {
5758
log.Printf("failed to initialize std_modules: %v\n", err)
5859
os.Exit(1)
5960
}
6061
stdModulesStdout = stdout
6162

62-
if err := cmd.Start(); err != nil {
63+
if err := stdModulesCmd.Start(); err != nil {
6364
log.Printf("failed to initialize std_modules: %v\n", err)
6465
os.Exit(1)
6566
}
66-
67-
go func() {
68-
if err := cmd.Wait(); err != nil {
69-
log.Printf("failed to wait for std_modules: %v\n", err)
70-
os.Exit(1)
71-
}
72-
}()
7367
}
7468

7569
func shutdownStdModuleProcess() {
7670
if err := stdModulesStdin.Close(); err != nil {
7771
fmt.Fprintf(os.Stderr, "error closing std module: %v", err)
7872
}
73+
74+
if err := stdModulesCmd.Wait(); err != nil {
75+
log.Printf("failed to wait for std_modules: %v\n", err)
76+
}
7977
}
8078

8179
func isStdModule(m module) (bool, error) {

0 commit comments

Comments
 (0)