1// 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
15package blueprint
16
17import (
18	"fmt"
19)
20
21type Singleton interface {
22	GenerateBuildActions(SingletonContext)
23}
24
25type SingletonContext interface {
26	Config() interface{}
27
28	ModuleName(module Module) string
29	ModuleDir(module Module) string
30	ModuleSubDir(module Module) string
31	BlueprintFile(module Module) string
32
33	ModuleErrorf(module Module, format string, args ...interface{})
34	Errorf(format string, args ...interface{})
35	Failed() bool
36
37	Variable(pctx PackageContext, name, value string)
38	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
39	Build(pctx PackageContext, params BuildParams)
40	RequireNinjaVersion(major, minor, micro int)
41
42	// SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
43	// that controls where Ninja stores its build log files.  This value can be
44	// set at most one time for a single build, later calls are ignored.
45	SetNinjaBuildDir(pctx PackageContext, value string)
46
47	VisitAllModules(visit func(Module))
48	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
49	VisitDepsDepthFirst(module Module, visit func(Module))
50	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
51		visit func(Module))
52
53	VisitAllModuleVariants(module Module, visit func(Module))
54
55	PrimaryModule(module Module) Module
56	FinalModule(module Module) Module
57
58	AddNinjaFileDeps(deps ...string)
59}
60
61var _ SingletonContext = (*singletonContext)(nil)
62
63type singletonContext struct {
64	context *Context
65	config  interface{}
66	scope   *localScope
67
68	ninjaFileDeps []string
69	errs          []error
70
71	actionDefs localBuildActions
72}
73
74func (s *singletonContext) Config() interface{} {
75	return s.config
76}
77
78func (s *singletonContext) ModuleName(logicModule Module) string {
79	return s.context.ModuleName(logicModule)
80}
81
82func (s *singletonContext) ModuleDir(logicModule Module) string {
83	return s.context.ModuleDir(logicModule)
84}
85
86func (s *singletonContext) ModuleSubDir(logicModule Module) string {
87	return s.context.ModuleSubDir(logicModule)
88}
89
90func (s *singletonContext) BlueprintFile(logicModule Module) string {
91	return s.context.BlueprintFile(logicModule)
92}
93
94func (s *singletonContext) error(err error) {
95	if err != nil {
96		s.errs = append(s.errs, err)
97	}
98}
99
100func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
101	args ...interface{}) {
102
103	s.error(s.context.ModuleErrorf(logicModule, format, args...))
104}
105
106func (s *singletonContext) Errorf(format string, args ...interface{}) {
107	// TODO: Make this not result in the error being printed as "internal error"
108	s.error(fmt.Errorf(format, args...))
109}
110
111func (s *singletonContext) Failed() bool {
112	return len(s.errs) > 0
113}
114
115func (s *singletonContext) Variable(pctx PackageContext, name, value string) {
116	s.scope.ReparentTo(pctx)
117
118	v, err := s.scope.AddLocalVariable(name, value)
119	if err != nil {
120		panic(err)
121	}
122
123	s.actionDefs.variables = append(s.actionDefs.variables, v)
124}
125
126func (s *singletonContext) Rule(pctx PackageContext, name string,
127	params RuleParams, argNames ...string) Rule {
128
129	s.scope.ReparentTo(pctx)
130
131	r, err := s.scope.AddLocalRule(name, &params, argNames...)
132	if err != nil {
133		panic(err)
134	}
135
136	s.actionDefs.rules = append(s.actionDefs.rules, r)
137
138	return r
139}
140
141func (s *singletonContext) Build(pctx PackageContext, params BuildParams) {
142	s.scope.ReparentTo(pctx)
143
144	def, err := parseBuildParams(s.scope, &params)
145	if err != nil {
146		panic(err)
147	}
148
149	s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def)
150}
151
152func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) {
153	s.context.requireNinjaVersion(major, minor, micro)
154}
155
156func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) {
157	s.scope.ReparentTo(pctx)
158
159	ninjaValue, err := parseNinjaString(s.scope, value)
160	if err != nil {
161		panic(err)
162	}
163
164	s.context.setNinjaBuildDir(ninjaValue)
165}
166
167func (s *singletonContext) VisitAllModules(visit func(Module)) {
168	s.context.VisitAllModules(visit)
169}
170
171func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool,
172	visit func(Module)) {
173
174	s.context.VisitAllModulesIf(pred, visit)
175}
176
177func (s *singletonContext) VisitDepsDepthFirst(module Module,
178	visit func(Module)) {
179
180	s.context.VisitDepsDepthFirst(module, visit)
181}
182
183func (s *singletonContext) VisitDepsDepthFirstIf(module Module,
184	pred func(Module) bool, visit func(Module)) {
185
186	s.context.VisitDepsDepthFirstIf(module, pred, visit)
187}
188
189func (s *singletonContext) PrimaryModule(module Module) Module {
190	return s.context.PrimaryModule(module)
191}
192
193func (s *singletonContext) FinalModule(module Module) Module {
194	return s.context.FinalModule(module)
195}
196
197func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) {
198	s.context.VisitAllModuleVariants(module, visit)
199}
200
201func (s *singletonContext) AddNinjaFileDeps(deps ...string) {
202	s.ninjaFileDeps = append(s.ninjaFileDeps, deps...)
203}
204