Merge pull request #84 from danw/pkgctx

Allow wrapping of PackageContext
diff --git a/context.go b/context.go
index 811df15..c8bc1f9 100644
--- a/context.go
+++ b/context.go
@@ -82,7 +82,7 @@
 	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) 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) 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 @@
 }
 
 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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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, &params)
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 (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 @@
 	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 @@
 	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 @@
 	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 @@
 //             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 @@
 	i := strings.LastIndex(pkgPath, "/")
 	shortName := pkgPath[i+1:]
 
-	p := &PackageContext{
+	p := &packageContext{
 		fullName:  pkgName,
 		shortName: shortName,
 		pkgPath:   pkgPath,
@@ -198,7 +220,7 @@
 // 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 @@
 // 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 @@
 }
 
 type staticVariable struct {
-	pctx   *PackageContext
+	pctx   *packageContext
 	name_  string
 	value_ string
 }
@@ -247,7 +269,7 @@
 // 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 @@
 	return v
 }
 
-func (v *staticVariable) packageContext() *PackageContext {
+func (v *staticVariable) packageContext() *packageContext {
 	return v.pctx
 }
 
@@ -271,7 +293,7 @@
 	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 @@
 }
 
 type variableFunc struct {
-	pctx   *PackageContext
+	pctx   *packageContext
 	name_  string
 	value_ func(interface{}) (string, error)
 }
@@ -305,7 +327,7 @@
 // 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 @@
 // 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 @@
 	return v
 }
 
-func (v *variableFunc) packageContext() *PackageContext {
+func (v *variableFunc) packageContext() *packageContext {
 	return v.pctx
 }
 
@@ -371,7 +393,7 @@
 	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 @@
 	name_ string
 }
 
-func (v *argVariable) packageContext() *PackageContext {
+func (v *argVariable) packageContext() *packageContext {
 	panic("this should not be called")
 }
 
@@ -431,7 +453,7 @@
 	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 @@
 }
 
 type staticPool struct {
-	pctx   *PackageContext
+	pctx   *packageContext
 	name_  string
 	params PoolParams
 }
@@ -458,7 +480,7 @@
 // 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 @@
 	return pool
 }
 
-func (p *staticPool) packageContext() *PackageContext {
+func (p *staticPool) packageContext() *packageContext {
 	return p.pctx
 }
 
@@ -483,7 +505,7 @@
 	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 @@
 }
 
 type poolFunc struct {
-	pctx       *PackageContext
+	pctx       *packageContext
 	name_      string
 	paramsFunc func(interface{}) (PoolParams, error)
 }
@@ -515,7 +537,7 @@
 // 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 @@
 	return pool
 }
 
-func (p *poolFunc) packageContext() *PackageContext {
+func (p *poolFunc) packageContext() *packageContext {
 	return p.pctx
 }
 
@@ -542,7 +564,7 @@
 	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 @@
 	name_ string
 }
 
-func (p *builtinPool) packageContext() *PackageContext {
+func (p *builtinPool) packageContext() *packageContext {
 	return nil
 }
 
@@ -574,7 +596,7 @@
 	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 @@
 }
 
 type staticRule struct {
-	pctx       *PackageContext
+	pctx       *packageContext
 	name_      string
 	params     RuleParams
 	argNames   map[string]bool
@@ -613,7 +635,7 @@
 // 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 @@
 	return r
 }
 
-func (r *staticRule) packageContext() *PackageContext {
+func (r *staticRule) packageContext() *packageContext {
 	return r.pctx
 }
 
@@ -658,7 +680,7 @@
 	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 @@
 }
 
 type ruleFunc struct {
-	pctx       *PackageContext
+	pctx       *packageContext
 	name_      string
 	paramsFunc func(interface{}) (RuleParams, error)
 	argNames   map[string]bool
@@ -719,7 +741,7 @@
 // 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 @@
 	return rule
 }
 
-func (r *ruleFunc) packageContext() *PackageContext {
+func (r *ruleFunc) packageContext() *packageContext {
 	return r.pctx
 }
 
@@ -764,7 +786,7 @@
 	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 @@
 	sync.Mutex // protects scope_ during lazy creation
 }
 
-func (r *builtinRule) packageContext() *PackageContext {
+func (r *builtinRule) packageContext() *packageContext {
 	return nil
 }
 
@@ -815,7 +837,7 @@
 	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 @@
 // 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 @@
 // 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 @@
 // 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 @@
 // 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 @@
 	value_     *ninjaString
 }
 
-func (l *localVariable) packageContext() *PackageContext {
+func (l *localVariable) packageContext() *packageContext {
 	return nil
 }
 
@@ -362,7 +362,7 @@
 	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 @@
 	scope_     *basicScope
 }
 
-func (l *localRule) packageContext() *PackageContext {
+func (l *localRule) packageContext() *packageContext {
 	return nil
 }
 
@@ -390,7 +390,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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, &params)
@@ -137,7 +137,7 @@
 	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)