Merge remote-tracking branch 'aosp/upstream' am: 3b6c68cd9e
Original change: https://android-review.googlesource.com/c/platform/build/blueprint/+/1557081 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I468a1f890e0ff8122563edae6980f8b8180b5a3d
This commit is contained in:
commit
d7e36a2687
8 changed files with 417 additions and 156 deletions
|
@ -186,7 +186,7 @@ func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...stri
|
|||
}
|
||||
|
||||
const outFilePermissions = 0666
|
||||
var out io.Writer
|
||||
var out io.StringWriter
|
||||
var f *os.File
|
||||
var buf *bufio.Writer
|
||||
|
||||
|
@ -201,10 +201,10 @@ func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...stri
|
|||
if err != nil {
|
||||
fatalf("error opening Ninja file: %s", err)
|
||||
}
|
||||
buf = bufio.NewWriter(f)
|
||||
buf = bufio.NewWriterSize(f, 16*1024*1024)
|
||||
out = buf
|
||||
} else {
|
||||
out = ioutil.Discard
|
||||
out = ioutil.Discard.(io.StringWriter)
|
||||
}
|
||||
|
||||
if globFile != "" {
|
||||
|
|
42
context.go
42
context.go
|
@ -1355,6 +1355,8 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
|
|||
m := *origModule
|
||||
newModule := &m
|
||||
newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
|
||||
newModule.reverseDeps = nil
|
||||
newModule.forwardDeps = nil
|
||||
newModule.logicModule = newLogicModule
|
||||
newModule.variant = newVariant(origModule, mutatorName, variationName, local)
|
||||
newModule.properties = newProperties
|
||||
|
@ -2180,7 +2182,9 @@ func (c *Context) updateDependencies() (errs []error) {
|
|||
checking[module] = true
|
||||
defer delete(checking, module)
|
||||
|
||||
deps := make(map[*moduleInfo]bool)
|
||||
// Reset the forward and reverse deps without reducing their capacity to avoid reallocation.
|
||||
module.reverseDeps = module.reverseDeps[:0]
|
||||
module.forwardDeps = module.forwardDeps[:0]
|
||||
|
||||
// Add an implicit dependency ordering on all earlier modules in the same module group
|
||||
for _, dep := range module.group.modules {
|
||||
|
@ -2188,18 +2192,22 @@ func (c *Context) updateDependencies() (errs []error) {
|
|||
break
|
||||
}
|
||||
if depModule := dep.module(); depModule != nil {
|
||||
deps[depModule] = true
|
||||
module.forwardDeps = append(module.forwardDeps, depModule)
|
||||
}
|
||||
}
|
||||
|
||||
outer:
|
||||
for _, dep := range module.directDeps {
|
||||
deps[dep.module] = true
|
||||
// use a loop to check for duplicates, average number of directDeps measured to be 9.5.
|
||||
for _, exists := range module.forwardDeps {
|
||||
if dep.module == exists {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
module.forwardDeps = append(module.forwardDeps, dep.module)
|
||||
}
|
||||
|
||||
module.reverseDeps = []*moduleInfo{}
|
||||
module.forwardDeps = []*moduleInfo{}
|
||||
|
||||
for dep := range deps {
|
||||
for _, dep := range module.forwardDeps {
|
||||
if checking[dep] {
|
||||
// This is a cycle.
|
||||
return []*moduleInfo{dep, module}
|
||||
|
@ -2225,7 +2233,6 @@ func (c *Context) updateDependencies() (errs []error) {
|
|||
}
|
||||
}
|
||||
|
||||
module.forwardDeps = append(module.forwardDeps, dep)
|
||||
dep.reverseDeps = append(dep.reverseDeps, module)
|
||||
}
|
||||
|
||||
|
@ -2309,6 +2316,8 @@ func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs [
|
|||
|
||||
deps = append(deps, depsPackages...)
|
||||
|
||||
c.memoizeFullNames(c.liveGlobals, pkgNames)
|
||||
|
||||
// This will panic if it finds a problem since it's a programming error.
|
||||
c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
|
||||
|
||||
|
@ -3173,6 +3182,21 @@ func (c *Context) makeUniquePackageNames(
|
|||
return pkgNames, deps
|
||||
}
|
||||
|
||||
// memoizeFullNames stores the full name of each live global variable, rule and pool since each is
|
||||
// guaranteed to be used at least twice, once in the definition and once for each usage, and many
|
||||
// are used much more than once.
|
||||
func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) {
|
||||
for v := range liveGlobals.variables {
|
||||
v.memoizeFullName(pkgNames)
|
||||
}
|
||||
for r := range liveGlobals.rules {
|
||||
r.memoizeFullName(pkgNames)
|
||||
}
|
||||
for p := range liveGlobals.pools {
|
||||
p.memoizeFullName(pkgNames)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) checkForVariableReferenceCycles(
|
||||
variables map[Variable]ninjaString, pkgNames map[*packageContext]string) {
|
||||
|
||||
|
@ -3489,7 +3513,7 @@ func (c *Context) SingletonName(singleton Singleton) string {
|
|||
// WriteBuildFile writes the Ninja manifeset text for the generated build
|
||||
// actions to w. If this is called before PrepareBuildActions successfully
|
||||
// completes then ErrBuildActionsNotReady is returned.
|
||||
func (c *Context) WriteBuildFile(w io.Writer) error {
|
||||
func (c *Context) WriteBuildFile(w io.StringWriter) error {
|
||||
var err error
|
||||
pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
|
||||
if !c.buildActionsReady {
|
||||
|
|
|
@ -392,50 +392,50 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string)
|
|||
var (
|
||||
comment = b.Comment
|
||||
rule = b.Rule.fullName(pkgNames)
|
||||
outputs = valueList(b.Outputs, pkgNames, outputEscaper)
|
||||
implicitOuts = valueList(b.ImplicitOutputs, pkgNames, outputEscaper)
|
||||
explicitDeps = valueList(b.Inputs, pkgNames, inputEscaper)
|
||||
implicitDeps = valueList(b.Implicits, pkgNames, inputEscaper)
|
||||
orderOnlyDeps = valueList(b.OrderOnly, pkgNames, inputEscaper)
|
||||
validations = valueList(b.Validations, pkgNames, inputEscaper)
|
||||
outputs = b.Outputs
|
||||
implicitOuts = b.ImplicitOutputs
|
||||
explicitDeps = b.Inputs
|
||||
implicitDeps = b.Implicits
|
||||
orderOnlyDeps = b.OrderOnly
|
||||
validations = b.Validations
|
||||
)
|
||||
|
||||
if b.RuleDef != nil {
|
||||
implicitDeps = append(valueList(b.RuleDef.CommandDeps, pkgNames, inputEscaper), implicitDeps...)
|
||||
orderOnlyDeps = append(valueList(b.RuleDef.CommandOrderOnly, pkgNames, inputEscaper), orderOnlyDeps...)
|
||||
implicitDeps = append(b.RuleDef.CommandDeps, implicitDeps...)
|
||||
orderOnlyDeps = append(b.RuleDef.CommandOrderOnly, orderOnlyDeps...)
|
||||
}
|
||||
|
||||
err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations)
|
||||
err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations, pkgNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
args := make(map[string]string)
|
||||
|
||||
for argVar, value := range b.Args {
|
||||
args[argVar.fullName(pkgNames)] = value.Value(pkgNames)
|
||||
}
|
||||
|
||||
err = writeVariables(nw, b.Variables, pkgNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for k := range args {
|
||||
keys = append(keys, k)
|
||||
type nameValuePair struct {
|
||||
name, value string
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, name := range keys {
|
||||
err = nw.ScopedAssign(name, args[name])
|
||||
args := make([]nameValuePair, 0, len(b.Args))
|
||||
|
||||
for argVar, value := range b.Args {
|
||||
fullName := argVar.fullName(pkgNames)
|
||||
args = append(args, nameValuePair{fullName, value.Value(pkgNames)})
|
||||
}
|
||||
sort.Slice(args, func(i, j int) bool { return args[i].name < args[j].name })
|
||||
|
||||
for _, pair := range args {
|
||||
err = nw.ScopedAssign(pair.name, pair.value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !b.Optional {
|
||||
err = nw.Default(outputs...)
|
||||
err = nw.Default(pkgNames, outputs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -444,16 +444,6 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string)
|
|||
return nw.BlankLine()
|
||||
}
|
||||
|
||||
func valueList(list []ninjaString, pkgNames map[*packageContext]string,
|
||||
escaper *strings.Replacer) []string {
|
||||
|
||||
result := make([]string, len(list))
|
||||
for i, ninjaStr := range list {
|
||||
result[i] = ninjaStr.ValueWithEscaper(pkgNames, escaper)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func writeVariables(nw *ninjaWriter, variables map[string]ninjaString,
|
||||
pkgNames map[*packageContext]string) error {
|
||||
var keys []string
|
||||
|
|
|
@ -17,6 +17,7 @@ package blueprint
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -36,7 +37,7 @@ var (
|
|||
|
||||
type ninjaString interface {
|
||||
Value(pkgNames map[*packageContext]string) string
|
||||
ValueWithEscaper(pkgNames map[*packageContext]string, escaper *strings.Replacer) string
|
||||
ValueWithEscaper(w io.StringWriter, pkgNames map[*packageContext]string, escaper *strings.Replacer)
|
||||
Eval(variables map[Variable]ninjaString) (string, error)
|
||||
Variables() []Variable
|
||||
}
|
||||
|
@ -284,26 +285,24 @@ func parseNinjaStrings(scope scope, strs []string) ([]ninjaString,
|
|||
}
|
||||
|
||||
func (n varNinjaString) Value(pkgNames map[*packageContext]string) string {
|
||||
return n.ValueWithEscaper(pkgNames, defaultEscaper)
|
||||
if len(n.strings) == 1 {
|
||||
return defaultEscaper.Replace(n.strings[0])
|
||||
}
|
||||
str := &strings.Builder{}
|
||||
n.ValueWithEscaper(str, pkgNames, defaultEscaper)
|
||||
return str.String()
|
||||
}
|
||||
|
||||
func (n varNinjaString) ValueWithEscaper(pkgNames map[*packageContext]string,
|
||||
escaper *strings.Replacer) string {
|
||||
func (n varNinjaString) ValueWithEscaper(w io.StringWriter, pkgNames map[*packageContext]string,
|
||||
escaper *strings.Replacer) {
|
||||
|
||||
if len(n.strings) == 1 {
|
||||
return escaper.Replace(n.strings[0])
|
||||
}
|
||||
|
||||
str := strings.Builder{}
|
||||
str.WriteString(escaper.Replace(n.strings[0]))
|
||||
w.WriteString(escaper.Replace(n.strings[0]))
|
||||
for i, v := range n.variables {
|
||||
str.WriteString("${")
|
||||
str.WriteString(v.fullName(pkgNames))
|
||||
str.WriteString("}")
|
||||
str.WriteString(escaper.Replace(n.strings[i+1]))
|
||||
w.WriteString("${")
|
||||
w.WriteString(v.fullName(pkgNames))
|
||||
w.WriteString("}")
|
||||
w.WriteString(escaper.Replace(n.strings[i+1]))
|
||||
}
|
||||
|
||||
return str.String()
|
||||
}
|
||||
|
||||
func (n varNinjaString) Eval(variables map[Variable]ninjaString) (string, error) {
|
||||
|
@ -327,12 +326,12 @@ func (n varNinjaString) Variables() []Variable {
|
|||
}
|
||||
|
||||
func (l literalNinjaString) Value(pkgNames map[*packageContext]string) string {
|
||||
return l.ValueWithEscaper(pkgNames, defaultEscaper)
|
||||
return defaultEscaper.Replace(string(l))
|
||||
}
|
||||
|
||||
func (l literalNinjaString) ValueWithEscaper(pkgNames map[*packageContext]string,
|
||||
escaper *strings.Replacer) string {
|
||||
return escaper.Replace(string(l))
|
||||
func (l literalNinjaString) ValueWithEscaper(w io.StringWriter, pkgNames map[*packageContext]string,
|
||||
escaper *strings.Replacer) {
|
||||
w.WriteString(escaper.Replace(string(l)))
|
||||
}
|
||||
|
||||
func (l literalNinjaString) Eval(variables map[Variable]ninjaString) (string, error) {
|
||||
|
|
246
ninja_writer.go
246
ninja_writer.go
|
@ -15,7 +15,6 @@
|
|||
package blueprint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
@ -29,13 +28,18 @@ const (
|
|||
|
||||
var indentString = strings.Repeat(" ", indentWidth*maxIndentDepth)
|
||||
|
||||
type StringWriterWriter interface {
|
||||
io.StringWriter
|
||||
io.Writer
|
||||
}
|
||||
|
||||
type ninjaWriter struct {
|
||||
writer io.Writer
|
||||
writer io.StringWriter
|
||||
|
||||
justDidBlankLine bool // true if the last operation was a BlankLine
|
||||
}
|
||||
|
||||
func newNinjaWriter(writer io.Writer) *ninjaWriter {
|
||||
func newNinjaWriter(writer io.StringWriter) *ninjaWriter {
|
||||
return &ninjaWriter{
|
||||
writer: writer,
|
||||
}
|
||||
|
@ -72,7 +76,7 @@ func (n *ninjaWriter) Comment(comment string) error {
|
|||
|
||||
if writeLine {
|
||||
line = strings.TrimSpace("# "+line) + "\n"
|
||||
_, err := io.WriteString(n.writer, line)
|
||||
_, err := n.writer.WriteString(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -82,7 +86,15 @@ func (n *ninjaWriter) Comment(comment string) error {
|
|||
|
||||
if lineStart != len(comment) {
|
||||
line := strings.TrimSpace(comment[lineStart:])
|
||||
_, err := fmt.Fprintf(n.writer, "# %s\n", line)
|
||||
_, err := n.writer.WriteString("# ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString("\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -93,25 +105,24 @@ func (n *ninjaWriter) Comment(comment string) error {
|
|||
|
||||
func (n *ninjaWriter) Pool(name string) error {
|
||||
n.justDidBlankLine = false
|
||||
_, err := fmt.Fprintf(n.writer, "pool %s\n", name)
|
||||
return err
|
||||
return n.writeStatement("pool", name)
|
||||
}
|
||||
|
||||
func (n *ninjaWriter) Rule(name string) error {
|
||||
n.justDidBlankLine = false
|
||||
_, err := fmt.Fprintf(n.writer, "rule %s\n", name)
|
||||
return err
|
||||
return n.writeStatement("rule", name)
|
||||
}
|
||||
|
||||
func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
||||
explicitDeps, implicitDeps, orderOnlyDeps, validations []string) error {
|
||||
explicitDeps, implicitDeps, orderOnlyDeps, validations []ninjaString,
|
||||
pkgNames map[*packageContext]string) error {
|
||||
|
||||
n.justDidBlankLine = false
|
||||
|
||||
const lineWrapLen = len(" $")
|
||||
const maxLineLen = lineWidth - lineWrapLen
|
||||
|
||||
wrapper := ninjaWriterWithWrap{
|
||||
wrapper := &ninjaWriterWithWrap{
|
||||
ninjaWriter: n,
|
||||
maxLineLen: maxLineLen,
|
||||
}
|
||||
|
@ -126,14 +137,16 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
|||
wrapper.WriteString("build")
|
||||
|
||||
for _, output := range outputs {
|
||||
wrapper.WriteStringWithSpace(output)
|
||||
wrapper.Space()
|
||||
output.ValueWithEscaper(wrapper, pkgNames, outputEscaper)
|
||||
}
|
||||
|
||||
if len(implicitOuts) > 0 {
|
||||
wrapper.WriteStringWithSpace("|")
|
||||
|
||||
for _, out := range implicitOuts {
|
||||
wrapper.WriteStringWithSpace(out)
|
||||
wrapper.Space()
|
||||
out.ValueWithEscaper(wrapper, pkgNames, outputEscaper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,14 +155,16 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
|||
wrapper.WriteStringWithSpace(rule)
|
||||
|
||||
for _, dep := range explicitDeps {
|
||||
wrapper.WriteStringWithSpace(dep)
|
||||
wrapper.Space()
|
||||
dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper)
|
||||
}
|
||||
|
||||
if len(implicitDeps) > 0 {
|
||||
wrapper.WriteStringWithSpace("|")
|
||||
|
||||
for _, dep := range implicitDeps {
|
||||
wrapper.WriteStringWithSpace(dep)
|
||||
wrapper.Space()
|
||||
dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +172,8 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
|||
wrapper.WriteStringWithSpace("||")
|
||||
|
||||
for _, dep := range orderOnlyDeps {
|
||||
wrapper.WriteStringWithSpace(dep)
|
||||
wrapper.Space()
|
||||
dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +181,8 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
|||
wrapper.WriteStringWithSpace("|@")
|
||||
|
||||
for _, dep := range validations {
|
||||
wrapper.WriteStringWithSpace(dep)
|
||||
wrapper.Space()
|
||||
dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,23 +191,57 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
|
|||
|
||||
func (n *ninjaWriter) Assign(name, value string) error {
|
||||
n.justDidBlankLine = false
|
||||
_, err := fmt.Fprintf(n.writer, "%s = %s\n", name, value)
|
||||
return err
|
||||
_, err := n.writer.WriteString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(" = ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString("\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ninjaWriter) ScopedAssign(name, value string) error {
|
||||
n.justDidBlankLine = false
|
||||
_, err := fmt.Fprintf(n.writer, "%s%s = %s\n", indentString[:indentWidth], name, value)
|
||||
return err
|
||||
_, err := n.writer.WriteString(indentString[:indentWidth])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(" = ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString("\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ninjaWriter) Default(targets ...string) error {
|
||||
func (n *ninjaWriter) Default(pkgNames map[*packageContext]string, targets ...ninjaString) error {
|
||||
n.justDidBlankLine = false
|
||||
|
||||
const lineWrapLen = len(" $")
|
||||
const maxLineLen = lineWidth - lineWrapLen
|
||||
|
||||
wrapper := ninjaWriterWithWrap{
|
||||
wrapper := &ninjaWriterWithWrap{
|
||||
ninjaWriter: n,
|
||||
maxLineLen: maxLineLen,
|
||||
}
|
||||
|
@ -198,7 +249,8 @@ func (n *ninjaWriter) Default(targets ...string) error {
|
|||
wrapper.WriteString("default")
|
||||
|
||||
for _, target := range targets {
|
||||
wrapper.WriteString(" " + target)
|
||||
wrapper.Space()
|
||||
target.ValueWithEscaper(wrapper, pkgNames, outputEscaper)
|
||||
}
|
||||
|
||||
return wrapper.Flush()
|
||||
|
@ -206,71 +258,157 @@ func (n *ninjaWriter) Default(targets ...string) error {
|
|||
|
||||
func (n *ninjaWriter) Subninja(file string) error {
|
||||
n.justDidBlankLine = false
|
||||
_, err := fmt.Fprintf(n.writer, "subninja %s\n", file)
|
||||
return err
|
||||
return n.writeStatement("subninja", file)
|
||||
}
|
||||
|
||||
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")
|
||||
_, err = n.writer.WriteString("\n")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type ninjaWriterWithWrap struct {
|
||||
*ninjaWriter
|
||||
maxLineLen int
|
||||
writtenLen int
|
||||
err error
|
||||
func (n *ninjaWriter) writeStatement(directive, name string) error {
|
||||
_, err := n.writer.WriteString(directive + " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = n.writer.WriteString("\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ninjaWriterWithWrap) writeString(s string, space bool) {
|
||||
// ninjaWriterWithWrap is an io.StringWriter that writes through to a ninjaWriter, but supports
|
||||
// user-readable line wrapping on boundaries when ninjaWriterWithWrap.Space is called.
|
||||
// It collects incoming calls to WriteString until either the line length is exceeded, in which case
|
||||
// it inserts a wrap before the pending strings and then writes them, or the next call to Space, in
|
||||
// which case it writes out the pending strings.
|
||||
//
|
||||
// WriteString never returns an error, all errors are held until Flush is called. Once an error has
|
||||
// occurred all writes become noops.
|
||||
type ninjaWriterWithWrap struct {
|
||||
*ninjaWriter
|
||||
// pending lists the strings that have been written since the last call to Space.
|
||||
pending []string
|
||||
|
||||
// pendingLen accumulates the lengths of the strings in pending.
|
||||
pendingLen int
|
||||
|
||||
// lineLen accumulates the number of bytes on the current line.
|
||||
lineLen int
|
||||
|
||||
// maxLineLen is the length of the line before wrapping.
|
||||
maxLineLen int
|
||||
|
||||
// space is true if the strings in pending should be preceded by a space.
|
||||
space bool
|
||||
|
||||
// err holds any error that has occurred to return in Flush.
|
||||
err error
|
||||
}
|
||||
|
||||
// WriteString writes the string to buffer, wrapping on a previous Space call if necessary.
|
||||
// It never returns an error, all errors are held until Flush is called.
|
||||
func (n *ninjaWriterWithWrap) WriteString(s string) (written int, noError error) {
|
||||
// Always return the full length of the string and a nil error.
|
||||
// ninjaWriterWithWrap doesn't return errors to the caller, it saves them until Flush()
|
||||
written = len(s)
|
||||
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
spaceLen := 0
|
||||
if space {
|
||||
spaceLen = 1
|
||||
}
|
||||
|
||||
if n.writtenLen+len(s)+spaceLen > n.maxLineLen {
|
||||
_, n.err = io.WriteString(n.writer, " $\n")
|
||||
const spaceLen = 1
|
||||
if !n.space {
|
||||
// No space is pending, so a line wrap can't be inserted before this, so just write
|
||||
// the string.
|
||||
n.lineLen += len(s)
|
||||
_, n.err = n.writer.WriteString(s)
|
||||
} else if n.lineLen+len(s)+spaceLen > n.maxLineLen {
|
||||
// A space is pending, and the pending strings plus the current string would exceed the
|
||||
// maximum line length. Wrap and indent before the pending space and strings, then write
|
||||
// the pending and current strings.
|
||||
_, n.err = n.writer.WriteString(" $\n")
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
_, n.err = io.WriteString(n.writer, indentString[:indentWidth*2])
|
||||
_, n.err = n.writer.WriteString(indentString[:indentWidth*2])
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
n.writtenLen = indentWidth * 2
|
||||
n.lineLen = indentWidth*2 + n.pendingLen
|
||||
s = strings.TrimLeftFunc(s, unicode.IsSpace)
|
||||
} else if space {
|
||||
_, n.err = io.WriteString(n.writer, " ")
|
||||
n.pending = append(n.pending, s)
|
||||
n.writePending()
|
||||
|
||||
n.space = false
|
||||
} else {
|
||||
// A space is pending but the current string would not reach the maximum line length,
|
||||
// add it to the pending list.
|
||||
n.pending = append(n.pending, s)
|
||||
n.pendingLen += len(s)
|
||||
n.lineLen += len(s)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Space inserts a space that is also a possible wrapping point into the string.
|
||||
func (n *ninjaWriterWithWrap) Space() {
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
if n.space {
|
||||
// A space was already pending, and the space plus any strings written after the space did
|
||||
// not reach the maxmimum line length, so write out the old space and pending strings.
|
||||
_, n.err = n.writer.WriteString(" ")
|
||||
n.lineLen++
|
||||
n.writePending()
|
||||
}
|
||||
n.space = true
|
||||
}
|
||||
|
||||
// writePending writes out all the strings stored in pending and resets it.
|
||||
func (n *ninjaWriterWithWrap) writePending() {
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
for _, pending := range n.pending {
|
||||
_, n.err = n.writer.WriteString(pending)
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
n.writtenLen++
|
||||
}
|
||||
|
||||
_, n.err = io.WriteString(n.writer, s)
|
||||
n.writtenLen += len(s)
|
||||
}
|
||||
|
||||
func (n *ninjaWriterWithWrap) WriteString(s string) {
|
||||
n.writeString(s, false)
|
||||
// Reset the length of pending back to 0 without reducing its capacity to avoid reallocating
|
||||
// the backing array.
|
||||
n.pending = n.pending[:0]
|
||||
n.pendingLen = 0
|
||||
}
|
||||
|
||||
// WriteStringWithSpace is a helper that calls Space and WriteString.
|
||||
func (n *ninjaWriterWithWrap) WriteStringWithSpace(s string) {
|
||||
n.writeString(s, true)
|
||||
n.Space()
|
||||
_, _ = n.WriteString(s)
|
||||
}
|
||||
|
||||
// Flush writes out any pending space or strings and then a newline. It also returns any errors
|
||||
// that have previously occurred.
|
||||
func (n *ninjaWriterWithWrap) Flush() error {
|
||||
if n.space {
|
||||
_, n.err = n.writer.WriteString(" ")
|
||||
}
|
||||
n.writePending()
|
||||
if n.err != nil {
|
||||
return n.err
|
||||
}
|
||||
_, err := io.WriteString(n.writer, "\n")
|
||||
_, err := n.writer.WriteString("\n")
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package blueprint
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -49,14 +50,26 @@ var ninjaWriterTestCases = []struct {
|
|||
},
|
||||
{
|
||||
input: func(w *ninjaWriter) {
|
||||
ck(w.Build("foo comment", "foo", []string{"o1", "o2"}, []string{"io1", "io2"},
|
||||
[]string{"e1", "e2"}, []string{"i1", "i2"}, []string{"oo1", "oo2"}, []string{"v1", "v2"}))
|
||||
ck(w.Build("foo comment", "foo", testNinjaStrings("o1", "o2"),
|
||||
testNinjaStrings("io1", "io2"), testNinjaStrings("e1", "e2"),
|
||||
testNinjaStrings("i1", "i2"), testNinjaStrings("oo1", "oo2"),
|
||||
testNinjaStrings("v1", "v2"), nil))
|
||||
},
|
||||
output: "# foo comment\nbuild o1 o2 | io1 io2: foo e1 e2 | i1 i2 || oo1 oo2 |@ v1 v2\n",
|
||||
},
|
||||
{
|
||||
input: func(w *ninjaWriter) {
|
||||
ck(w.Default("foo"))
|
||||
ck(w.Build("foo comment", "foo",
|
||||
testNinjaStrings(strings.Repeat("o", lineWidth)),
|
||||
nil,
|
||||
testNinjaStrings(strings.Repeat("i", lineWidth)),
|
||||
nil, nil, nil, nil))
|
||||
},
|
||||
output: "# foo comment\nbuild $\n " + strings.Repeat("o", lineWidth) + ": foo $\n " + strings.Repeat("i", lineWidth) + "\n",
|
||||
},
|
||||
{
|
||||
input: func(w *ninjaWriter) {
|
||||
ck(w.Default(nil, testNinjaStrings("foo")...))
|
||||
},
|
||||
output: "default foo\n",
|
||||
},
|
||||
|
@ -94,7 +107,8 @@ var ninjaWriterTestCases = []struct {
|
|||
ck(w.ScopedAssign("command", "echo out: $out in: $in _arg: $_arg"))
|
||||
ck(w.ScopedAssign("pool", "p"))
|
||||
ck(w.BlankLine())
|
||||
ck(w.Build("r comment", "r", []string{"foo.o"}, nil, []string{"foo.in"}, nil, nil, nil))
|
||||
ck(w.Build("r comment", "r", testNinjaStrings("foo.o"),
|
||||
nil, testNinjaStrings("foo.in"), nil, nil, nil, nil))
|
||||
ck(w.ScopedAssign("_arg", "arg value"))
|
||||
},
|
||||
output: `pool p
|
||||
|
@ -124,3 +138,8 @@ func TestNinjaWriter(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testNinjaStrings(s ...string) []ninjaString {
|
||||
ret, _ := parseNinjaStrings(nil, s)
|
||||
return ret
|
||||
}
|
||||
|
|
108
package_ctx.go
108
package_ctx.go
|
@ -250,9 +250,10 @@ func (p *packageContext) ImportAs(as, pkgPath string) {
|
|||
}
|
||||
|
||||
type staticVariable struct {
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
value_ string
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
value_ string
|
||||
fullName_ string
|
||||
}
|
||||
|
||||
// StaticVariable returns a Variable whose value does not depend on any
|
||||
|
@ -271,7 +272,11 @@ func (p *packageContext) StaticVariable(name, value string) Variable {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
v := &staticVariable{p, name, value}
|
||||
v := &staticVariable{
|
||||
pctx: p,
|
||||
name_: name,
|
||||
value_: value,
|
||||
}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -289,9 +294,16 @@ func (v *staticVariable) name() string {
|
|||
}
|
||||
|
||||
func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string {
|
||||
if v.fullName_ != "" {
|
||||
return v.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
|
||||
}
|
||||
|
||||
func (v *staticVariable) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
v.fullName_ = v.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (v *staticVariable) value(interface{}) (ninjaString, error) {
|
||||
ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
|
||||
if err != nil {
|
||||
|
@ -306,9 +318,10 @@ func (v *staticVariable) String() string {
|
|||
}
|
||||
|
||||
type variableFunc struct {
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
value_ func(interface{}) (string, error)
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
value_ func(interface{}) (string, error)
|
||||
fullName_ string
|
||||
}
|
||||
|
||||
// VariableFunc returns a Variable whose value is determined by a function that
|
||||
|
@ -332,7 +345,11 @@ func (p *packageContext) VariableFunc(name string,
|
|||
panic(err)
|
||||
}
|
||||
|
||||
v := &variableFunc{p, name, f}
|
||||
v := &variableFunc{
|
||||
pctx: p,
|
||||
name_: name,
|
||||
value_: f,
|
||||
}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -371,7 +388,11 @@ func (p *packageContext) VariableConfigMethod(name string,
|
|||
return resultStr, nil
|
||||
}
|
||||
|
||||
v := &variableFunc{p, name, fun}
|
||||
v := &variableFunc{
|
||||
pctx: p,
|
||||
name_: name,
|
||||
value_: fun,
|
||||
}
|
||||
err = p.scope.AddVariable(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -389,9 +410,16 @@ func (v *variableFunc) name() string {
|
|||
}
|
||||
|
||||
func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string {
|
||||
if v.fullName_ != "" {
|
||||
return v.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
|
||||
}
|
||||
|
||||
func (v *variableFunc) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
v.fullName_ = v.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (v *variableFunc) value(config interface{}) (ninjaString, error) {
|
||||
value, err := v.value_(config)
|
||||
if err != nil {
|
||||
|
@ -452,6 +480,10 @@ func (v *argVariable) fullName(pkgNames map[*packageContext]string) string {
|
|||
return v.name_
|
||||
}
|
||||
|
||||
func (v *argVariable) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
// Nothing to do, full name is known at initialization.
|
||||
}
|
||||
|
||||
func (v *argVariable) value(config interface{}) (ninjaString, error) {
|
||||
return nil, errVariableIsArg
|
||||
}
|
||||
|
@ -461,9 +493,10 @@ func (v *argVariable) String() string {
|
|||
}
|
||||
|
||||
type staticPool struct {
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
params PoolParams
|
||||
pctx *packageContext
|
||||
name_ string
|
||||
params PoolParams
|
||||
fullName_ string
|
||||
}
|
||||
|
||||
// StaticPool returns a Pool whose value does not depend on any configuration
|
||||
|
@ -483,7 +516,11 @@ func (p *packageContext) StaticPool(name string, params PoolParams) Pool {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
pool := &staticPool{p, name, params}
|
||||
pool := &staticPool{
|
||||
pctx: p,
|
||||
name_: name,
|
||||
params: params,
|
||||
}
|
||||
err = p.scope.AddPool(pool)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -501,9 +538,16 @@ func (p *staticPool) name() string {
|
|||
}
|
||||
|
||||
func (p *staticPool) fullName(pkgNames map[*packageContext]string) string {
|
||||
if p.fullName_ != "" {
|
||||
return p.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
|
||||
}
|
||||
|
||||
func (p *staticPool) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
p.fullName_ = p.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (p *staticPool) def(config interface{}) (*poolDef, error) {
|
||||
def, err := parsePoolParams(p.pctx.scope, &p.params)
|
||||
if err != nil {
|
||||
|
@ -520,6 +564,7 @@ type poolFunc struct {
|
|||
pctx *packageContext
|
||||
name_ string
|
||||
paramsFunc func(interface{}) (PoolParams, error)
|
||||
fullName_ string
|
||||
}
|
||||
|
||||
// PoolFunc returns a Pool whose value is determined by a function that takes a
|
||||
|
@ -542,7 +587,11 @@ func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
|
|||
panic(err)
|
||||
}
|
||||
|
||||
pool := &poolFunc{p, name, f}
|
||||
pool := &poolFunc{
|
||||
pctx: p,
|
||||
name_: name,
|
||||
paramsFunc: f,
|
||||
}
|
||||
err = p.scope.AddPool(pool)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -560,9 +609,16 @@ func (p *poolFunc) name() string {
|
|||
}
|
||||
|
||||
func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string {
|
||||
if p.fullName_ != "" {
|
||||
return p.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
|
||||
}
|
||||
|
||||
func (p *poolFunc) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
p.fullName_ = p.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (p *poolFunc) def(config interface{}) (*poolDef, error) {
|
||||
params, err := p.paramsFunc(config)
|
||||
if err != nil {
|
||||
|
@ -595,6 +651,10 @@ func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string {
|
|||
return p.name_
|
||||
}
|
||||
|
||||
func (p *builtinPool) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
// Nothing to do, full name is known at initialization.
|
||||
}
|
||||
|
||||
func (p *builtinPool) def(config interface{}) (*poolDef, error) {
|
||||
return nil, errPoolIsBuiltin
|
||||
}
|
||||
|
@ -616,6 +676,7 @@ type staticRule struct {
|
|||
params RuleParams
|
||||
argNames map[string]bool
|
||||
scope_ *basicScope
|
||||
fullName_ string
|
||||
sync.Mutex // protects scope_ during lazy creation
|
||||
}
|
||||
|
||||
|
@ -683,9 +744,16 @@ func (r *staticRule) name() string {
|
|||
}
|
||||
|
||||
func (r *staticRule) fullName(pkgNames map[*packageContext]string) string {
|
||||
if r.fullName_ != "" {
|
||||
return r.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
|
||||
}
|
||||
|
||||
func (r *staticRule) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
r.fullName_ = r.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (r *staticRule) def(interface{}) (*ruleDef, error) {
|
||||
def, err := parseRuleParams(r.scope(), &r.params)
|
||||
if err != nil {
|
||||
|
@ -721,6 +789,7 @@ type ruleFunc struct {
|
|||
paramsFunc func(interface{}) (RuleParams, error)
|
||||
argNames map[string]bool
|
||||
scope_ *basicScope
|
||||
fullName_ string
|
||||
sync.Mutex // protects scope_ during lazy creation
|
||||
}
|
||||
|
||||
|
@ -789,9 +858,16 @@ func (r *ruleFunc) name() string {
|
|||
}
|
||||
|
||||
func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string {
|
||||
if r.fullName_ != "" {
|
||||
return r.fullName_
|
||||
}
|
||||
return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
|
||||
}
|
||||
|
||||
func (r *ruleFunc) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
r.fullName_ = r.fullName(pkgNames)
|
||||
}
|
||||
|
||||
func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
|
||||
params, err := r.paramsFunc(config)
|
||||
if err != nil {
|
||||
|
@ -843,6 +919,10 @@ func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string {
|
|||
return r.name_
|
||||
}
|
||||
|
||||
func (r *builtinRule) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
// Nothing to do, full name is known at initialization.
|
||||
}
|
||||
|
||||
func (r *builtinRule) def(config interface{}) (*ruleDef, error) {
|
||||
return nil, errRuleIsBuiltin
|
||||
}
|
||||
|
|
51
scope.go
51
scope.go
|
@ -28,6 +28,7 @@ type Variable interface {
|
|||
packageContext() *packageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired
|
||||
value(config interface{}) (ninjaString, error)
|
||||
String() string
|
||||
}
|
||||
|
@ -38,6 +39,7 @@ type Pool interface {
|
|||
packageContext() *packageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired
|
||||
def(config interface{}) (*poolDef, error)
|
||||
String() string
|
||||
}
|
||||
|
@ -48,6 +50,7 @@ type Rule interface {
|
|||
packageContext() *packageContext
|
||||
name() string // "foo"
|
||||
fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
|
||||
memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired
|
||||
def(config interface{}) (*ruleDef, error)
|
||||
scope() *basicScope
|
||||
isArg(argName string) bool
|
||||
|
@ -294,9 +297,9 @@ func (s *localScope) AddLocalVariable(name, value string) (*localVariable,
|
|||
}
|
||||
|
||||
v := &localVariable{
|
||||
namePrefix: s.namePrefix,
|
||||
name_: name,
|
||||
value_: ninjaValue,
|
||||
fullName_: s.namePrefix + name,
|
||||
name_: name,
|
||||
value_: ninjaValue,
|
||||
}
|
||||
|
||||
err = s.scope.AddVariable(v)
|
||||
|
@ -333,11 +336,11 @@ func (s *localScope) AddLocalRule(name string, params *RuleParams,
|
|||
}
|
||||
|
||||
r := &localRule{
|
||||
namePrefix: s.namePrefix,
|
||||
name_: name,
|
||||
def_: def,
|
||||
argNames: argNamesSet,
|
||||
scope_: ruleScope,
|
||||
fullName_: s.namePrefix + name,
|
||||
name_: name,
|
||||
def_: def,
|
||||
argNames: argNamesSet,
|
||||
scope_: ruleScope,
|
||||
}
|
||||
|
||||
err = s.scope.AddRule(r)
|
||||
|
@ -349,9 +352,9 @@ func (s *localScope) AddLocalRule(name string, params *RuleParams,
|
|||
}
|
||||
|
||||
type localVariable struct {
|
||||
namePrefix string
|
||||
name_ string
|
||||
value_ ninjaString
|
||||
fullName_ string
|
||||
name_ string
|
||||
value_ ninjaString
|
||||
}
|
||||
|
||||
func (l *localVariable) packageContext() *packageContext {
|
||||
|
@ -363,7 +366,11 @@ func (l *localVariable) name() string {
|
|||
}
|
||||
|
||||
func (l *localVariable) fullName(pkgNames map[*packageContext]string) string {
|
||||
return l.namePrefix + l.name_
|
||||
return l.fullName_
|
||||
}
|
||||
|
||||
func (l *localVariable) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
// Nothing to do, full name is known at initialization.
|
||||
}
|
||||
|
||||
func (l *localVariable) value(interface{}) (ninjaString, error) {
|
||||
|
@ -371,15 +378,15 @@ func (l *localVariable) value(interface{}) (ninjaString, error) {
|
|||
}
|
||||
|
||||
func (l *localVariable) String() string {
|
||||
return "<local var>:" + l.namePrefix + l.name_
|
||||
return "<local var>:" + l.fullName_
|
||||
}
|
||||
|
||||
type localRule struct {
|
||||
namePrefix string
|
||||
name_ string
|
||||
def_ *ruleDef
|
||||
argNames map[string]bool
|
||||
scope_ *basicScope
|
||||
fullName_ string
|
||||
name_ string
|
||||
def_ *ruleDef
|
||||
argNames map[string]bool
|
||||
scope_ *basicScope
|
||||
}
|
||||
|
||||
func (l *localRule) packageContext() *packageContext {
|
||||
|
@ -391,7 +398,11 @@ func (l *localRule) name() string {
|
|||
}
|
||||
|
||||
func (l *localRule) fullName(pkgNames map[*packageContext]string) string {
|
||||
return l.namePrefix + l.name_
|
||||
return l.fullName_
|
||||
}
|
||||
|
||||
func (l *localRule) memoizeFullName(pkgNames map[*packageContext]string) {
|
||||
// Nothing to do, full name is known at initialization.
|
||||
}
|
||||
|
||||
func (l *localRule) def(interface{}) (*ruleDef, error) {
|
||||
|
@ -407,5 +418,5 @@ func (r *localRule) isArg(argName string) bool {
|
|||
}
|
||||
|
||||
func (r *localRule) String() string {
|
||||
return "<local rule>:" + r.namePrefix + r.name_
|
||||
return "<local rule>:" + r.fullName_
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue