blob: 5b93c200e3438d7cec2d9d2159fdec43d88bc981 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
18 "errors"
19 "fmt"
Jamie Gennis28a63fb2014-06-05 19:50:44 -070020 "reflect"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070021 "runtime"
22 "strings"
Colin Cross691a60d2015-01-07 18:08:56 -080023 "sync"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070024)
25
Jamie Gennis2fb20952014-10-03 02:49:58 -070026// A PackageContext provides a way to create package-scoped Ninja pools,
27// rules, and variables. A Go package should create a single unexported
28// package-scoped PackageContext variable that it uses to create all package-
29// scoped Ninja object definitions. This PackageContext object should then be
30// passed to all calls to define module- or singleton-specific Ninja
31// definitions. For example:
32//
33// package blah
34//
35// import (
36// "blueprint"
37// )
38//
39// var (
40// pctx = NewPackageContext("path/to/blah")
41//
42// myPrivateVar = pctx.StaticVariable("myPrivateVar", "abcdef")
43// MyExportedVar = pctx.StaticVariable("MyExportedVar", "$myPrivateVar 123456!")
44//
45// SomeRule = pctx.StaticRule(...)
46// )
47//
48// // ...
49//
50// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
51// ctx.Build(pctx, blueprint.BuildParams{
52// Rule: SomeRule,
53// Outputs: []string{"$myPrivateVar"},
54// })
55// }
Dan Willemsenaeffbf72015-11-25 15:29:32 -080056type PackageContext interface {
57 Import(pkgPath string)
58 ImportAs(as, pkgPath string)
59
60 StaticVariable(name, value string) Variable
61 VariableFunc(name string, f func(config interface{}) (string, error)) Variable
62 VariableConfigMethod(name string, method interface{}) Variable
63
64 StaticPool(name string, params PoolParams) Pool
65 PoolFunc(name string, f func(interface{}) (PoolParams, error)) Pool
66
67 StaticRule(name string, params RuleParams, argNames ...string) Rule
68 RuleFunc(name string, f func(interface{}) (RuleParams, error), argNames ...string) Rule
69
70 getScope() *basicScope
71}
72
73type packageContext struct {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074 fullName string
75 shortName string
76 pkgPath string
Jamie Gennis48aed8c2014-06-13 18:25:54 -070077 scope *basicScope
Jamie Gennis1bc967e2014-05-27 16:34:41 -070078}
Dan Willemsenaeffbf72015-11-25 15:29:32 -080079var _ PackageContext = &packageContext{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070080
Dan Willemsenaeffbf72015-11-25 15:29:32 -080081func (p *packageContext) getScope() *basicScope {
82 return p.scope
83}
84
85var packageContexts = map[string]*packageContext{}
Jamie Gennis2fb20952014-10-03 02:49:58 -070086
87// NewPackageContext creates a PackageContext object for a given package. The
88// pkgPath argument should always be set to the full path used to import the
89// package. This function may only be called from a Go package's init()
90// function or as part of a package-scoped variable initialization.
Dan Willemsenaeffbf72015-11-25 15:29:32 -080091func NewPackageContext(pkgPath string) PackageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -070092 checkCalledFromInit()
93
94 if _, present := packageContexts[pkgPath]; present {
95 panic(fmt.Errorf("package %q already has a package context"))
96 }
97
98 pkgName := pkgPathToName(pkgPath)
99 err := validateNinjaName(pkgName)
100 if err != nil {
101 panic(err)
102 }
103
104 i := strings.LastIndex(pkgPath, "/")
105 shortName := pkgPath[i+1:]
106
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800107 p := &packageContext{
Jamie Gennis2fb20952014-10-03 02:49:58 -0700108 fullName: pkgName,
109 shortName: shortName,
110 pkgPath: pkgPath,
111 scope: newScope(nil),
112 }
113
114 packageContexts[pkgPath] = p
115
116 return p
117}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119var Phony Rule = &builtinRule{
120 name_: "phony",
121}
122
Ken Oslund4b9a0512015-04-14 16:26:58 -0700123var Console Pool = &builtinPool{
124 name_: "console",
125}
126
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700127var errRuleIsBuiltin = errors.New("the rule is a built-in")
Ken Oslund4b9a0512015-04-14 16:26:58 -0700128var errPoolIsBuiltin = errors.New("the pool is a built-in")
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700129var errVariableIsArg = errors.New("argument variables have no value")
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700130
Jamie Gennis2fb20952014-10-03 02:49:58 -0700131// checkCalledFromInit panics if a Go package's init function is not on the
132// call stack.
133func checkCalledFromInit() {
134 for skip := 3; ; skip++ {
135 _, funcName, ok := callerName(skip)
136 if !ok {
137 panic("not called from an init func")
138 }
139
140 if funcName == "init" || strings.HasPrefix(funcName, "init·") {
141 return
142 }
143 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700144}
145
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700146// callerName returns the package path and function name of the calling
147// function. The skip argument has the same meaning as the skip argument of
148// runtime.Callers.
Jamie Gennis2fb20952014-10-03 02:49:58 -0700149func callerName(skip int) (pkgPath, funcName string, ok bool) {
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700150 var pc [1]uintptr
151 n := runtime.Callers(skip+1, pc[:])
152 if n != 1 {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700153 return "", "", false
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700154 }
155
156 f := runtime.FuncForPC(pc[0])
157 fullName := f.Name()
158
159 lastDotIndex := strings.LastIndex(fullName, ".")
160 if lastDotIndex == -1 {
161 panic("unable to distinguish function name from package")
162 }
163
164 if fullName[lastDotIndex-1] == ')' {
165 // The caller is a method on some type, so it's name looks like
166 // "pkg/path.(type).method". We need to go back one dot farther to get
167 // to the package name.
168 lastDotIndex = strings.LastIndex(fullName[:lastDotIndex], ".")
169 }
170
171 pkgPath = fullName[:lastDotIndex]
172 funcName = fullName[lastDotIndex+1:]
Jamie Gennis2fb20952014-10-03 02:49:58 -0700173 ok = true
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700174 return
175}
176
Jamie Gennis2fb20952014-10-03 02:49:58 -0700177// pkgPathToName makes a Ninja-friendly name out of a Go package name by
178// replaceing all the '/' characters with '.'. We assume the results are
179// unique, though this is not 100% guaranteed for Go package names that
180// already contain '.' characters. Disallowing package names with '.' isn't
181// reasonable since many package names contain the name of the hosting site
182// (e.g. "code.google.com"). In practice this probably isn't really a
183// problem.
184func pkgPathToName(pkgPath string) string {
185 return strings.Replace(pkgPath, "/", ".", -1)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700186}
187
Jamie Gennis2fb20952014-10-03 02:49:58 -0700188// Import enables access to the exported Ninja pools, rules, and variables
189// that are defined at the package scope of another Go package. Go's
190// visibility rules apply to these references - capitalized names indicate
191// that something is exported. It may only be called from a Go package's
192// init() function. The Go package path passed to Import must have already
193// been imported into the Go package using a Go import statement. The
194// imported variables may then be accessed from Ninja strings as
195// "${pkg.Variable}", while the imported rules can simply be accessed as
196// exported Go variables from the package. For example:
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700197//
198// import (
199// "blueprint"
200// "foo/bar"
201// )
202//
Jamie Gennis2fb20952014-10-03 02:49:58 -0700203// var pctx = NewPackagePath("blah")
204//
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700205// func init() {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700206// pctx.Import("foo/bar")
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700207// }
208//
209// ...
210//
211// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700212// ctx.Build(pctx, blueprint.BuildParams{
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700213// Rule: bar.SomeRule,
214// Outputs: []string{"${bar.SomeVariable}"},
215// })
216// }
Jamie Gennisd4e10182014-06-12 20:06:50 -0700217//
218// Note that the local name used to refer to the package in Ninja variable names
219// is derived from pkgPath by extracting the last path component. This differs
220// from Go's import declaration, which derives the local name from the package
221// clause in the imported package. By convention these names are made to match,
222// but this is not required.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800223func (p *packageContext) Import(pkgPath string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700224 checkCalledFromInit()
225 importPkg, ok := packageContexts[pkgPath]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226 if !ok {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700227 panic(fmt.Errorf("package %q has no context", pkgPath))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700228 }
229
Jamie Gennis2fb20952014-10-03 02:49:58 -0700230 err := p.scope.AddImport(importPkg.shortName, importPkg.scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700231 if err != nil {
232 panic(err)
233 }
234}
235
Jamie Gennisd4e10182014-06-12 20:06:50 -0700236// ImportAs provides the same functionality as Import, but it allows the local
237// name that will be used to refer to the package to be specified explicitly.
238// It may only be called from a Go package's init() function.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800239func (p *packageContext) ImportAs(as, pkgPath string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700240 checkCalledFromInit()
241 importPkg, ok := packageContexts[pkgPath]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700242 if !ok {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700243 panic(fmt.Errorf("package %q has no context", pkgPath))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700244 }
245
246 err := validateNinjaName(as)
247 if err != nil {
248 panic(err)
249 }
250
Jamie Gennis2fb20952014-10-03 02:49:58 -0700251 err = p.scope.AddImport(as, importPkg.scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700252 if err != nil {
253 panic(err)
254 }
255}
256
257type staticVariable struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800258 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700259 name_ string
260 value_ string
261}
262
Jamie Gennisd4e10182014-06-12 20:06:50 -0700263// StaticVariable returns a Variable whose value does not depend on any
264// configuration information. It may only be called during a Go package's
265// initialization - either from the init() function or as part of a package-
266// scoped variable's initialization.
267//
268// This function is usually used to initialize a package-scoped Go variable that
269// represents a Ninja variable that will be output. The name argument should
270// exactly match the Go variable name, and the value string may reference other
271// Ninja variables that are visible within the calling Go package.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800272func (p *packageContext) StaticVariable(name, value string) Variable {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700273 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700274 err := validateNinjaName(name)
275 if err != nil {
276 panic(err)
277 }
278
Jamie Gennis2fb20952014-10-03 02:49:58 -0700279 v := &staticVariable{p, name, value}
280 err = p.scope.AddVariable(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700281 if err != nil {
282 panic(err)
283 }
284
285 return v
286}
287
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800288func (v *staticVariable) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700289 return v.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700290}
291
292func (v *staticVariable) name() string {
293 return v.name_
294}
295
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800296func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700297 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700298}
299
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700300func (v *staticVariable) value(interface{}) (*ninjaString, error) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700301 ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700302 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700303 err = fmt.Errorf("error parsing variable %s value: %s", v, err)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700304 panic(err)
305 }
306 return ninjaStr, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700307}
308
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700309func (v *staticVariable) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700310 return v.pctx.pkgPath + "." + v.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700311}
312
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700313type variableFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800314 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700315 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700316 value_ func(interface{}) (string, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700317}
318
319// VariableFunc returns a Variable whose value is determined by a function that
Jamie Gennisd4e10182014-06-12 20:06:50 -0700320// takes a config object as input and returns either the variable value or an
321// error. It may only be called during a Go package's initialization - either
322// from the init() function or as part of a package-scoped variable's
323// initialization.
324//
325// This function is usually used to initialize a package-scoped Go variable that
326// represents a Ninja variable that will be output. The name argument should
327// exactly match the Go variable name, and the value string returned by f may
328// reference other Ninja variables that are visible within the calling Go
329// package.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800330func (p *packageContext) VariableFunc(name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700331 f func(config interface{}) (string, error)) Variable {
332
333 checkCalledFromInit()
Jamie Gennisd4e10182014-06-12 20:06:50 -0700334
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700335 err := validateNinjaName(name)
336 if err != nil {
337 panic(err)
338 }
339
Jamie Gennis2fb20952014-10-03 02:49:58 -0700340 v := &variableFunc{p, name, f}
341 err = p.scope.AddVariable(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700342 if err != nil {
343 panic(err)
344 }
345
346 return v
347}
348
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700349// VariableConfigMethod returns a Variable whose value is determined by calling
Jamie Gennisd4e10182014-06-12 20:06:50 -0700350// a method on the config object. The method must take no arguments and return
351// a single string that will be the variable's value. It may only be called
352// during a Go package's initialization - either from the init() function or as
353// part of a package-scoped variable's initialization.
354//
355// This function is usually used to initialize a package-scoped Go variable that
356// represents a Ninja variable that will be output. The name argument should
357// exactly match the Go variable name, and the value string returned by method
358// may reference other Ninja variables that are visible within the calling Go
359// package.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800360func (p *packageContext) VariableConfigMethod(name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700361 method interface{}) Variable {
362
363 checkCalledFromInit()
364
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700365 err := validateNinjaName(name)
366 if err != nil {
367 panic(err)
368 }
369
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700370 methodValue := reflect.ValueOf(method)
371 validateVariableMethod(name, methodValue)
372
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700373 fun := func(config interface{}) (string, error) {
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700374 result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)})
375 resultStr := result[0].Interface().(string)
376 return resultStr, nil
377 }
378
Jamie Gennis2fb20952014-10-03 02:49:58 -0700379 v := &variableFunc{p, name, fun}
380 err = p.scope.AddVariable(v)
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700381 if err != nil {
382 panic(err)
383 }
384
385 return v
386}
387
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800388func (v *variableFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700389 return v.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700390}
391
392func (v *variableFunc) name() string {
393 return v.name_
394}
395
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800396func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700397 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398}
399
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700400func (v *variableFunc) value(config interface{}) (*ninjaString, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700401 value, err := v.value_(config)
402 if err != nil {
403 return nil, err
404 }
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700405
Jamie Gennis2fb20952014-10-03 02:49:58 -0700406 ninjaStr, err := parseNinjaString(v.pctx.scope, value)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700407 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700408 err = fmt.Errorf("error parsing variable %s value: %s", v, err)
Jamie Gennis71bd58a2014-06-13 18:19:16 -0700409 panic(err)
410 }
411
412 return ninjaStr, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700413}
414
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700415func (v *variableFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700416 return v.pctx.pkgPath + "." + v.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700417}
418
Jamie Gennis28a63fb2014-06-05 19:50:44 -0700419func validateVariableMethod(name string, methodValue reflect.Value) {
420 methodType := methodValue.Type()
421 if methodType.Kind() != reflect.Func {
422 panic(fmt.Errorf("method given for variable %s is not a function",
423 name))
424 }
425 if n := methodType.NumIn(); n != 1 {
426 panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)",
427 name, n))
428 }
429 if n := methodType.NumOut(); n != 1 {
430 panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)",
431 name, n))
432 }
433 if kind := methodType.Out(0).Kind(); kind != reflect.String {
434 panic(fmt.Errorf("method for variable %s does not return a string",
435 name))
436 }
437}
438
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700439// An argVariable is a Variable that exists only when it is set by a build
440// statement to pass a value to the rule being invoked. It has no value, so it
441// can never be used to create a Ninja assignment statement. It is inserted
442// into the rule's scope, which is used for name lookups within the rule and
443// when assigning argument values as part of a build statement.
444type argVariable struct {
445 name_ string
446}
447
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800448func (v *argVariable) packageContext() *packageContext {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700449 panic("this should not be called")
450}
451
452func (v *argVariable) name() string {
453 return v.name_
454}
455
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800456func (v *argVariable) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700457 return v.name_
458}
459
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700460func (v *argVariable) value(config interface{}) (*ninjaString, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700461 return nil, errVariableIsArg
462}
463
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700464func (v *argVariable) String() string {
465 return "<arg>:" + v.name_
466}
467
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700468type staticPool struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800469 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700470 name_ string
471 params PoolParams
472}
473
Jamie Gennisd4e10182014-06-12 20:06:50 -0700474// StaticPool returns a Pool whose value does not depend on any configuration
475// information. It may only be called during a Go package's initialization -
476// either from the init() function or as part of a package-scoped Go variable's
477// initialization.
478//
479// This function is usually used to initialize a package-scoped Go variable that
480// represents a Ninja pool that will be output. The name argument should
481// exactly match the Go variable name, and the params fields may reference other
482// Ninja variables that are visible within the calling Go package.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800483func (p *packageContext) StaticPool(name string, params PoolParams) Pool {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700484 checkCalledFromInit()
485
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700486 err := validateNinjaName(name)
487 if err != nil {
488 panic(err)
489 }
490
Jamie Gennis2fb20952014-10-03 02:49:58 -0700491 pool := &staticPool{p, name, params}
492 err = p.scope.AddPool(pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700493 if err != nil {
494 panic(err)
495 }
496
Jamie Gennis2fb20952014-10-03 02:49:58 -0700497 return pool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700498}
499
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800500func (p *staticPool) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700501 return p.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700502}
503
504func (p *staticPool) name() string {
505 return p.name_
506}
507
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800508func (p *staticPool) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700509 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700510}
511
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700512func (p *staticPool) def(config interface{}) (*poolDef, error) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700513 def, err := parsePoolParams(p.pctx.scope, &p.params)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700514 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700515 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700516 }
517 return def, nil
518}
519
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700520func (p *staticPool) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700521 return p.pctx.pkgPath + "." + p.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700522}
523
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700524type poolFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800525 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700526 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700527 paramsFunc func(interface{}) (PoolParams, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700528}
529
Jamie Gennisd4e10182014-06-12 20:06:50 -0700530// PoolFunc returns a Pool whose value is determined by a function that takes a
531// config object as input and returns either the pool parameters or an error. It
532// may only be called during a Go package's initialization - either from the
533// init() function or as part of a package-scoped variable's initialization.
534//
535// This function is usually used to initialize a package-scoped Go variable that
536// represents a Ninja pool that will be output. The name argument should
537// exactly match the Go variable name, and the string fields of the PoolParams
538// returned by f may reference other Ninja variables that are visible within the
539// calling Go package.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800540func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700541 error)) Pool {
542
543 checkCalledFromInit()
544
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700545 err := validateNinjaName(name)
546 if err != nil {
547 panic(err)
548 }
549
Jamie Gennis2fb20952014-10-03 02:49:58 -0700550 pool := &poolFunc{p, name, f}
551 err = p.scope.AddPool(pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700552 if err != nil {
553 panic(err)
554 }
555
Jamie Gennis2fb20952014-10-03 02:49:58 -0700556 return pool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700557}
558
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800559func (p *poolFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700560 return p.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700561}
562
563func (p *poolFunc) name() string {
564 return p.name_
565}
566
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800567func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700568 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700569}
570
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700571func (p *poolFunc) def(config interface{}) (*poolDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700572 params, err := p.paramsFunc(config)
573 if err != nil {
574 return nil, err
575 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700576 def, err := parsePoolParams(p.pctx.scope, &params)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700577 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700578 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700579 }
580 return def, nil
581}
582
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700583func (p *poolFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700584 return p.pctx.pkgPath + "." + p.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700585}
586
Ken Oslund4b9a0512015-04-14 16:26:58 -0700587type builtinPool struct {
Colin Cross63d5d4d2015-04-20 16:41:55 -0700588 name_ string
Ken Oslund4b9a0512015-04-14 16:26:58 -0700589}
590
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800591func (p *builtinPool) packageContext() *packageContext {
Ken Oslund4b9a0512015-04-14 16:26:58 -0700592 return nil
593}
594
595func (p *builtinPool) name() string {
596 return p.name_
597}
598
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800599func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string {
Ken Oslund4b9a0512015-04-14 16:26:58 -0700600 return p.name_
601}
602
603func (p *builtinPool) def(config interface{}) (*poolDef, error) {
604 return nil, errPoolIsBuiltin
605}
606
607func (p *builtinPool) String() string {
608 return "<builtin>:" + p.name_
609}
610
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700611type staticRule struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800612 pctx *packageContext
Colin Cross691a60d2015-01-07 18:08:56 -0800613 name_ string
614 params RuleParams
615 argNames map[string]bool
616 scope_ *basicScope
617 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700618}
619
Jamie Gennisd4e10182014-06-12 20:06:50 -0700620// StaticRule returns a Rule whose value does not depend on any configuration
621// information. It may only be called during a Go package's initialization -
622// either from the init() function or as part of a package-scoped Go variable's
623// initialization.
624//
625// This function is usually used to initialize a package-scoped Go variable that
626// represents a Ninja rule that will be output. The name argument should
627// exactly match the Go variable name, and the params fields may reference other
628// Ninja variables that are visible within the calling Go package.
629//
630// The argNames arguments list Ninja variables that may be overridden by Ninja
631// build statements that invoke the rule. These arguments may be referenced in
632// any of the string fields of params. Arguments can shadow package-scoped
633// variables defined within the caller's Go package, but they may not shadow
634// those defined in another package. Shadowing a package-scoped variable
635// results in the package-scoped variable's value being used for build
636// statements that do not override the argument. For argument names that do not
637// shadow package-scoped variables the default value is an empty string.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800638func (p *packageContext) StaticRule(name string, params RuleParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700639 argNames ...string) Rule {
640
641 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700642
643 err := validateNinjaName(name)
644 if err != nil {
645 panic(err)
646 }
647
648 err = validateArgNames(argNames)
649 if err != nil {
650 panic(fmt.Errorf("invalid argument name: %s", err))
651 }
652
653 argNamesSet := make(map[string]bool)
654 for _, argName := range argNames {
655 argNamesSet[argName] = true
656 }
657
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700658 ruleScope := (*basicScope)(nil) // This will get created lazily
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700659
Colin Cross691a60d2015-01-07 18:08:56 -0800660 r := &staticRule{
661 pctx: p,
662 name_: name,
663 params: params,
664 argNames: argNamesSet,
665 scope_: ruleScope,
666 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700667 err = p.scope.AddRule(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700668 if err != nil {
669 panic(err)
670 }
671
672 return r
673}
674
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800675func (r *staticRule) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700676 return r.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700677}
678
679func (r *staticRule) name() string {
680 return r.name_
681}
682
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800683func (r *staticRule) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700684 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700685}
686
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700687func (r *staticRule) def(interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700688 def, err := parseRuleParams(r.scope(), &r.params)
689 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700690 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700691 }
692 return def, nil
693}
694
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700695func (r *staticRule) scope() *basicScope {
696 // We lazily create the scope so that all the package-scoped variables get
697 // declared before the args are created. Otherwise we could incorrectly
698 // shadow a package-scoped variable with an arg variable.
Colin Cross691a60d2015-01-07 18:08:56 -0800699 r.Lock()
700 defer r.Unlock()
701
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700702 if r.scope_ == nil {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700703 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700704 }
705 return r.scope_
706}
707
708func (r *staticRule) isArg(argName string) bool {
709 return r.argNames[argName]
710}
711
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700712func (r *staticRule) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700713 return r.pctx.pkgPath + "." + r.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700714}
715
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700716type ruleFunc struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800717 pctx *packageContext
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700718 name_ string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700719 paramsFunc func(interface{}) (RuleParams, error)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700720 argNames map[string]bool
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700721 scope_ *basicScope
Colin Cross691a60d2015-01-07 18:08:56 -0800722 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700723}
724
Jamie Gennisd4e10182014-06-12 20:06:50 -0700725// RuleFunc returns a Rule whose value is determined by a function that takes a
726// config object as input and returns either the rule parameters or an error. It
727// may only be called during a Go package's initialization - either from the
728// init() function or as part of a package-scoped variable's initialization.
729//
730// This function is usually used to initialize a package-scoped Go variable that
731// represents a Ninja rule that will be output. The name argument should
732// exactly match the Go variable name, and the string fields of the RuleParams
733// returned by f may reference other Ninja variables that are visible within the
734// calling Go package.
735//
736// The argNames arguments list Ninja variables that may be overridden by Ninja
737// build statements that invoke the rule. These arguments may be referenced in
738// any of the string fields of the RuleParams returned by f. Arguments can
739// shadow package-scoped variables defined within the caller's Go package, but
740// they may not shadow those defined in another package. Shadowing a package-
741// scoped variable results in the package-scoped variable's value being used for
742// build statements that do not override the argument. For argument names that
743// do not shadow package-scoped variables the default value is an empty string.
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800744func (p *packageContext) RuleFunc(name string, f func(interface{}) (RuleParams,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700745 error), argNames ...string) Rule {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700746
Jamie Gennis2fb20952014-10-03 02:49:58 -0700747 checkCalledFromInit()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700748
749 err := validateNinjaName(name)
750 if err != nil {
751 panic(err)
752 }
753
754 err = validateArgNames(argNames)
755 if err != nil {
756 panic(fmt.Errorf("invalid argument name: %s", err))
757 }
758
759 argNamesSet := make(map[string]bool)
760 for _, argName := range argNames {
761 argNamesSet[argName] = true
762 }
763
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700764 ruleScope := (*basicScope)(nil) // This will get created lazily
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700765
Colin Cross691a60d2015-01-07 18:08:56 -0800766 rule := &ruleFunc{
767 pctx: p,
768 name_: name,
769 paramsFunc: f,
770 argNames: argNamesSet,
771 scope_: ruleScope,
772 }
Jamie Gennis2fb20952014-10-03 02:49:58 -0700773 err = p.scope.AddRule(rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700774 if err != nil {
775 panic(err)
776 }
777
Jamie Gennis2fb20952014-10-03 02:49:58 -0700778 return rule
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700779}
780
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800781func (r *ruleFunc) packageContext() *packageContext {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700782 return r.pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700783}
784
785func (r *ruleFunc) name() string {
786 return r.name_
787}
788
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800789func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700790 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700791}
792
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700793func (r *ruleFunc) def(config interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700794 params, err := r.paramsFunc(config)
795 if err != nil {
796 return nil, err
797 }
798 def, err := parseRuleParams(r.scope(), &params)
799 if err != nil {
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700800 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700801 }
802 return def, nil
803}
804
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700805func (r *ruleFunc) scope() *basicScope {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700806 // We lazily create the scope so that all the global variables get declared
807 // before the args are created. Otherwise we could incorrectly shadow a
808 // global variable with an arg variable.
Colin Cross691a60d2015-01-07 18:08:56 -0800809 r.Lock()
810 defer r.Unlock()
811
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700812 if r.scope_ == nil {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700813 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700814 }
815 return r.scope_
816}
817
818func (r *ruleFunc) isArg(argName string) bool {
819 return r.argNames[argName]
820}
821
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700822func (r *ruleFunc) String() string {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700823 return r.pctx.pkgPath + "." + r.name_
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700824}
825
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700826type builtinRule struct {
Colin Cross691a60d2015-01-07 18:08:56 -0800827 name_ string
828 scope_ *basicScope
829 sync.Mutex // protects scope_ during lazy creation
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700830}
831
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800832func (r *builtinRule) packageContext() *packageContext {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700833 return nil
834}
835
836func (r *builtinRule) name() string {
837 return r.name_
838}
839
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800840func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700841 return r.name_
842}
843
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700844func (r *builtinRule) def(config interface{}) (*ruleDef, error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700845 return nil, errRuleIsBuiltin
846}
847
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700848func (r *builtinRule) scope() *basicScope {
Colin Cross691a60d2015-01-07 18:08:56 -0800849 r.Lock()
850 defer r.Unlock()
851
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700852 if r.scope_ == nil {
853 r.scope_ = makeRuleScope(nil, nil)
854 }
855 return r.scope_
856}
857
858func (r *builtinRule) isArg(argName string) bool {
859 return false
860}
861
Jamie Gennis48aed8c2014-06-13 18:25:54 -0700862func (r *builtinRule) String() string {
863 return "<builtin>:" + r.name_
864}