-
Notifications
You must be signed in to change notification settings - Fork 17
Rework progress #352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Rework progress #352
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,6 +90,8 @@ github.com/containers/storage v1.59.1/go.mod h1:KoAYHnAjP3/cTsRS+mmWZGkufSY2GACi | |
| github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= | ||
| github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= | ||
| github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= | ||
| github.com/croissanne/images v0.0.0-20251023114920-81eefc443b5e h1:MuftBLwWLE8gWoJY1/P26tw0TL9HIkb4LcoTepZjVyY= | ||
| github.com/croissanne/images v0.0.0-20251023114920-81eefc443b5e/go.mod h1:tZqcrs3eNUA0VPs1h3YCnbnpAskVVfo36CIi2USSfDs= | ||
| github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= | ||
| github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= | ||
| github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= | ||
|
|
@@ -245,8 +247,6 @@ github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplU | |
| github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U= | ||
| github.com/osbuild/blueprint v1.16.0 h1:f/kHih+xpeJ1v7wtIfzdHPZTsiXsqKeDQ1+rrue6298= | ||
| github.com/osbuild/blueprint v1.16.0/go.mod h1:HPlJzkEl7q5g8hzaGksUk7ifFAy9QFw9LmzhuFOAVm4= | ||
| github.com/osbuild/images v0.206.0 h1:F9G6dnqrURRUcWE2eWIPQLzHutSCT0OyWMcITK28uCQ= | ||
| github.com/osbuild/images v0.206.0/go.mod h1:iF6bTLzBtyp9l27fexsD5AzwHEn9+bXF5Jr4HHQecmI= | ||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not have been in this commit, there is a separate one I guess you accidentally squashed it in. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,30 +7,17 @@ import ( | |
| "io" | ||
| "log" | ||
| "os" | ||
| "os/exec" | ||
| "strings" | ||
| "sync" | ||
| "syscall" | ||
|
|
||
| "github.com/osbuild/images/pkg/datasizes" | ||
| "github.com/osbuild/images/pkg/osbuild" | ||
| ) | ||
|
|
||
| type OSBuildOptions struct { | ||
| StoreDir string | ||
| OutputDir string | ||
| ExtraEnv []string | ||
|
|
||
| // BuildLog writes the osbuild output to the given writer | ||
| BuildLog io.Writer | ||
|
|
||
| CacheMaxSize int64 | ||
| } | ||
|
|
||
| // XXX: merge variant back into images/pkg/osbuild/osbuild-exec.go | ||
| func RunOSBuild(pb ProgressBar, manifest []byte, exports []string, opts *OSBuildOptions) error { | ||
| func RunOSBuild(pb ProgressBar, manifest []byte, exports []string, opts *osbuild.OSBuildOptions) error { | ||
| if opts == nil { | ||
| opts = &OSBuildOptions{} | ||
| opts = &osbuild.OSBuildOptions{} | ||
| } | ||
|
|
||
| // To keep maximum compatibility keep the old behavior to run osbuild | ||
|
|
@@ -48,92 +35,39 @@ func RunOSBuild(pb ProgressBar, manifest []byte, exports []string, opts *OSBuild | |
| } | ||
| } | ||
|
|
||
| func newOsbuildCmd(manifest []byte, exports []string, opts *OSBuildOptions) *exec.Cmd { | ||
| cacheMaxSize := int64(20 * datasizes.GiB) | ||
| if opts.CacheMaxSize != 0 { | ||
| cacheMaxSize = opts.CacheMaxSize | ||
| } | ||
| cmd := exec.Command( | ||
| osbuildCmd, | ||
| "--store", opts.StoreDir, | ||
| "--output-directory", opts.OutputDir, | ||
| fmt.Sprintf("--cache-max-size=%v", cacheMaxSize), | ||
| "-", | ||
| ) | ||
| for _, export := range exports { | ||
| cmd.Args = append(cmd.Args, "--export", export) | ||
| } | ||
| cmd.Env = append(os.Environ(), opts.ExtraEnv...) | ||
| cmd.Stdin = bytes.NewBuffer(manifest) | ||
| return cmd | ||
| } | ||
|
|
||
| func runOSBuildNoProgress(pb ProgressBar, manifest []byte, exports []string, opts *OSBuildOptions) error { | ||
| var stdout, stderr io.Writer | ||
|
|
||
| var writeMu sync.Mutex | ||
| if opts.BuildLog == nil { | ||
| // No external build log requested and we won't need an | ||
| // internal one because all output goes directly to | ||
| // stdout/stderr. This is for maximum compatibility with | ||
| // the existing bootc-image-builder in "verbose" mode | ||
| // where stdout, stderr come directly from osbuild. | ||
| stdout = osStdout() | ||
| stderr = osStderr() | ||
| } else { | ||
| // There is a slight wrinkle here: when requesting a | ||
| // buildlog we can no longer write to separate | ||
| // stdout/stderr streams without being racy and give | ||
| // potential out-of-order output (which is very bad | ||
| // and confusing in a log). The reason is that if | ||
| // cmd.Std{out,err} are different "go" will start two | ||
| // go-routine to monitor/copy those are racy when both | ||
| // stdout,stderr output happens close together | ||
| // (TestRunOSBuildWithBuildlog demos that). We cannot | ||
| // have our cake and eat it so here we need to combine | ||
| // osbuilds stderr into our stdout. | ||
| mw := newSyncedWriter(&writeMu, io.MultiWriter(osStdout(), opts.BuildLog)) | ||
| stdout = mw | ||
| stderr = mw | ||
| } | ||
|
|
||
| cmd := newOsbuildCmd(manifest, exports, opts) | ||
| cmd.Stdout = stdout | ||
| cmd.Stderr = stderr | ||
| func runOSBuildNoProgress(pb ProgressBar, manifest []byte, exports []string, opts *osbuild.OSBuildOptions) error { | ||
| cmd := osbuild.NewOSBuildCmd(manifest, exports, opts) | ||
| if err := cmd.Run(); err != nil { | ||
| return fmt.Errorf("error running osbuild: %w", err) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| var osbuildCmd = "osbuild" | ||
|
|
||
| func runOSBuildWithProgress(pb ProgressBar, manifest []byte, exports []string, opts *OSBuildOptions) (err error) { | ||
| func runOSBuildWithProgress(pb ProgressBar, manifest []byte, exports []string, opts *osbuild.OSBuildOptions) (err error) { | ||
| rp, wp, err := os.Pipe() | ||
| if err != nil { | ||
| return fmt.Errorf("cannot create pipe for osbuild: %w", err) | ||
| } | ||
| defer rp.Close() | ||
| defer wp.Close() | ||
|
|
||
| cmd := newOsbuildCmd(manifest, exports, opts) | ||
| cmd.Args = append(cmd.Args, "--monitor=JSONSeqMonitor") | ||
| cmd.Args = append(cmd.Args, "--monitor-fd=3") | ||
|
|
||
| opts.Monitor = osbuild.MonitorJSONSeq | ||
| opts.MonitorFD = 3 | ||
| opts.MonitorFile = wp | ||
| var stdio bytes.Buffer | ||
| var mw, buildLog io.Writer | ||
| var writeMu sync.Mutex | ||
| if opts.BuildLog != nil { | ||
| mw = newSyncedWriter(&writeMu, io.MultiWriter(&stdio, opts.BuildLog)) | ||
| buildLog = newSyncedWriter(&writeMu, opts.BuildLog) | ||
| } else { | ||
| mw = &stdio | ||
| var mu sync.Mutex | ||
| buildLog := opts.BuildLog | ||
| opts.BuildLogMu = &mu | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can someone explain why type SyncedWriter struct {
mu sync.Mutex
w io.Writer
}
func NewSyncedWriter(w io.Writer) *SyncedWriter {
return &SyncedWriter{w: w}
}
func (sw *SyncedWriter) Write(p []byte) (n int, err error) {
sw.mu.Lock()
defer sw.mu.Unlock()
return sw.w.Write(p)
}Than we could drop this passing of mutex, it is created on stack either way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 reasons:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 2nd reason is actually no longer the case with osbuild/images#1966 ; but we still need to pass along the mutex, unless we don't care about the ordering for these extra statements ibcli adds to the buildlog. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, right. Well, how about to tee before sync so each writer has its individual mutex that can be shared? Something like: syncedStdio := newSyncedWriter(&stdio)
syncedBuildLog := newSyncedWriter(opts.BuildLog)
io.MultiWriter(syncedStdio, syncedBuildLog)Then use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the flow should be If we create the syncw after the mw we get I think by having both stdout and stderr go via the multiw into syncw we're already out of order? Unsure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh actually this works in images, I guess io.MultiWriter isn't racy? The only problem is still writing the the buildlog from ibcli if we actually wanna move the synced writer over to images. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reversing multiwriter and syncedwriter can work, test pass with go test -race iwth this in images: But this doesn't solve problem 2 :/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if opts.BuildLog == nil { | ||
| mw := &stdio | ||
| opts.Stdout = mw | ||
| opts.Stderr = mw | ||
| buildLog = io.Discard | ||
| } else { | ||
| opts.Stdout = &stdio | ||
| } | ||
|
|
||
| cmd.Stdout = mw | ||
| cmd.Stderr = mw | ||
| cmd.ExtraFiles = []*os.File{wp} | ||
| cmd := osbuild.NewOSBuildCmd(manifest, exports, opts) | ||
|
|
||
| osbuildStatus := osbuild.NewStatusScanner(rp) | ||
| if err := cmd.Start(); err != nil { | ||
|
|
@@ -186,11 +120,15 @@ func runOSBuildWithProgress(pb ProgressBar, manifest []byte, exports []string, o | |
| // external build log | ||
| if st.Message != "" { | ||
| tracesMsgs = append(tracesMsgs, st.Message) | ||
| mu.Lock() | ||
| fmt.Fprintln(buildLog, st.Message) | ||
| mu.Unlock() | ||
| } | ||
| if st.Trace != "" { | ||
| tracesMsgs = append(tracesMsgs, st.Trace) | ||
| mu.Lock() | ||
| fmt.Fprintln(buildLog, st.Trace) | ||
| mu.Unlock() | ||
| } | ||
| } | ||
|
|
||
|
|
||
This file was deleted.

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is still draft, this is just to show what it would look like with osbuild/images#1966. Not actually intending to merge this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure was just highlighting it, I guess we have a linter for that. Or not, depends on the repo :-)