blob: a743a86efb1e6b4900ad6bf31b4aef79bcf23359 [file] [log] [blame]
Colin Crossfeec25b2019-01-30 17:32:39 -08001// Copyright 2018 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 "path/filepath"
20 "sort"
21 "strings"
22
23 "github.com/google/blueprint"
24 "github.com/google/blueprint/proptools"
25)
26
27type RuleBuilderInstall struct {
28 From, To string
29}
30
31type RuleBuilder struct {
32 commands []*RuleBuilderCommand
33 installs []RuleBuilderInstall
34 restat bool
35}
36
37func (r *RuleBuilder) Restat() *RuleBuilder {
38 r.restat = true
39 return r
40}
41
42func (r *RuleBuilder) Install(from, to string) {
43 r.installs = append(r.installs, RuleBuilderInstall{from, to})
44}
45
46func (r *RuleBuilder) Command() *RuleBuilderCommand {
47 command := &RuleBuilderCommand{}
48 r.commands = append(r.commands, command)
49 return command
50}
51
52func (r *RuleBuilder) Inputs() []string {
53 outputs := r.outputSet()
54
55 inputs := make(map[string]bool)
56 for _, c := range r.commands {
57 for _, input := range c.inputs {
58 if !outputs[input] {
59 inputs[input] = true
60 }
61 }
62 }
63
64 var inputList []string
65 for input := range inputs {
66 inputList = append(inputList, input)
67 }
68 sort.Strings(inputList)
69
70 return inputList
71}
72
73func (r *RuleBuilder) outputSet() map[string]bool {
74 outputs := make(map[string]bool)
75 for _, c := range r.commands {
76 for _, output := range c.outputs {
77 outputs[output] = true
78 }
79 }
80 return outputs
81}
82
83func (r *RuleBuilder) Outputs() []string {
84 outputs := r.outputSet()
85
86 var outputList []string
87 for output := range outputs {
88 outputList = append(outputList, output)
89 }
90 sort.Strings(outputList)
91 return outputList
92}
93
94func (r *RuleBuilder) Installs() []RuleBuilderInstall {
95 return append([]RuleBuilderInstall(nil), r.installs...)
96}
97
98func (r *RuleBuilder) Tools() []string {
99 var tools []string
100 for _, c := range r.commands {
101 tools = append(tools, c.tools...)
102 }
103 return tools
104}
105
106func (r *RuleBuilder) Commands() []string {
107 var commands []string
108 for _, c := range r.commands {
109 commands = append(commands, string(c.buf))
110 }
111 return commands
112}
113
Colin Cross786cd6d2019-02-01 16:41:11 -0800114type BuilderContext interface {
115 PathContext
116 Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule
117 Build(PackageContext, BuildParams)
118}
119
120func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
121 // TODO: convert RuleBuilder arguments and storage to Paths
122 mctx, _ := ctx.(ModuleContext)
Colin Crossfeec25b2019-01-30 17:32:39 -0800123 var inputs Paths
124 for _, input := range r.Inputs() {
Colin Cross786cd6d2019-02-01 16:41:11 -0800125 // Module output paths
126 if mctx != nil {
127 rel, isRel := MaybeRel(ctx, PathForModuleOut(mctx).String(), input)
128 if isRel {
129 inputs = append(inputs, PathForModuleOut(mctx, rel))
130 continue
131 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800132 }
Colin Cross786cd6d2019-02-01 16:41:11 -0800133
134 // Other output paths
135 rel, isRel := MaybeRel(ctx, PathForOutput(ctx).String(), input)
136 if isRel {
137 inputs = append(inputs, PathForOutput(ctx, rel))
138 continue
139 }
140
141 // TODO: remove this once boot image is moved to where PathForOutput can find it.
142 inputs = append(inputs, &unknownRulePath{input})
Colin Crossfeec25b2019-01-30 17:32:39 -0800143 }
144
145 var outputs WritablePaths
146 for _, output := range r.Outputs() {
Colin Cross786cd6d2019-02-01 16:41:11 -0800147 if mctx != nil {
148 rel := Rel(ctx, PathForModuleOut(mctx).String(), output)
149 outputs = append(outputs, PathForModuleOut(mctx, rel))
150 } else {
151 rel := Rel(ctx, PathForOutput(ctx).String(), output)
152 outputs = append(outputs, PathForOutput(ctx, rel))
153 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800154 }
155
156 if len(r.Commands()) > 0 {
157 ctx.Build(pctx, BuildParams{
158 Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
159 Command: strings.Join(proptools.NinjaEscape(r.Commands()), " && "),
160 CommandDeps: r.Tools(),
161 }),
162 Implicits: inputs,
163 Outputs: outputs,
164 Description: desc,
165 })
166 }
167}
168
169type RuleBuilderCommand struct {
170 buf []byte
171 inputs []string
172 outputs []string
173 tools []string
174}
175
176func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
177 if len(c.buf) > 0 {
178 c.buf = append(c.buf, ' ')
179 }
180 c.buf = append(c.buf, text...)
181 return c
182}
183
184func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
185 return c.Text(fmt.Sprintf(format, a...))
186}
187
188func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand {
189 return c.Text(flag)
190}
191
192func (c *RuleBuilderCommand) FlagWithArg(flag, arg string) *RuleBuilderCommand {
193 return c.Text(flag + arg)
194}
195
196func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string) *RuleBuilderCommand {
197 return c.Text(flag + strings.Join(list, sep))
198}
199
200func (c *RuleBuilderCommand) Tool(path string) *RuleBuilderCommand {
201 c.tools = append(c.tools, path)
202 return c.Text(path)
203}
204
205func (c *RuleBuilderCommand) Input(path string) *RuleBuilderCommand {
206 c.inputs = append(c.inputs, path)
207 return c.Text(path)
208}
209
210func (c *RuleBuilderCommand) Implicit(path string) *RuleBuilderCommand {
211 c.inputs = append(c.inputs, path)
212 return c
213}
214
215func (c *RuleBuilderCommand) Implicits(paths []string) *RuleBuilderCommand {
216 c.inputs = append(c.inputs, paths...)
217 return c
218}
219
220func (c *RuleBuilderCommand) Output(path string) *RuleBuilderCommand {
221 c.outputs = append(c.outputs, path)
222 return c.Text(path)
223}
224
225func (c *RuleBuilderCommand) ImplicitOutput(path string) *RuleBuilderCommand {
226 c.outputs = append(c.outputs, path)
227 return c
228}
229
230func (c *RuleBuilderCommand) FlagWithInput(flag, path string) *RuleBuilderCommand {
231 c.inputs = append(c.inputs, path)
232 return c.Text(flag + path)
233}
234
235func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths []string, sep string) *RuleBuilderCommand {
236 c.inputs = append(c.inputs, paths...)
237 return c.FlagWithList(flag, paths, sep)
238}
239
240func (c *RuleBuilderCommand) FlagWithOutput(flag, path string) *RuleBuilderCommand {
241 c.outputs = append(c.outputs, path)
242 return c.Text(flag + path)
243}
244
245type unknownRulePath struct {
246 path string
247}
248
249var _ Path = (*unknownRulePath)(nil)
250
251func (p *unknownRulePath) String() string { return p.path }
252func (p *unknownRulePath) Ext() string { return filepath.Ext(p.path) }
253func (p *unknownRulePath) Base() string { return filepath.Base(p.path) }
254func (p *unknownRulePath) Rel() string { return p.path }