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	"github.com/google/blueprint"
19	"github.com/google/blueprint/proptools"
20)
21
22type defaultsDependencyTag struct {
23	blueprint.BaseDependencyTag
24}
25
26var DefaultsDepTag defaultsDependencyTag
27
28type defaultsProperties struct {
29	Defaults []string
30}
31
32type DefaultableModule struct {
33	defaultsProperties    defaultsProperties
34	defaultableProperties []interface{}
35}
36
37func (d *DefaultableModule) defaults() *defaultsProperties {
38	return &d.defaultsProperties
39}
40
41func (d *DefaultableModule) setProperties(props []interface{}) {
42	d.defaultableProperties = props
43}
44
45type Defaultable interface {
46	defaults() *defaultsProperties
47	setProperties([]interface{})
48	applyDefaults(TopDownMutatorContext, []Defaults)
49}
50
51var _ Defaultable = (*DefaultableModule)(nil)
52
53func InitDefaultableModule(module Module, d Defaultable,
54	props ...interface{}) (blueprint.Module, []interface{}) {
55
56	d.setProperties(props)
57
58	props = append(props, d.defaults())
59
60	return module, props
61}
62
63type DefaultsModule struct {
64	DefaultableModule
65	defaultProperties []interface{}
66}
67
68type Defaults interface {
69	Defaultable
70	isDefaults() bool
71	properties() []interface{}
72}
73
74func (d *DefaultsModule) isDefaults() bool {
75	return true
76}
77
78func (d *DefaultsModule) properties() []interface{} {
79	return d.defaultableProperties
80}
81
82func InitDefaultsModule(module Module, d Defaults, props ...interface{}) (blueprint.Module, []interface{}) {
83	props = append(props,
84		&hostAndDeviceProperties{},
85		&commonProperties{},
86		&variableProperties{})
87
88	_, props = InitArchModule(module, props...)
89
90	_, props = InitDefaultableModule(module, d, props...)
91
92	props = append(props, &module.base().nameProperties)
93
94	module.base().module = module
95
96	return module, props
97}
98
99var _ Defaults = (*DefaultsModule)(nil)
100
101func (defaultable *DefaultableModule) applyDefaults(ctx TopDownMutatorContext,
102	defaultsList []Defaults) {
103
104	for _, defaults := range defaultsList {
105		for _, prop := range defaultable.defaultableProperties {
106			for _, def := range defaults.properties() {
107				if proptools.TypeEqual(prop, def) {
108					err := proptools.PrependProperties(prop, def, nil)
109					if err != nil {
110						if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
111							ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
112						} else {
113							panic(err)
114						}
115					}
116				}
117			}
118		}
119	}
120}
121
122func defaultsDepsMutator(ctx BottomUpMutatorContext) {
123	if defaultable, ok := ctx.Module().(Defaultable); ok {
124		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
125	}
126}
127
128func defaultsMutator(ctx TopDownMutatorContext) {
129	if defaultable, ok := ctx.Module().(Defaultable); ok && len(defaultable.defaults().Defaults) > 0 {
130		var defaultsList []Defaults
131		ctx.WalkDeps(func(module, parent blueprint.Module) bool {
132			if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
133				if defaults, ok := module.(Defaults); ok {
134					defaultsList = append(defaultsList, defaults)
135					return len(defaults.defaults().Defaults) > 0
136				} else {
137					ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
138						ctx.OtherModuleName(module))
139				}
140			}
141			return false
142		})
143		defaultable.applyDefaults(ctx, defaultsList)
144	}
145}
146