From de7afaaf749957b3b7c03036e36c99a5ac7e3afb Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 23 Jan 2019 13:23:00 -0800 Subject: [PATCH] Write ninja file directly to the output file Writing the ninja file to a byte buffer causes a significant amount of time to be spent in memmove when growing the byte slice. Write the file directly to disk instead. This also fixes some unhandled error warnings, which become more likely when doing disk IO instead of byte buffer writes. Change-Id: I5094e4c45cab4012713037f60c5a4fb00718f92e --- bootstrap/command.go | 46 +++++++++++++++++++++++++++++++------------- context.go | 5 ++++- ninja_defs.go | 5 ++++- ninja_writer.go | 10 ++++++++-- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/bootstrap/command.go b/bootstrap/command.go index da0191b..bf6bbe9 100644 --- a/bootstrap/command.go +++ b/bootstrap/command.go @@ -15,9 +15,10 @@ package bootstrap import ( - "bytes" + "bufio" "flag" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -173,20 +174,39 @@ func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...stri } deps = append(deps, extraDeps...) - buf := bytes.NewBuffer(nil) - err = ctx.WriteBuildFile(buf) - if err != nil { - fatalf("error generating Ninja file contents: %s", err) - } - - if stage == StageMain && emptyNinjaFile { - buf.Reset() - } - const outFilePermissions = 0666 - err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions) + var out io.Writer + var f *os.File + var buf *bufio.Writer + + if stage != StageMain || !emptyNinjaFile { + f, err = os.OpenFile(outFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, outFilePermissions) + if err != nil { + fatalf("error opening Ninja file: %s", err) + } + buf = bufio.NewWriter(f) + out = buf + } else { + out = ioutil.Discard + } + + err = ctx.WriteBuildFile(out) if err != nil { - fatalf("error writing %s: %s", outFile, err) + fatalf("error writing Ninja file contents: %s", err) + } + + if buf != nil { + err = buf.Flush() + if err != nil { + fatalf("error flushing Ninja file contents: %s", err) + } + } + + if f != nil { + err = f.Close() + if err != nil { + fatalf("error closing Ninja file: %s", err) + } } if globFile != "" { diff --git a/context.go b/context.go index 8d44853..5694ac0 100644 --- a/context.go +++ b/context.go @@ -3113,7 +3113,10 @@ func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error { func (c *Context) writeSubninjas(nw *ninjaWriter) error { for _, subninja := range c.subninjas { - nw.Subninja(subninja) + err := nw.Subninja(subninja) + if err != nil { + return err + } } return nw.BlankLine() } diff --git a/ninja_defs.go b/ninja_defs.go index b27658b..61846fe 100644 --- a/ninja_defs.go +++ b/ninja_defs.go @@ -410,7 +410,10 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) } if !b.Optional { - nw.Default(outputs...) + err = nw.Default(outputs...) + if err != nil { + return err + } } return nw.BlankLine() diff --git a/ninja_writer.go b/ninja_writer.go index 5902986..5366f3f 100644 --- a/ninja_writer.go +++ b/ninja_writer.go @@ -117,7 +117,10 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } if comment != "" { - wrapper.Comment(comment) + err := wrapper.Comment(comment) + if err != nil { + return err + } } wrapper.WriteString("build") @@ -237,7 +240,10 @@ func (n *ninjaWriterWithWrap) writeString(s string, space bool) { n.writtenLen = indentWidth * 2 s = strings.TrimLeftFunc(s, unicode.IsSpace) } else if space { - io.WriteString(n.writer, " ") + _, n.err = io.WriteString(n.writer, " ") + if n.err != nil { + return + } n.writtenLen++ }