Skip to content

Commit 9adbff4

Browse files
authored
Make output more compact and easier to read (#295)
Build output now includes a target and command heading. Info-level log lines no longer have the unhelpful "INFO" prefix. All non-error build output now goes to stdout so someone who wants a more quiet experience for a successful build can redirect to `/dev/null`. Individual lines of command and log output now also include the target they are running for and the time the line was outputted. This serves to both visually group outputs by command as well as provide fine-grained timing information. Also propagate `NO_COLOR` to build environment. [Fixes ch4043] [Fixes ch4040]
1 parent 70a9eb0 commit 9adbff4

File tree

12 files changed

+384
-89
lines changed

12 files changed

+384
-89
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ The format is based on [Keep a Changelog][], and this project adheres to
2222
error if the targets have a dependency cycle.
2323
- yb attempts to detect some common Docker configuration issues and inform the
2424
user about them.
25+
- yb now obeys the [`NO_COLOR` environment variable][] and propagates it to the
26+
build environment.
27+
28+
[`NO_COLOR` environment variable]: https://no-color.org/
2529

2630
### Changed
2731

2832
- Commands run as part of `build`, `exec`, or `run` now run without Docker by
2933
default. You can get the old behavior by running with `--mode=container`.
34+
- Tool output has been changed to be more compact, to be easier to trace
35+
command output, and to include more timing information.
3036
- `yb platform` is now an alias for `yb version`.
3137

3238
### Fixed

cmd/yb/build.go

+25-36
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package main
33
import (
44
"context"
55
"fmt"
6-
"io/ioutil"
6+
"io"
77
"os"
88
"strings"
99
"time"
@@ -98,6 +98,7 @@ func (b *buildCmd) run(ctx context.Context) error {
9898
startTime := time.Now()
9999
ctx, span := ybtrace.Start(ctx, "Build", trace.WithNewRoot())
100100
defer span.End()
101+
ctx = withStdoutLogs(ctx)
101102

102103
log.Infof(ctx, "Build started at %s", startTime.Format(longTimeFormat))
103104

@@ -117,10 +118,10 @@ func (b *buildCmd) run(ctx context.Context) error {
117118
showDockerWarningsIfNeeded(ctx, b.mode, buildTargets)
118119

119120
// Do the build!
120-
startSection("BUILD")
121121
log.Debugf(ctx, "Building package %s in %s...", targetPackage.Name, targetPackage.Path)
122122

123123
buildError := doTargetList(ctx, targetPackage, buildTargets, &doOptions{
124+
output: os.Stdout,
124125
executionMode: b.mode,
125126
dockerClient: dockerClient,
126127
dataDirs: dataDirs,
@@ -132,27 +133,27 @@ func (b *buildCmd) run(ctx context.Context) error {
132133
})
133134
if buildError != nil {
134135
span.SetStatus(codes.Unknown, buildError.Error())
136+
log.Errorf(ctx, "%v", buildError)
135137
}
136138
span.End()
137139
endTime := time.Now()
138140
buildTime := endTime.Sub(startTime)
139141

140-
log.Infof(ctx, "")
141-
log.Infof(ctx, "Build finished at %s, taking %s", endTime.Format(longTimeFormat), buildTime)
142-
log.Infof(ctx, "")
143-
144-
log.Infof(ctx, "%s", buildTraces.dump())
142+
fmt.Printf("\nBuild finished at %s, taking %v\n\n", endTime.Format(longTimeFormat), buildTime.Truncate(time.Millisecond))
143+
fmt.Println(buildTraces.dump())
145144

145+
style := termStylesFromEnv()
146146
if buildError != nil {
147-
subSection("BUILD FAILED")
148-
return buildError
147+
fmt.Printf("%sBUILD FAILED%s ❌\n", style.buildResult(false), style.reset())
148+
return alreadyLoggedError{buildError}
149149
}
150150

151-
subSection("BUILD SUCCEEDED")
151+
fmt.Printf("%sBUILD PASSED%s ️✔️\n", style.buildResult(true), style.reset())
152152
return nil
153153
}
154154

155155
type doOptions struct {
156+
output io.Writer
156157
dataDirs *ybdata.Dirs
157158
downloader *ybdata.Downloader
158159
executionMode executionMode
@@ -198,6 +199,11 @@ func doTargetList(ctx context.Context, pkg *yb.Package, targets []*yb.Target, op
198199
}
199200

200201
func doTarget(ctx context.Context, pkg *yb.Package, target *yb.Target, opts *doOptions) error {
202+
style := termStylesFromEnv()
203+
fmt.Printf("\n🎯 %sTarget: %s%s\n", style.target(), target.Name, style.reset())
204+
205+
ctx = withLogPrefix(ctx, target.Name)
206+
201207
bio, err := newBiome(ctx, target, newBiomeOptions{
202208
packageDir: pkg.Path,
203209
dataDirs: opts.dataDirs,
@@ -216,15 +222,17 @@ func doTarget(ctx context.Context, pkg *yb.Package, target *yb.Target, opts *doO
216222
log.Warnf(ctx, "Clean up environment: %v", err)
217223
}
218224
}()
225+
output := newLinePrefixWriter(opts.output, target.Name)
219226
sys := build.Sys{
220227
Biome: bio,
221228
Downloader: opts.downloader,
222229
DockerClient: opts.dockerClient,
223230
DockerNetworkID: opts.dockerNetworkID,
224-
Stdout: os.Stdout,
225-
Stderr: os.Stderr,
231+
232+
Stdout: output,
233+
Stderr: output,
226234
}
227-
execBiome, err := build.Setup(ctx, sys, target)
235+
execBiome, err := build.Setup(withLogPrefix(ctx, setupLogPrefix), sys, target)
228236
if err != nil {
229237
return err
230238
}
@@ -241,34 +249,15 @@ func doTarget(ctx context.Context, pkg *yb.Package, target *yb.Target, opts *doO
241249
return nil
242250
}
243251

244-
subSection(fmt.Sprintf("Build target: %s", target.Name))
245-
log.Infof(ctx, "Executing build steps...")
246-
return build.Execute(ctx, sys, target)
252+
return build.Execute(withStdoutLogs(ctx), sys, announceCommand, target)
247253
}
248254

249-
// Because, why not?
250-
// Based on https://github.com/sindresorhus/is-docker/blob/master/index.js and https://github.com/moby/moby/issues/18355
251-
// Discussion is not settled yet: https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container#25518538
252-
func insideTheMatrix() bool {
253-
hasDockerEnv := pathExists("/.dockerenv")
254-
hasDockerCGroup := false
255-
dockerCGroupPath := "/proc/self/cgroup"
256-
if pathExists(dockerCGroupPath) {
257-
contents, _ := ioutil.ReadFile(dockerCGroupPath)
258-
hasDockerCGroup = strings.Count(string(contents), "docker") > 0
259-
}
260-
return hasDockerEnv || hasDockerCGroup
255+
func announceCommand(cmdString string) {
256+
style := termStylesFromEnv()
257+
fmt.Printf("%s> %s%s\n", style.command(), cmdString, style.reset())
261258
}
262259

263260
func pathExists(path string) bool {
264261
_, err := os.Lstat(path)
265262
return !os.IsNotExist(err)
266263
}
267-
268-
func startSection(name string) {
269-
fmt.Printf(" === %s ===\n", name)
270-
}
271-
272-
func subSection(name string) {
273-
fmt.Printf(" -- %s -- \n", name)
274-
}

cmd/yb/exec.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (b *execCmd) run(ctx context.Context) error {
9999
Stdout: os.Stdout,
100100
Stderr: os.Stderr,
101101
}
102-
execBiome, err := build.Setup(ctx, sys, execTarget)
102+
execBiome, err := build.Setup(withLogPrefix(ctx, execTarget.Name+setupLogPrefix), sys, execTarget)
103103
if err != nil {
104104
return err
105105
}
@@ -109,5 +109,5 @@ func (b *execCmd) run(ctx context.Context) error {
109109
log.Errorf(ctx, "Clean up environment %s: %v", b.execEnvName, err)
110110
}
111111
}()
112-
return build.Execute(ctx, sys, execTarget)
112+
return build.Execute(ctx, sys, announceCommand, execTarget)
113113
}

cmd/yb/main.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"os"
78
"path/filepath"
@@ -87,12 +88,28 @@ func main() {
8788
err = rootCmd.ExecuteContext(ctx)
8889
cancel()
8990
if err != nil {
90-
initLog(cfg, false)
91-
log.Errorf(ctx, "%v", err)
91+
if !errors.As(err, new(alreadyLoggedError)) {
92+
initLog(cfg, false)
93+
log.Errorf(ctx, "%v", err)
94+
}
9295
os.Exit(1)
9396
}
9497
}
9598

99+
// alreadyLoggedError wraps another error to signal that it has already been
100+
// shown to the user. If returned from a subcommand, then main() will not log it.
101+
type alreadyLoggedError struct {
102+
err error
103+
}
104+
105+
func (e alreadyLoggedError) Error() string {
106+
return e.err.Error()
107+
}
108+
109+
func (e alreadyLoggedError) Unwrap() error {
110+
return e.err
111+
}
112+
96113
func displayOldDirectoryWarning(ctx context.Context) {
97114
home := os.Getenv("HOME")
98115
if home == "" {

0 commit comments

Comments
 (0)