From aeffbf776abff483634d1fc1bba0abce15b6d72e Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Wed, 25 Nov 2015 15:29:32 -0800 Subject: [PATCH] Allow wrapping of PackageContext Turn PackageContext into an interface so that build systems can wrap it to add more custom helpers. This does introduce an API change, though it should be fairly simple. NewPackageContext used to provide an opaque *PackageContext struct, now it provides a PackageContext interface. Change-Id: I383c64a303d857ef5e0dec86ad77f791ba4c9639 --- context.go | 18 ++++----- module_ctx.go | 12 +++--- ninja_defs.go | 6 +-- ninja_strings.go | 4 +- package_ctx.go | 96 +++++++++++++++++++++++++++++------------------- scope.go | 24 ++++++------ singleton_ctx.go | 16 ++++---- 7 files changed, 99 insertions(+), 77 deletions(-) diff --git a/context.go b/context.go index 811df15..c8bc1f9 100644 --- a/context.go +++ b/context.go @@ -82,7 +82,7 @@ type Context struct { ignoreUnknownModuleTypes bool // set during PrepareBuildActions - pkgNames map[*PackageContext]string + pkgNames map[*packageContext]string globalVariables map[Variable]*ninjaString globalPools map[Pool]*poolDef globalRules map[Rule]*ruleDef @@ -1919,13 +1919,13 @@ func (c *Context) setNinjaBuildDir(value *ninjaString) { } func (c *Context) makeUniquePackageNames( - liveGlobals *liveTracker) map[*PackageContext]string { + liveGlobals *liveTracker) map[*packageContext]string { - pkgs := make(map[string]*PackageContext) - pkgNames := make(map[*PackageContext]string) - longPkgNames := make(map[*PackageContext]bool) + pkgs := make(map[string]*packageContext) + pkgNames := make(map[*packageContext]string) + longPkgNames := make(map[*packageContext]bool) - processPackage := func(pctx *PackageContext) { + processPackage := func(pctx *packageContext) { if pctx == nil { // This is a built-in rule and has no package. return @@ -1972,7 +1972,7 @@ func (c *Context) makeUniquePackageNames( } func (c *Context) checkForVariableReferenceCycles( - variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) { + variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) { visited := make(map[Variable]bool) // variables that were already checked checking := make(map[Variable]bool) // variables actively being checked @@ -2313,11 +2313,11 @@ func (c *Context) writeBuildDir(nw *ninjaWriter) error { } type globalEntity interface { - fullName(pkgNames map[*PackageContext]string) string + fullName(pkgNames map[*packageContext]string) string } type globalEntitySorter struct { - pkgNames map[*PackageContext]string + pkgNames map[*packageContext]string entities []globalEntity } diff --git a/module_ctx.go b/module_ctx.go index ce3cb8a..bb33d37 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -137,9 +137,9 @@ type ModuleContext interface { ModuleSubDir() string - Variable(pctx *PackageContext, name, value string) - Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule - Build(pctx *PackageContext, params BuildParams) + Variable(pctx PackageContext, name, value string) + Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule + Build(pctx PackageContext, params BuildParams) AddNinjaFileDeps(deps ...string) @@ -267,7 +267,7 @@ func (m *moduleContext) ModuleSubDir() string { return m.module.variantName } -func (m *moduleContext) Variable(pctx *PackageContext, name, value string) { +func (m *moduleContext) Variable(pctx PackageContext, name, value string) { m.scope.ReparentTo(pctx) v, err := m.scope.AddLocalVariable(name, value) @@ -278,7 +278,7 @@ func (m *moduleContext) Variable(pctx *PackageContext, name, value string) { m.actionDefs.variables = append(m.actionDefs.variables, v) } -func (m *moduleContext) Rule(pctx *PackageContext, name string, +func (m *moduleContext) Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule { m.scope.ReparentTo(pctx) @@ -293,7 +293,7 @@ func (m *moduleContext) Rule(pctx *PackageContext, name string, return r } -func (m *moduleContext) Build(pctx *PackageContext, params BuildParams) { +func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.scope.ReparentTo(pctx) def, err := parseBuildParams(m.scope, ¶ms) diff --git a/ninja_defs.go b/ninja_defs.go index 05b8f2f..e7a2929 100644 --- a/ninja_defs.go +++ b/ninja_defs.go @@ -207,7 +207,7 @@ func parseRuleParams(scope scope, params *RuleParams) (*ruleDef, } func (r *ruleDef) WriteTo(nw *ninjaWriter, name string, - pkgNames map[*PackageContext]string) error { + pkgNames map[*packageContext]string) error { if r.Comment != "" { err := nw.Comment(r.Comment) @@ -327,7 +327,7 @@ func parseBuildParams(scope scope, params *BuildParams) (*buildDef, return b, nil } -func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*PackageContext]string) error { +func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) error { var ( comment = b.Comment rule = b.Rule.fullName(pkgNames) @@ -372,7 +372,7 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*PackageContext]string) return nw.BlankLine() } -func valueList(list []*ninjaString, pkgNames map[*PackageContext]string, +func valueList(list []*ninjaString, pkgNames map[*packageContext]string, escaper *strings.Replacer) []string { result := make([]string, len(list)) diff --git a/ninja_strings.go b/ninja_strings.go index 3492da2..5bdddea 100644 --- a/ninja_strings.go +++ b/ninja_strings.go @@ -258,11 +258,11 @@ func parseNinjaStrings(scope scope, strs []string) ([]*ninjaString, return result, nil } -func (n *ninjaString) Value(pkgNames map[*PackageContext]string) string { +func (n *ninjaString) Value(pkgNames map[*packageContext]string) string { return n.ValueWithEscaper(pkgNames, defaultEscaper) } -func (n *ninjaString) ValueWithEscaper(pkgNames map[*PackageContext]string, +func (n *ninjaString) ValueWithEscaper(pkgNames map[*packageContext]string, escaper *strings.Replacer) string { str := escaper.Replace(n.strings[0]) diff --git a/package_ctx.go b/package_ctx.go index 0d3f0ae..5b93c20 100644 --- a/package_ctx.go +++ b/package_ctx.go @@ -53,20 +53,42 @@ import ( // Outputs: []string{"$myPrivateVar"}, // }) // } -type PackageContext struct { +type PackageContext interface { + Import(pkgPath string) + ImportAs(as, pkgPath string) + + StaticVariable(name, value string) Variable + VariableFunc(name string, f func(config interface{}) (string, error)) Variable + VariableConfigMethod(name string, method interface{}) Variable + + StaticPool(name string, params PoolParams) Pool + PoolFunc(name string, f func(interface{}) (PoolParams, error)) Pool + + StaticRule(name string, params RuleParams, argNames ...string) Rule + RuleFunc(name string, f func(interface{}) (RuleParams, error), argNames ...string) Rule + + getScope() *basicScope +} + +type packageContext struct { fullName string shortName string pkgPath string scope *basicScope } +var _ PackageContext = &packageContext{} -var packageContexts = map[string]*PackageContext{} +func (p *packageContext) getScope() *basicScope { + return p.scope +} + +var packageContexts = map[string]*packageContext{} // NewPackageContext creates a PackageContext object for a given package. The // pkgPath argument should always be set to the full path used to import the // package. This function may only be called from a Go package's init() // function or as part of a package-scoped variable initialization. -func NewPackageContext(pkgPath string) *PackageContext { +func NewPackageContext(pkgPath string) PackageContext { checkCalledFromInit() if _, present := packageContexts[pkgPath]; present { @@ -82,7 +104,7 @@ func NewPackageContext(pkgPath string) *PackageContext { i := strings.LastIndex(pkgPath, "/") shortName := pkgPath[i+1:] - p := &PackageContext{ + p := &packageContext{ fullName: pkgName, shortName: shortName, pkgPath: pkgPath, @@ -198,7 +220,7 @@ func pkgPathToName(pkgPath string) string { // from Go's import declaration, which derives the local name from the package // clause in the imported package. By convention these names are made to match, // but this is not required. -func (p *PackageContext) Import(pkgPath string) { +func (p *packageContext) Import(pkgPath string) { checkCalledFromInit() importPkg, ok := packageContexts[pkgPath] if !ok { @@ -214,7 +236,7 @@ func (p *PackageContext) Import(pkgPath string) { // ImportAs provides the same functionality as Import, but it allows the local // name that will be used to refer to the package to be specified explicitly. // It may only be called from a Go package's init() function. -func (p *PackageContext) ImportAs(as, pkgPath string) { +func (p *packageContext) ImportAs(as, pkgPath string) { checkCalledFromInit() importPkg, ok := packageContexts[pkgPath] if !ok { @@ -233,7 +255,7 @@ func (p *PackageContext) ImportAs(as, pkgPath string) { } type staticVariable struct { - pctx *PackageContext + pctx *packageContext name_ string value_ string } @@ -247,7 +269,7 @@ type staticVariable struct { // represents a Ninja variable that will be output. The name argument should // exactly match the Go variable name, and the value string may reference other // Ninja variables that are visible within the calling Go package. -func (p *PackageContext) StaticVariable(name, value string) Variable { +func (p *packageContext) StaticVariable(name, value string) Variable { checkCalledFromInit() err := validateNinjaName(name) if err != nil { @@ -263,7 +285,7 @@ func (p *PackageContext) StaticVariable(name, value string) Variable { return v } -func (v *staticVariable) packageContext() *PackageContext { +func (v *staticVariable) packageContext() *packageContext { return v.pctx } @@ -271,7 +293,7 @@ func (v *staticVariable) name() string { return v.name_ } -func (v *staticVariable) fullName(pkgNames map[*PackageContext]string) string { +func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ } @@ -289,7 +311,7 @@ func (v *staticVariable) String() string { } type variableFunc struct { - pctx *PackageContext + pctx *packageContext name_ string value_ func(interface{}) (string, error) } @@ -305,7 +327,7 @@ type variableFunc struct { // exactly match the Go variable name, and the value string returned by f may // reference other Ninja variables that are visible within the calling Go // package. -func (p *PackageContext) VariableFunc(name string, +func (p *packageContext) VariableFunc(name string, f func(config interface{}) (string, error)) Variable { checkCalledFromInit() @@ -335,7 +357,7 @@ func (p *PackageContext) VariableFunc(name string, // exactly match the Go variable name, and the value string returned by method // may reference other Ninja variables that are visible within the calling Go // package. -func (p *PackageContext) VariableConfigMethod(name string, +func (p *packageContext) VariableConfigMethod(name string, method interface{}) Variable { checkCalledFromInit() @@ -363,7 +385,7 @@ func (p *PackageContext) VariableConfigMethod(name string, return v } -func (v *variableFunc) packageContext() *PackageContext { +func (v *variableFunc) packageContext() *packageContext { return v.pctx } @@ -371,7 +393,7 @@ func (v *variableFunc) name() string { return v.name_ } -func (v *variableFunc) fullName(pkgNames map[*PackageContext]string) string { +func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ } @@ -423,7 +445,7 @@ type argVariable struct { name_ string } -func (v *argVariable) packageContext() *PackageContext { +func (v *argVariable) packageContext() *packageContext { panic("this should not be called") } @@ -431,7 +453,7 @@ func (v *argVariable) name() string { return v.name_ } -func (v *argVariable) fullName(pkgNames map[*PackageContext]string) string { +func (v *argVariable) fullName(pkgNames map[*packageContext]string) string { return v.name_ } @@ -444,7 +466,7 @@ func (v *argVariable) String() string { } type staticPool struct { - pctx *PackageContext + pctx *packageContext name_ string params PoolParams } @@ -458,7 +480,7 @@ type staticPool struct { // represents a Ninja pool that will be output. The name argument should // exactly match the Go variable name, and the params fields may reference other // Ninja variables that are visible within the calling Go package. -func (p *PackageContext) StaticPool(name string, params PoolParams) Pool { +func (p *packageContext) StaticPool(name string, params PoolParams) Pool { checkCalledFromInit() err := validateNinjaName(name) @@ -475,7 +497,7 @@ func (p *PackageContext) StaticPool(name string, params PoolParams) Pool { return pool } -func (p *staticPool) packageContext() *PackageContext { +func (p *staticPool) packageContext() *packageContext { return p.pctx } @@ -483,7 +505,7 @@ func (p *staticPool) name() string { return p.name_ } -func (p *staticPool) fullName(pkgNames map[*PackageContext]string) string { +func (p *staticPool) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ } @@ -500,7 +522,7 @@ func (p *staticPool) String() string { } type poolFunc struct { - pctx *PackageContext + pctx *packageContext name_ string paramsFunc func(interface{}) (PoolParams, error) } @@ -515,7 +537,7 @@ type poolFunc struct { // exactly match the Go variable name, and the string fields of the PoolParams // returned by f may reference other Ninja variables that are visible within the // calling Go package. -func (p *PackageContext) PoolFunc(name string, f func(interface{}) (PoolParams, +func (p *packageContext) PoolFunc(name string, f func(interface{}) (PoolParams, error)) Pool { checkCalledFromInit() @@ -534,7 +556,7 @@ func (p *PackageContext) PoolFunc(name string, f func(interface{}) (PoolParams, return pool } -func (p *poolFunc) packageContext() *PackageContext { +func (p *poolFunc) packageContext() *packageContext { return p.pctx } @@ -542,7 +564,7 @@ func (p *poolFunc) name() string { return p.name_ } -func (p *poolFunc) fullName(pkgNames map[*PackageContext]string) string { +func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ } @@ -566,7 +588,7 @@ type builtinPool struct { name_ string } -func (p *builtinPool) packageContext() *PackageContext { +func (p *builtinPool) packageContext() *packageContext { return nil } @@ -574,7 +596,7 @@ func (p *builtinPool) name() string { return p.name_ } -func (p *builtinPool) fullName(pkgNames map[*PackageContext]string) string { +func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string { return p.name_ } @@ -587,7 +609,7 @@ func (p *builtinPool) String() string { } type staticRule struct { - pctx *PackageContext + pctx *packageContext name_ string params RuleParams argNames map[string]bool @@ -613,7 +635,7 @@ type staticRule struct { // results in the package-scoped variable's value being used for build // statements that do not override the argument. For argument names that do not // shadow package-scoped variables the default value is an empty string. -func (p *PackageContext) StaticRule(name string, params RuleParams, +func (p *packageContext) StaticRule(name string, params RuleParams, argNames ...string) Rule { checkCalledFromInit() @@ -650,7 +672,7 @@ func (p *PackageContext) StaticRule(name string, params RuleParams, return r } -func (r *staticRule) packageContext() *PackageContext { +func (r *staticRule) packageContext() *packageContext { return r.pctx } @@ -658,7 +680,7 @@ func (r *staticRule) name() string { return r.name_ } -func (r *staticRule) fullName(pkgNames map[*PackageContext]string) string { +func (r *staticRule) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ } @@ -692,7 +714,7 @@ func (r *staticRule) String() string { } type ruleFunc struct { - pctx *PackageContext + pctx *packageContext name_ string paramsFunc func(interface{}) (RuleParams, error) argNames map[string]bool @@ -719,7 +741,7 @@ type ruleFunc struct { // scoped variable results in the package-scoped variable's value being used for // build statements that do not override the argument. For argument names that // do not shadow package-scoped variables the default value is an empty string. -func (p *PackageContext) RuleFunc(name string, f func(interface{}) (RuleParams, +func (p *packageContext) RuleFunc(name string, f func(interface{}) (RuleParams, error), argNames ...string) Rule { checkCalledFromInit() @@ -756,7 +778,7 @@ func (p *PackageContext) RuleFunc(name string, f func(interface{}) (RuleParams, return rule } -func (r *ruleFunc) packageContext() *PackageContext { +func (r *ruleFunc) packageContext() *packageContext { return r.pctx } @@ -764,7 +786,7 @@ func (r *ruleFunc) name() string { return r.name_ } -func (r *ruleFunc) fullName(pkgNames map[*PackageContext]string) string { +func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string { return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ } @@ -807,7 +829,7 @@ type builtinRule struct { sync.Mutex // protects scope_ during lazy creation } -func (r *builtinRule) packageContext() *PackageContext { +func (r *builtinRule) packageContext() *packageContext { return nil } @@ -815,7 +837,7 @@ func (r *builtinRule) name() string { return r.name_ } -func (r *builtinRule) fullName(pkgNames map[*PackageContext]string) string { +func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string { return r.name_ } diff --git a/scope.go b/scope.go index ef4eb2c..84db0cf 100644 --- a/scope.go +++ b/scope.go @@ -25,9 +25,9 @@ import ( // to the output .ninja file. A variable may contain references to other global // Ninja variables, but circular variable references are not allowed. type Variable interface { - packageContext() *PackageContext + packageContext() *packageContext name() string // "foo" - fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo" + fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" value(config interface{}) (*ninjaString, error) String() string } @@ -35,9 +35,9 @@ type Variable interface { // A Pool represents a Ninja pool that will be written to the output .ninja // file. type Pool interface { - packageContext() *PackageContext + packageContext() *packageContext name() string // "foo" - fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo" + fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" def(config interface{}) (*poolDef, error) String() string } @@ -45,9 +45,9 @@ type Pool interface { // A Rule represents a Ninja build rule that will be written to the output // .ninja file. type Rule interface { - packageContext() *PackageContext + packageContext() *packageContext name() string // "foo" - fullName(pkgNames map[*PackageContext]string) string // "pkg.foo" or "path.to.pkg.foo" + fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" def(config interface{}) (*ruleDef, error) scope() *basicScope isArg(argName string) bool @@ -260,8 +260,8 @@ func newLocalScope(parent *basicScope, namePrefix string) *localScope { // package context. This allows a ModuleContext and SingletonContext to call // a function defined in a different Go package and have that function retain // access to all of the package-scoped variables of its own package. -func (s *localScope) ReparentTo(pctx *PackageContext) { - s.scope.parent = pctx.scope +func (s *localScope) ReparentTo(pctx PackageContext) { + s.scope.parent = pctx.getScope() } func (s *localScope) LookupVariable(name string) (Variable, error) { @@ -354,7 +354,7 @@ type localVariable struct { value_ *ninjaString } -func (l *localVariable) packageContext() *PackageContext { +func (l *localVariable) packageContext() *packageContext { return nil } @@ -362,7 +362,7 @@ func (l *localVariable) name() string { return l.name_ } -func (l *localVariable) fullName(pkgNames map[*PackageContext]string) string { +func (l *localVariable) fullName(pkgNames map[*packageContext]string) string { return l.namePrefix + l.name_ } @@ -382,7 +382,7 @@ type localRule struct { scope_ *basicScope } -func (l *localRule) packageContext() *PackageContext { +func (l *localRule) packageContext() *packageContext { return nil } @@ -390,7 +390,7 @@ func (l *localRule) name() string { return l.name_ } -func (l *localRule) fullName(pkgNames map[*PackageContext]string) string { +func (l *localRule) fullName(pkgNames map[*packageContext]string) string { return l.namePrefix + l.name_ } diff --git a/singleton_ctx.go b/singleton_ctx.go index ee96fc6..2ba0199 100644 --- a/singleton_ctx.go +++ b/singleton_ctx.go @@ -32,15 +32,15 @@ type SingletonContext interface { ModuleErrorf(module Module, format string, args ...interface{}) Errorf(format string, args ...interface{}) - Variable(pctx *PackageContext, name, value string) - Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule - Build(pctx *PackageContext, params BuildParams) + Variable(pctx PackageContext, name, value string) + Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule + Build(pctx PackageContext, params BuildParams) RequireNinjaVersion(major, minor, micro int) // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable // that controls where Ninja stores its build log files. This value can be // set at most one time for a single build, later calls are ignored. - SetNinjaBuildDir(pctx *PackageContext, value string) + SetNinjaBuildDir(pctx PackageContext, value string) VisitAllModules(visit func(Module)) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) @@ -96,7 +96,7 @@ func (s *singletonContext) Errorf(format string, args ...interface{}) { s.errs = append(s.errs, fmt.Errorf(format, args...)) } -func (s *singletonContext) Variable(pctx *PackageContext, name, value string) { +func (s *singletonContext) Variable(pctx PackageContext, name, value string) { s.scope.ReparentTo(pctx) v, err := s.scope.AddLocalVariable(name, value) @@ -107,7 +107,7 @@ func (s *singletonContext) Variable(pctx *PackageContext, name, value string) { s.actionDefs.variables = append(s.actionDefs.variables, v) } -func (s *singletonContext) Rule(pctx *PackageContext, name string, +func (s *singletonContext) Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule { s.scope.ReparentTo(pctx) @@ -122,7 +122,7 @@ func (s *singletonContext) Rule(pctx *PackageContext, name string, return r } -func (s *singletonContext) Build(pctx *PackageContext, params BuildParams) { +func (s *singletonContext) Build(pctx PackageContext, params BuildParams) { s.scope.ReparentTo(pctx) def, err := parseBuildParams(s.scope, ¶ms) @@ -137,7 +137,7 @@ func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) { s.context.requireNinjaVersion(major, minor, micro) } -func (s *singletonContext) SetNinjaBuildDir(pctx *PackageContext, value string) { +func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) { s.scope.ReparentTo(pctx) ninjaValue, err := parseNinjaString(s.scope, value)