Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 00185f9

Browse files
SG start bazel enhancements (#59718)
* WIP draft * cleanup * added output buffering * fixed process exiting (I think) * added bazel run targets * ran go mod tidy and gazelle * WIP draft * cleanup * added output buffering * fixed process exiting (I think) * added bazel run targets * ran go mod tidy and gazelle * fixed installing progress bar render issue * Removed closes that were causing race conditions * logging extracted from ibazel output * only log first and relevant errors * removed slow testing command
1 parent 48fdc63 commit 00185f9

21 files changed

+1405
-983
lines changed

.bazel_fix_commands.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1-
[]
1+
[
2+
{
3+
"regex": "^Check that imports in Go sources match importpath attributes in deps.$",
4+
"command": "./dev/bazel_configure_accept_changes.sh",
5+
"args": []
6+
},
7+
{
8+
"regex": "missing input file",
9+
"command": "./dev/bazel_configure_accept_changes.sh",
10+
"args": []
11+
},
12+
{
13+
"regex": ": undefined:",
14+
"command": "./dev/bazel_configure_accept_changes.sh",
15+
"args": []
16+
}
17+
]

deps.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,8 +4201,8 @@ def go_dependencies():
42014201
name = "com_github_nxadm_tail",
42024202
build_file_proto_mode = "disable_global",
42034203
importpath = "github.com/nxadm/tail",
4204-
sum = "h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=",
4205-
version = "v1.4.8",
4204+
sum = "h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=",
4205+
version = "v1.4.11",
42064206
)
42074207
go_repository(
42084208
name = "com_github_nytimes_gziphandler",

dev/bazel_configure_accept_changes.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#! /bin/bash
2+
3+
# Run bazel configure and if the error code is 110, exit with error code 0
4+
# This is because 110 means that configuration files were successfully
5+
# Can be used by processes which want to run configuration as an auto-fix
6+
# and expect a 0 exit code
7+
bazel configure
8+
exit_code=$?
9+
10+
if [ $exit_code -eq 0 ]; then
11+
echo "No configuration changes made"
12+
exit 0
13+
elif [ $exit_code -eq 110 ]; then
14+
echo "Bazel configuration completed"
15+
exit 0
16+
else
17+
echo "Unknown error"
18+
exit $exit_code
19+
fi

dev/sg/internal/run/BUILD.bazel

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
load("//dev:go_defs.bzl", "go_test")
21
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
load("//dev:go_defs.bzl", "go_test")
33

44
go_library(
55
name = "run",
66
srcs = [
7-
"bazel_build.go",
87
"bazel_command.go",
98
"command.go",
109
"helpers.go",
1110
"ibazel.go",
11+
"installer.go",
1212
"logger.go",
1313
"pid.go",
1414
"prefix_suffix_saver.go",
1515
"run.go",
16-
"run_bazel.go",
16+
"sgconfig_command.go",
1717
],
1818
importpath = "github.com/sourcegraph/sourcegraph/dev/sg/internal/run",
1919
visibility = ["//dev/sg:__subpackages__"],
@@ -28,9 +28,9 @@ go_library(
2828
"//lib/output",
2929
"//lib/process",
3030
"@com_github_grafana_regexp//:regexp",
31+
"@com_github_nxadm_tail//:tail",
3132
"@com_github_rjeczalik_notify//:notify",
3233
"@com_github_sourcegraph_conc//pool",
33-
"@org_golang_x_sync//semaphore",
3434
],
3535
)
3636

dev/sg/internal/run/bazel_build.go

Lines changed: 0 additions & 64 deletions
This file was deleted.

dev/sg/internal/run/bazel_command.go

Lines changed: 78 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -3,150 +3,123 @@ package run
33
import (
44
"context"
55
"fmt"
6-
"io"
76
"os/exec"
7+
"strings"
88

99
"github.com/rjeczalik/notify"
10+
1011
"github.com/sourcegraph/sourcegraph/dev/sg/internal/secrets"
11-
"github.com/sourcegraph/sourcegraph/dev/sg/internal/std"
12-
"github.com/sourcegraph/sourcegraph/lib/errors"
13-
"github.com/sourcegraph/sourcegraph/lib/output"
14-
"github.com/sourcegraph/sourcegraph/lib/process"
1512
)
1613

1714
// A BazelCommand is a command definition for sg run/start that uses
1815
// bazel under the hood. It will handle restarting itself autonomously,
1916
// as long as iBazel is running and watch that specific target.
2017
type BazelCommand struct {
21-
Name string
22-
Description string `yaml:"description"`
23-
Target string `yaml:"target"`
24-
Args string `yaml:"args"`
25-
PreCmd string `yaml:"precmd"`
26-
Env map[string]string `yaml:"env"`
27-
IgnoreStdout bool `yaml:"ignoreStdout"`
28-
IgnoreStderr bool `yaml:"ignoreStderr"`
18+
Name string
19+
Description string `yaml:"description"`
20+
Target string `yaml:"target"`
21+
Args string `yaml:"args"`
22+
PreCmd string `yaml:"precmd"`
23+
Env map[string]string `yaml:"env"`
24+
IgnoreStdout bool `yaml:"ignoreStdout"`
25+
IgnoreStderr bool `yaml:"ignoreStderr"`
26+
ContinueWatchOnExit bool `yaml:"continueWatchOnExit"`
27+
// Preamble is a short and visible message, displayed when the command is launched.
28+
Preamble string `yaml:"preamble"`
2929
ExternalSecrets map[string]secrets.ExternalSecret `yaml:"external_secrets"`
30-
}
3130

32-
func (bc *BazelCommand) BinLocation() (string, error) {
33-
return binLocation(bc.Target)
31+
// RunTarget specifies a target that should be run via `bazel run $RunTarget` instead of directly executing the binary.
32+
RunTarget string `yaml:"runTarget"`
3433
}
3534

36-
func (bc *BazelCommand) watch(ctx context.Context) (<-chan struct{}, error) {
37-
// Grab the location of the binary in bazel-out.
38-
binLocation, err := bc.BinLocation()
39-
if err != nil {
40-
return nil, err
41-
}
35+
func (bc BazelCommand) GetName() string {
36+
return bc.Name
37+
}
4238

43-
// Set up the watcher.
44-
restart := make(chan struct{})
45-
events := make(chan notify.EventInfo, 1)
46-
if err := notify.Watch(binLocation, events, notify.All); err != nil {
47-
return nil, err
48-
}
39+
func (bc BazelCommand) GetContinueWatchOnExit() bool {
40+
return bc.ContinueWatchOnExit
41+
}
4942

50-
// Start watching for a freshly compiled version of the binary.
51-
go func() {
52-
defer close(events)
53-
defer notify.Stop(events)
54-
55-
for {
56-
select {
57-
case <-ctx.Done():
58-
return
59-
case e := <-events:
60-
if e.Event() != notify.Remove {
61-
restart <- struct{}{}
62-
}
63-
}
43+
func (bc BazelCommand) GetEnv() map[string]string {
44+
return bc.Env
45+
}
6446

65-
}
66-
}()
47+
func (bc BazelCommand) GetIgnoreStdout() bool {
48+
return bc.IgnoreStdout
49+
}
6750

68-
return restart, nil
51+
func (bc BazelCommand) GetIgnoreStderr() bool {
52+
return bc.IgnoreStderr
6953
}
7054

71-
func (bc *BazelCommand) Start(ctx context.Context, dir string, parentEnv map[string]string) error {
72-
std.Out.WriteLine(output.Styledf(output.StylePending, "Running %s...", bc.Name))
55+
func (bc BazelCommand) GetPreamble() string {
56+
return bc.Preamble
57+
}
7358

74-
// Run the binary for the first time.
75-
cancel, err := bc.start(ctx, dir, parentEnv)
59+
func (bc BazelCommand) GetBinaryLocation() (string, error) {
60+
baseOutput, err := outputPath()
7661
if err != nil {
77-
return errors.Wrapf(err, "failed to start Bazel command %q", bc.Name)
62+
return "", err
7863
}
64+
// Trim "bazel-out" because the next bazel query will include it.
65+
outputPath := strings.TrimSuffix(strings.TrimSpace(string(baseOutput)), "bazel-out")
7966

80-
// Restart when the binary change.
81-
wantRestart, err := bc.watch(ctx)
67+
// Get the binary from the specific target.
68+
cmd := exec.Command("bazel", "cquery", bc.Target, "--output=files")
69+
baseOutput, err = cmd.Output()
8270
if err != nil {
83-
return err
71+
return "", err
8472
}
73+
binPath := strings.TrimSpace(string(baseOutput))
8574

86-
// Wait forever until we're asked to stop or that restarting returns an error.
87-
for {
88-
select {
89-
case <-ctx.Done():
90-
return ctx.Err()
91-
case <-wantRestart:
92-
std.Out.WriteLine(output.Styledf(output.StylePending, "Restarting %s...", bc.Name))
93-
cancel()
94-
cancel, err = bc.start(ctx, dir, parentEnv)
95-
if err != nil {
96-
return err
97-
}
98-
}
99-
}
75+
return fmt.Sprintf("%s%s", outputPath, binPath), nil
10076
}
10177

102-
func (bc *BazelCommand) start(ctx context.Context, dir string, parentEnv map[string]string) (func(), error) {
103-
binLocation, err := bc.BinLocation()
104-
if err != nil {
105-
return nil, err
106-
}
78+
func (bc BazelCommand) GetExternalSecrets() map[string]secrets.ExternalSecret {
79+
return bc.ExternalSecrets
80+
}
10781

108-
sc := &startedCmd{
109-
stdoutBuf: &prefixSuffixSaver{N: 32 << 10},
110-
stderrBuf: &prefixSuffixSaver{N: 32 << 10},
82+
func (bc BazelCommand) watchPaths() ([]string, error) {
83+
// If no target is defined, there is nothing to be built and watched
84+
if bc.Target == "" {
85+
return nil, nil
11186
}
112-
113-
commandCtx, cancel := context.WithCancel(ctx)
114-
sc.cancel = cancel
115-
sc.Cmd = exec.CommandContext(commandCtx, "bash", "-c", fmt.Sprintf("%s\n%s", bc.PreCmd, binLocation))
116-
sc.Cmd.Dir = dir
117-
118-
secretsEnv, err := getSecrets(ctx, bc.Name, bc.ExternalSecrets)
87+
// Grab the location of the binary in bazel-out.
88+
binLocation, err := bc.GetBinaryLocation()
11989
if err != nil {
120-
std.Out.WriteLine(output.Styledf(output.StyleWarning, "[%s] %s %s",
121-
bc.Name, output.EmojiFailure, err.Error()))
90+
return nil, err
12291
}
92+
return []string{binLocation}, nil
12393

124-
sc.Cmd.Env = makeEnv(parentEnv, secretsEnv, bc.Env)
94+
}
12595

126-
var stdoutWriter, stderrWriter io.Writer
127-
logger := newCmdLogger(commandCtx, bc.Name, std.Out.Output)
128-
if bc.IgnoreStdout {
129-
std.Out.WriteLine(output.Styledf(output.StyleSuggestion, "Ignoring stdout of %s", bc.Name))
130-
stdoutWriter = sc.stdoutBuf
131-
} else {
132-
stdoutWriter = io.MultiWriter(logger, sc.stdoutBuf)
133-
}
134-
if bc.IgnoreStderr {
135-
std.Out.WriteLine(output.Styledf(output.StyleSuggestion, "Ignoring stderr of %s", bc.Name))
136-
stderrWriter = sc.stderrBuf
96+
func (bc BazelCommand) StartWatch(ctx context.Context) (<-chan struct{}, error) {
97+
if watchPaths, err := bc.watchPaths(); err != nil {
98+
return nil, err
13799
} else {
138-
stderrWriter = io.MultiWriter(logger, sc.stderrBuf)
100+
// skip remove events as we don't care about files being removed, we only
101+
// want to know when the binary has been rebuilt
102+
return WatchPaths(ctx, watchPaths, notify.Remove)
139103
}
104+
}
140105

141-
eg, err := process.PipeOutputUnbuffered(ctx, sc.Cmd, stdoutWriter, stderrWriter)
142-
if err != nil {
143-
return nil, err
106+
func (bc BazelCommand) GetExecCmd(ctx context.Context) (*exec.Cmd, error) {
107+
var cmd string
108+
var err error
109+
if bc.RunTarget != "" {
110+
cmd = "bazel run " + bc.RunTarget
111+
} else {
112+
if cmd, err = bc.GetBinaryLocation(); err != nil {
113+
return nil, err
114+
}
144115
}
145-
sc.outEg = eg
146116

147-
if err := sc.Start(); err != nil {
148-
return nil, err
149-
}
117+
return exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("%s\n%s", bc.PreCmd, cmd)), nil
118+
}
150119

151-
return cancel, nil
120+
func outputPath() ([]byte, error) {
121+
// Get the output directory from Bazel, which varies depending on which OS
122+
// we're running against.
123+
cmd := exec.Command("bazel", "info", "output_path")
124+
return cmd.Output()
152125
}

0 commit comments

Comments
 (0)