f61d03d241
The next CL will need a TestContext parameter in ContentFromFileRuleForTests in order to retrieve the file rule contents from the Config. Add it and update all the tests that use it in order to simply review of the next CL. Bug: 306029038 Test: go test ./... Change-Id: Ia4b4c9854017ea3472fa2f8ba42cf7f72720496e
252 lines
8.2 KiB
Go
252 lines
8.2 KiB
Go
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/bootstrap"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
var (
|
|
pctx = NewPackageContext("android/soong/android")
|
|
exportedVars = NewExportedVariables(pctx)
|
|
|
|
cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
|
|
Config.CpPreserveSymlinksFlags)
|
|
|
|
// A phony rule that is not the built-in Ninja phony rule. The built-in
|
|
// phony rule has special behavior that is sometimes not desired. See the
|
|
// Ninja docs for more details.
|
|
Phony = pctx.AndroidStaticRule("Phony",
|
|
blueprint.RuleParams{
|
|
Command: "# phony $out",
|
|
Description: "phony $out",
|
|
})
|
|
|
|
// GeneratedFile is a rule for indicating that a given file was generated
|
|
// while running soong. This allows the file to be cleaned up if it ever
|
|
// stops being generated by soong.
|
|
GeneratedFile = pctx.AndroidStaticRule("GeneratedFile",
|
|
blueprint.RuleParams{
|
|
Command: "# generated $out",
|
|
Description: "generated $out",
|
|
Generator: true,
|
|
})
|
|
|
|
// A copy rule.
|
|
Cp = pctx.AndroidStaticRule("Cp",
|
|
blueprint.RuleParams{
|
|
Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
|
|
Description: "cp $out",
|
|
},
|
|
"cpFlags", "extraCmds")
|
|
|
|
// A copy rule that doesn't preserve symlinks.
|
|
CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink",
|
|
blueprint.RuleParams{
|
|
Command: "rm -f $out && cp $cpFlags $in $out$extraCmds",
|
|
Description: "cp $out",
|
|
},
|
|
"cpFlags", "extraCmds")
|
|
|
|
// A copy rule that only updates the output if it changed.
|
|
CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
|
|
blueprint.RuleParams{
|
|
Command: "if ! cmp -s $in $out; then cp $in $out; fi",
|
|
Description: "cp if changed $out",
|
|
Restat: true,
|
|
},
|
|
"cpFlags")
|
|
|
|
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
|
|
blueprint.RuleParams{
|
|
Command: "rm -f $out && cp $cpFlags $in $out && chmod +x $out$extraCmds",
|
|
Description: "cp $out",
|
|
},
|
|
"cpFlags", "extraCmds")
|
|
|
|
// A timestamp touch rule.
|
|
Touch = pctx.AndroidStaticRule("Touch",
|
|
blueprint.RuleParams{
|
|
Command: "touch $out",
|
|
Description: "touch $out",
|
|
})
|
|
|
|
// A symlink rule.
|
|
Symlink = pctx.AndroidStaticRule("Symlink",
|
|
blueprint.RuleParams{
|
|
Command: "rm -f $out && ln -f -s $fromPath $out",
|
|
Description: "symlink $out",
|
|
SymlinkOutputs: []string{"$out"},
|
|
},
|
|
"fromPath")
|
|
|
|
ErrorRule = pctx.AndroidStaticRule("Error",
|
|
blueprint.RuleParams{
|
|
Command: `echo "$error" && false`,
|
|
Description: "error building $out",
|
|
},
|
|
"error")
|
|
|
|
Cat = pctx.AndroidStaticRule("Cat",
|
|
blueprint.RuleParams{
|
|
Command: "rm -f $out && cat $in > $out",
|
|
Description: "concatenate files to $out",
|
|
})
|
|
|
|
// ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
|
|
// doesn't support -e option. Therefore we force to use /bin/bash when writing out
|
|
// content to file.
|
|
writeFile = pctx.AndroidStaticRule("writeFile",
|
|
blueprint.RuleParams{
|
|
Command: `rm -f $out && /bin/bash -c 'echo -e -n "$$0" > $out' $content`,
|
|
Description: "writing file $out",
|
|
},
|
|
"content")
|
|
|
|
// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
|
|
localPool = blueprint.NewBuiltinPool("local_pool")
|
|
|
|
// Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
|
|
remotePool = blueprint.NewBuiltinPool("remote_pool")
|
|
|
|
// Used for processes that need significant RAM to ensure there are not too many running in parallel.
|
|
highmemPool = blueprint.NewBuiltinPool("highmem_pool")
|
|
)
|
|
|
|
func init() {
|
|
pctx.Import("github.com/google/blueprint/bootstrap")
|
|
|
|
pctx.VariableFunc("RBEWrapper", func(ctx PackageVarContext) string {
|
|
return ctx.Config().RBEWrapper()
|
|
})
|
|
|
|
exportedVars.ExportStringList("NeverAllowNotInIncludeDir", neverallowNotInIncludeDir)
|
|
exportedVars.ExportStringList("NeverAllowNoUseIncludeDir", neverallowNoUseIncludeDir)
|
|
}
|
|
|
|
func BazelCcToolchainVars(config Config) string {
|
|
return BazelToolchainVars(config, exportedVars)
|
|
}
|
|
|
|
var (
|
|
// echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
|
|
echoEscaper = strings.NewReplacer(
|
|
`\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
|
|
"\n", `\n`, // Then replace newlines with \n
|
|
)
|
|
|
|
// echoEscaper reverses echoEscaper.
|
|
echoUnescaper = strings.NewReplacer(
|
|
`\n`, "\n",
|
|
`\\`, `\`,
|
|
)
|
|
|
|
// shellUnescaper reverses the replacer in proptools.ShellEscape
|
|
shellUnescaper = strings.NewReplacer(`'\''`, `'`)
|
|
)
|
|
|
|
func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
|
|
content = echoEscaper.Replace(content)
|
|
content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
|
|
if content == "" {
|
|
content = "''"
|
|
}
|
|
ctx.Build(pctx, BuildParams{
|
|
Rule: writeFile,
|
|
Output: outputFile,
|
|
Description: "write " + outputFile.Base(),
|
|
Args: map[string]string{
|
|
"content": content,
|
|
},
|
|
})
|
|
}
|
|
|
|
// WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
|
|
// so that the file contains exactly the contents passed to the function, plus a trailing newline.
|
|
func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
|
|
WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
|
|
}
|
|
|
|
// WriteFileRuleVerbatim creates a ninja rule to write contents to a file. The contents will be
|
|
// escaped so that the file contains exactly the contents passed to the function.
|
|
func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
|
|
// This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
|
|
const SHARD_SIZE = 131072 - 10000
|
|
|
|
if len(content) > SHARD_SIZE {
|
|
var chunks WritablePaths
|
|
for i, c := range ShardString(content, SHARD_SIZE) {
|
|
tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
|
|
buildWriteFileRule(ctx, tempPath, c)
|
|
chunks = append(chunks, tempPath)
|
|
}
|
|
ctx.Build(pctx, BuildParams{
|
|
Rule: Cat,
|
|
Inputs: chunks.Paths(),
|
|
Output: outputFile,
|
|
Description: "Merging to " + outputFile.Base(),
|
|
})
|
|
return
|
|
}
|
|
buildWriteFileRule(ctx, outputFile, content)
|
|
}
|
|
|
|
// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
|
|
func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
|
|
intermediate := PathForIntermediates(ctx, "write_executable_file_intermediates").Join(ctx, outputFile.String())
|
|
WriteFileRuleVerbatim(ctx, intermediate, content)
|
|
ctx.Build(pctx, BuildParams{
|
|
Rule: CpExecutable,
|
|
Output: outputFile,
|
|
Input: intermediate,
|
|
})
|
|
}
|
|
|
|
// shellUnescape reverses proptools.ShellEscape
|
|
func shellUnescape(s string) string {
|
|
// Remove leading and trailing quotes if present
|
|
if len(s) >= 2 && s[0] == '\'' {
|
|
s = s[1 : len(s)-1]
|
|
}
|
|
s = shellUnescaper.Replace(s)
|
|
return s
|
|
}
|
|
|
|
// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
|
|
// in tests.
|
|
func ContentFromFileRuleForTests(t *testing.T, ctx *TestContext, params TestingBuildParams) string {
|
|
t.Helper()
|
|
if g, w := params.Rule, writeFile; g != w {
|
|
t.Errorf("expected params.Rule to be %q, was %q", w, g)
|
|
return ""
|
|
}
|
|
|
|
content := params.Args["content"]
|
|
content = shellUnescape(content)
|
|
content = echoUnescaper.Replace(content)
|
|
|
|
return content
|
|
}
|
|
|
|
// GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
|
|
func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
|
|
bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
|
|
}
|