1// Copyright 2015 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 android
16
17import (
18	"fmt"
19
20	"github.com/google/blueprint"
21	"github.com/google/blueprint/pathtools"
22)
23
24// AndroidPackageContext is a wrapper for blueprint.PackageContext that adds
25// some android-specific helper functions.
26type AndroidPackageContext struct {
27	blueprint.PackageContext
28}
29
30func NewPackageContext(pkgPath string) AndroidPackageContext {
31	return AndroidPackageContext{blueprint.NewPackageContext(pkgPath)}
32}
33
34// configErrorWrapper can be used with Path functions when a Context is not
35// available. A Config can be provided, and errors are stored as a list for
36// later retrieval.
37//
38// The most common use here will be with VariableFunc, where only a config is
39// provided, and an error should be returned.
40type configErrorWrapper struct {
41	pctx   AndroidPackageContext
42	config Config
43	errors []error
44}
45
46var _ PathContext = &configErrorWrapper{}
47var _ errorfContext = &configErrorWrapper{}
48
49func (e *configErrorWrapper) Config() interface{} {
50	return e.config
51}
52func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
53	e.errors = append(e.errors, fmt.Errorf(format, args...))
54}
55func (e *configErrorWrapper) AddNinjaFileDeps(deps ...string) {
56	e.pctx.AddNinjaFileDeps(deps...)
57}
58
59func (e *configErrorWrapper) Fs() pathtools.FileSystem {
60	return nil
61}
62
63// SourcePathVariable returns a Variable whose value is the source directory
64// appended with the supplied path. It may only be called during a Go package's
65// initialization - either from the init() function or as part of a
66// package-scoped variable's initialization.
67func (p AndroidPackageContext) SourcePathVariable(name, path string) blueprint.Variable {
68	return p.VariableFunc(name, func(config interface{}) (string, error) {
69		ctx := &configErrorWrapper{p, config.(Config), []error{}}
70		p := safePathForSource(ctx, path)
71		if len(ctx.errors) > 0 {
72			return "", ctx.errors[0]
73		}
74		return p.String(), nil
75	})
76}
77
78// HostBinVariable returns a Variable whose value is the path to a host tool
79// in the bin directory for host targets. It may only be called during a Go
80// package's initialization - either from the init() function or as part of a
81// package-scoped variable's initialization.
82func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
83	return p.VariableFunc(name, func(config interface{}) (string, error) {
84		ctx := &configErrorWrapper{p, config.(Config), []error{}}
85		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
86		if len(ctx.errors) > 0 {
87			return "", ctx.errors[0]
88		}
89		return p.String(), nil
90	})
91}
92
93// HostJavaToolVariable returns a Variable whose value is the path to a host
94// tool in the frameworks directory for host targets. It may only be called
95// during a Go package's initialization - either from the init() function or as
96// part of a package-scoped variable's initialization.
97func (p AndroidPackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
98	return p.VariableFunc(name, func(config interface{}) (string, error) {
99		ctx := &configErrorWrapper{p, config.(Config), []error{}}
100		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
101		if len(ctx.errors) > 0 {
102			return "", ctx.errors[0]
103		}
104		return p.String(), nil
105	})
106}
107
108// IntermediatesPathVariable returns a Variable whose value is the intermediate
109// directory appended with the supplied path. It may only be called during a Go
110// package's initialization - either from the init() function or as part of a
111// package-scoped variable's initialization.
112func (p AndroidPackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
113	return p.VariableFunc(name, func(config interface{}) (string, error) {
114		ctx := &configErrorWrapper{p, config.(Config), []error{}}
115		p := PathForIntermediates(ctx, path)
116		if len(ctx.errors) > 0 {
117			return "", ctx.errors[0]
118		}
119		return p.String(), nil
120	})
121}
122
123// PrefixedPathsForOptionalSourceVariable returns a Variable whose value is the
124// list of present source paths prefixed with the supplied prefix. It may only
125// be called during a Go package's initialization - either from the init()
126// function or as part of a package-scoped variable's initialization.
127func (p AndroidPackageContext) PrefixedPathsForOptionalSourceVariable(
128	name, prefix string, paths []string) blueprint.Variable {
129
130	return p.VariableFunc(name, func(config interface{}) (string, error) {
131		ctx := &configErrorWrapper{p, config.(Config), []error{}}
132		paths := PathsForOptionalSource(ctx, "", paths)
133		if len(ctx.errors) > 0 {
134			return "", ctx.errors[0]
135		}
136		return JoinWithPrefix(paths.Strings(), prefix), nil
137	})
138}
139
140type RuleParams struct {
141	blueprint.RuleParams
142	GomaSupported bool
143}
144
145// AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
146func (p AndroidPackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
147	argNames ...string) blueprint.Rule {
148	return p.AndroidRuleFunc(name, func(interface{}) (blueprint.RuleParams, error) {
149		return params, nil
150	}, argNames...)
151}
152
153// AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
154func (p AndroidPackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
155	argNames ...string) blueprint.Rule {
156	return p.StaticRule(name, params, argNames...)
157}
158
159func (p AndroidPackageContext) AndroidRuleFunc(name string,
160	f func(interface{}) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
161	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
162		params, err := f(config)
163		if config.(Config).UseGoma() && params.Pool == nil {
164			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
165			// local parallelism value
166			params.Pool = localPool
167		}
168		return params, err
169	}, argNames...)
170}
171