8e0c51192a
Change-Id: I6f7c7374093c0745ee4aa677480376a06648b358
258 lines
5.6 KiB
Go
258 lines
5.6 KiB
Go
// Copyright 2014 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package blueprint
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
const (
|
|
indentWidth = 4
|
|
lineWidth = 80
|
|
)
|
|
|
|
type ninjaWriter struct {
|
|
writer io.Writer
|
|
|
|
justDidBlankLine bool // true if the last operation was a BlankLine
|
|
}
|
|
|
|
func newNinjaWriter(writer io.Writer) *ninjaWriter {
|
|
return &ninjaWriter{
|
|
writer: writer,
|
|
}
|
|
}
|
|
|
|
func (n *ninjaWriter) Comment(comment string) error {
|
|
n.justDidBlankLine = false
|
|
|
|
const lineHeaderLen = len("# ")
|
|
const maxLineLen = lineWidth - lineHeaderLen
|
|
|
|
var lineStart, lastSplitPoint int
|
|
for i, r := range comment {
|
|
if unicode.IsSpace(r) {
|
|
// We know we can safely split the line here.
|
|
lastSplitPoint = i + 1
|
|
}
|
|
|
|
var line string
|
|
var writeLine bool
|
|
switch {
|
|
case r == '\n':
|
|
// Output the line without trimming the left so as to allow comments
|
|
// to contain their own indentation.
|
|
line = strings.TrimRightFunc(comment[lineStart:i], unicode.IsSpace)
|
|
writeLine = true
|
|
|
|
case (i-lineStart > maxLineLen) && (lastSplitPoint > lineStart):
|
|
// The line has grown too long and is splittable. Split it at the
|
|
// last split point.
|
|
line = strings.TrimSpace(comment[lineStart:lastSplitPoint])
|
|
writeLine = true
|
|
}
|
|
|
|
if writeLine {
|
|
line = strings.TrimSpace("# "+line) + "\n"
|
|
_, err := io.WriteString(n.writer, line)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lineStart = lastSplitPoint
|
|
}
|
|
}
|
|
|
|
if lineStart != len(comment) {
|
|
line := strings.TrimSpace(comment[lineStart:])
|
|
_, err := fmt.Fprintf(n.writer, "# %s\n", line)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (n *ninjaWriter) Pool(name string) error {
|
|
n.justDidBlankLine = false
|
|
_, err := fmt.Fprintf(n.writer, "pool %s\n", name)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) Rule(name string) error {
|
|
n.justDidBlankLine = false
|
|
_, err := fmt.Fprintf(n.writer, "rule %s\n", name)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) Build(rule string, outputs, explicitDeps, implicitDeps,
|
|
orderOnlyDeps []string) error {
|
|
|
|
n.justDidBlankLine = false
|
|
|
|
const lineWrapLen = len(" $")
|
|
const maxLineLen = lineWidth - lineWrapLen
|
|
|
|
line := "build"
|
|
|
|
appendWithWrap := func(s string) (err error) {
|
|
if len(line)+len(s) > maxLineLen {
|
|
_, err = fmt.Fprintf(n.writer, "%s $\n", line)
|
|
line = strings.Repeat(" ", indentWidth*2)
|
|
s = strings.TrimLeftFunc(s, unicode.IsSpace)
|
|
}
|
|
line += s
|
|
return
|
|
}
|
|
|
|
for _, output := range outputs {
|
|
err := appendWithWrap(" " + output)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err := appendWithWrap(":")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = appendWithWrap(" " + rule)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, dep := range explicitDeps {
|
|
err := appendWithWrap(" " + dep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if len(implicitDeps) > 0 {
|
|
err := appendWithWrap(" |")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, dep := range implicitDeps {
|
|
err := appendWithWrap(" " + dep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(orderOnlyDeps) > 0 {
|
|
err := appendWithWrap(" ||")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, dep := range orderOnlyDeps {
|
|
err := appendWithWrap(" " + dep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
_, err = fmt.Fprintln(n.writer, line)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) Assign(name, value string) error {
|
|
n.justDidBlankLine = false
|
|
_, err := fmt.Fprintf(n.writer, "%s = %s\n", name, value)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) ScopedAssign(name, value string) error {
|
|
n.justDidBlankLine = false
|
|
indent := strings.Repeat(" ", indentWidth)
|
|
_, err := fmt.Fprintf(n.writer, "%s%s = %s\n", indent, name, value)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) Default(targets ...string) error {
|
|
n.justDidBlankLine = false
|
|
|
|
const lineWrapLen = len(" $")
|
|
const maxLineLen = lineWidth - lineWrapLen
|
|
|
|
line := "default"
|
|
|
|
appendWithWrap := func(s string) (err error) {
|
|
if len(line)+len(s) > maxLineLen {
|
|
_, err = fmt.Fprintf(n.writer, "%s $\n", line)
|
|
line = strings.Repeat(" ", indentWidth*2)
|
|
s = strings.TrimLeftFunc(s, unicode.IsSpace)
|
|
}
|
|
line += s
|
|
return
|
|
}
|
|
|
|
for _, target := range targets {
|
|
err := appendWithWrap(" " + target)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
_, err := fmt.Fprintln(n.writer, line)
|
|
return err
|
|
}
|
|
|
|
func (n *ninjaWriter) BlankLine() (err error) {
|
|
// We don't output multiple blank lines in a row.
|
|
if !n.justDidBlankLine {
|
|
n.justDidBlankLine = true
|
|
_, err = io.WriteString(n.writer, "\n")
|
|
}
|
|
return err
|
|
}
|
|
|
|
func writeAssignments(w io.Writer, indent int, assignments ...string) error {
|
|
var maxNameLen int
|
|
for i := 0; i < len(assignments); i += 2 {
|
|
name := assignments[i]
|
|
err := validateNinjaName(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if maxNameLen < len(name) {
|
|
maxNameLen = len(name)
|
|
}
|
|
}
|
|
|
|
indentStr := strings.Repeat(" ", indent*indentWidth)
|
|
extraIndentStr := strings.Repeat(" ", (indent+1)*indentWidth)
|
|
replacer := strings.NewReplacer("\n", "$\n"+extraIndentStr)
|
|
|
|
for i := 0; i < len(assignments); i += 2 {
|
|
name := assignments[i]
|
|
value := replacer.Replace(assignments[i+1])
|
|
_, err := fmt.Fprintf(w, "%s% *s = %s\n", indentStr, maxNameLen, name,
|
|
value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|