Merge changes Ie8721dcd,If1827b9d,Iec250a2d,I3f46f611,Idf136919, ... am: ba5fff85a7
am: 0b0fcae3ca
am: defc5c9f8a
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1651847 Change-Id: Ifc60075b65f4f27134aaab9315e4c0ffe90f2481
This commit is contained in:
commit
8a63fa9fd2
|
@ -14,6 +14,7 @@ bootstrap_go_package {
|
||||||
"soong-bazel",
|
"soong-bazel",
|
||||||
"soong-cquery",
|
"soong-cquery",
|
||||||
"soong-remoteexec",
|
"soong-remoteexec",
|
||||||
|
"soong-response",
|
||||||
"soong-shared",
|
"soong-shared",
|
||||||
"soong-ui-metrics_proto",
|
"soong-ui-metrics_proto",
|
||||||
],
|
],
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
|
|
||||||
"android/soong/cmd/sbox/sbox_proto"
|
"android/soong/cmd/sbox/sbox_proto"
|
||||||
"android/soong/remoteexec"
|
"android/soong/remoteexec"
|
||||||
|
"android/soong/response"
|
||||||
"android/soong/shared"
|
"android/soong/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -408,30 +409,21 @@ func (r *RuleBuilder) Tools() Paths {
|
||||||
func (r *RuleBuilder) RspFileInputs() Paths {
|
func (r *RuleBuilder) RspFileInputs() Paths {
|
||||||
var rspFileInputs Paths
|
var rspFileInputs Paths
|
||||||
for _, c := range r.commands {
|
for _, c := range r.commands {
|
||||||
if c.rspFileInputs != nil {
|
for _, rspFile := range c.rspFiles {
|
||||||
if rspFileInputs != nil {
|
rspFileInputs = append(rspFileInputs, rspFile.paths...)
|
||||||
panic("Multiple commands in a rule may not have rsp file inputs")
|
|
||||||
}
|
|
||||||
rspFileInputs = c.rspFileInputs
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rspFileInputs
|
return rspFileInputs
|
||||||
}
|
}
|
||||||
|
|
||||||
// RspFile returns the path to the rspfile that was passed to the RuleBuilderCommand.FlagWithRspFileInputList method.
|
func (r *RuleBuilder) rspFiles() []rspFileAndPaths {
|
||||||
func (r *RuleBuilder) RspFile() WritablePath {
|
var rspFiles []rspFileAndPaths
|
||||||
var rspFile WritablePath
|
|
||||||
for _, c := range r.commands {
|
for _, c := range r.commands {
|
||||||
if c.rspFile != nil {
|
rspFiles = append(rspFiles, c.rspFiles...)
|
||||||
if rspFile != nil {
|
|
||||||
panic("Multiple commands in a rule may not have rsp file inputs")
|
|
||||||
}
|
|
||||||
rspFile = c.rspFile
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rspFile
|
return rspFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
|
// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
|
||||||
|
@ -459,26 +451,6 @@ func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderComma
|
||||||
Inputs(depFiles.Paths())
|
Inputs(depFiles.Paths())
|
||||||
}
|
}
|
||||||
|
|
||||||
// composeRspFileContent returns a string that will serve as the contents of the rsp file to pass
|
|
||||||
// the listed input files to the command running in the sandbox.
|
|
||||||
func (r *RuleBuilder) composeRspFileContent(rspFileInputs Paths) string {
|
|
||||||
if r.sboxInputs {
|
|
||||||
if len(rspFileInputs) > 0 {
|
|
||||||
// When SandboxInputs is used the paths need to be rewritten to be relative to the sandbox
|
|
||||||
// directory so that they are valid after sbox chdirs into the sandbox directory.
|
|
||||||
return proptools.NinjaEscape(strings.Join(r.sboxPathsForInputsRel(rspFileInputs), " "))
|
|
||||||
} else {
|
|
||||||
// If the list of inputs is empty fall back to "$in" so that the rspfilecontent Ninja
|
|
||||||
// variable is set to something non-empty, otherwise ninja will complain. The inputs
|
|
||||||
// will be empty (all the non-rspfile inputs are implicits), so $in will evaluate to
|
|
||||||
// an empty string.
|
|
||||||
return "$in"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "$in"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
|
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
|
||||||
// Outputs.
|
// Outputs.
|
||||||
func (r *RuleBuilder) Build(name string, desc string) {
|
func (r *RuleBuilder) Build(name string, desc string) {
|
||||||
|
@ -520,8 +492,7 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
||||||
commands := r.Commands()
|
commands := r.Commands()
|
||||||
outputs := r.Outputs()
|
outputs := r.Outputs()
|
||||||
inputs := r.Inputs()
|
inputs := r.Inputs()
|
||||||
rspFileInputs := r.RspFileInputs()
|
rspFiles := r.rspFiles()
|
||||||
rspFilePath := r.RspFile()
|
|
||||||
|
|
||||||
if len(commands) == 0 {
|
if len(commands) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -575,11 +546,22 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using an rsp file copy it into the sbox directory.
|
// If using rsp files copy them and their contents into the sbox directory with
|
||||||
if rspFilePath != nil {
|
// the appropriate path mappings.
|
||||||
command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
|
for _, rspFile := range rspFiles {
|
||||||
From: proto.String(rspFilePath.String()),
|
command.RspFiles = append(command.RspFiles, &sbox_proto.RspFile{
|
||||||
To: proto.String(r.sboxPathForInputRel(rspFilePath)),
|
File: proto.String(rspFile.file.String()),
|
||||||
|
// These have to match the logic in sboxPathForInputRel
|
||||||
|
PathMappings: []*sbox_proto.PathMapping{
|
||||||
|
{
|
||||||
|
From: proto.String(r.outDir.String()),
|
||||||
|
To: proto.String(sboxOutSubDir),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: proto.String(PathForOutput(r.ctx).String()),
|
||||||
|
To: proto.String(sboxOutSubDir),
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,20 +623,30 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
||||||
inputs = append(inputs, sboxCmd.inputs...)
|
inputs = append(inputs, sboxCmd.inputs...)
|
||||||
|
|
||||||
if r.rbeParams != nil {
|
if r.rbeParams != nil {
|
||||||
var remoteInputs []string
|
// RBE needs a list of input files to copy to the remote builder. For inputs already
|
||||||
remoteInputs = append(remoteInputs, inputs.Strings()...)
|
// listed in an rsp file, pass the rsp file directly to rewrapper. For the rest,
|
||||||
remoteInputs = append(remoteInputs, tools.Strings()...)
|
// create a new rsp file to pass to rewrapper.
|
||||||
remoteInputs = append(remoteInputs, rspFileInputs.Strings()...)
|
var remoteRspFiles Paths
|
||||||
if rspFilePath != nil {
|
var remoteInputs Paths
|
||||||
remoteInputs = append(remoteInputs, rspFilePath.String())
|
|
||||||
|
remoteInputs = append(remoteInputs, inputs...)
|
||||||
|
remoteInputs = append(remoteInputs, tools...)
|
||||||
|
|
||||||
|
for _, rspFile := range rspFiles {
|
||||||
|
remoteInputs = append(remoteInputs, rspFile.file)
|
||||||
|
remoteRspFiles = append(remoteRspFiles, rspFile.file)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remoteInputs) > 0 {
|
||||||
|
inputsListFile := r.sboxManifestPath.ReplaceExtension(r.ctx, "rbe_inputs.list")
|
||||||
|
writeRspFileRule(r.ctx, inputsListFile, remoteInputs)
|
||||||
|
remoteRspFiles = append(remoteRspFiles, inputsListFile)
|
||||||
|
// Add the new rsp file as an extra input to the rule.
|
||||||
|
inputs = append(inputs, inputsListFile)
|
||||||
}
|
}
|
||||||
inputsListFile := r.sboxManifestPath.ReplaceExtension(r.ctx, "rbe_inputs.list")
|
|
||||||
inputsListContents := rspFileForInputs(remoteInputs)
|
|
||||||
WriteFileRule(r.ctx, inputsListFile, inputsListContents)
|
|
||||||
inputs = append(inputs, inputsListFile)
|
|
||||||
|
|
||||||
r.rbeParams.OutputFiles = outputs.Strings()
|
r.rbeParams.OutputFiles = outputs.Strings()
|
||||||
r.rbeParams.RSPFile = inputsListFile.String()
|
r.rbeParams.RSPFiles = remoteRspFiles.Strings()
|
||||||
rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
|
rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
|
||||||
commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
|
commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
|
||||||
}
|
}
|
||||||
|
@ -672,9 +664,24 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
||||||
implicitOutputs := outputs[1:]
|
implicitOutputs := outputs[1:]
|
||||||
|
|
||||||
var rspFile, rspFileContent string
|
var rspFile, rspFileContent string
|
||||||
if rspFilePath != nil {
|
var rspFileInputs Paths
|
||||||
rspFile = rspFilePath.String()
|
if len(rspFiles) > 0 {
|
||||||
rspFileContent = r.composeRspFileContent(rspFileInputs)
|
// The first rsp files uses Ninja's rsp file support for the rule
|
||||||
|
rspFile = rspFiles[0].file.String()
|
||||||
|
// Use "$in" for rspFileContent to avoid duplicating the list of files in the dependency
|
||||||
|
// list and in the contents of the rsp file. Inputs to the rule that are not in the
|
||||||
|
// rsp file will be listed in Implicits instead of Inputs so they don't show up in "$in".
|
||||||
|
rspFileContent = "$in"
|
||||||
|
rspFileInputs = append(rspFileInputs, rspFiles[0].paths...)
|
||||||
|
|
||||||
|
for _, rspFile := range rspFiles[1:] {
|
||||||
|
// Any additional rsp files need an extra rule to write the file.
|
||||||
|
writeRspFileRule(r.ctx, rspFile.file, rspFile.paths)
|
||||||
|
// The main rule needs to depend on the inputs listed in the extra rsp file.
|
||||||
|
inputs = append(inputs, rspFile.paths...)
|
||||||
|
// The main rule needs to depend on the extra rsp file.
|
||||||
|
inputs = append(inputs, rspFile.file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool blueprint.Pool
|
var pool blueprint.Pool
|
||||||
|
@ -725,8 +732,12 @@ type RuleBuilderCommand struct {
|
||||||
depFiles WritablePaths
|
depFiles WritablePaths
|
||||||
tools Paths
|
tools Paths
|
||||||
packagedTools []PackagingSpec
|
packagedTools []PackagingSpec
|
||||||
rspFileInputs Paths
|
rspFiles []rspFileAndPaths
|
||||||
rspFile WritablePath
|
}
|
||||||
|
|
||||||
|
type rspFileAndPaths struct {
|
||||||
|
file WritablePath
|
||||||
|
paths Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RuleBuilderCommand) addInput(path Path) string {
|
func (c *RuleBuilderCommand) addInput(path Path) string {
|
||||||
|
@ -1170,22 +1181,19 @@ func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *Ru
|
||||||
return c.Text(flag + c.PathForOutput(path))
|
return c.Text(flag + c.PathForOutput(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with no separator
|
// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with
|
||||||
// between them. The paths will be written to the rspfile. If sbox is enabled, the rspfile must
|
// no separator between them. The paths will be written to the rspfile. If sbox is enabled, the
|
||||||
// be outside the sbox directory.
|
// rspfile must be outside the sbox directory. The first use of FlagWithRspFileInputList in any
|
||||||
|
// RuleBuilderCommand of a RuleBuilder will use Ninja's rsp file support for the rule, additional
|
||||||
|
// uses will result in an auxiliary rules to write the rspFile contents.
|
||||||
func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, rspFile WritablePath, paths Paths) *RuleBuilderCommand {
|
func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, rspFile WritablePath, paths Paths) *RuleBuilderCommand {
|
||||||
if c.rspFileInputs != nil {
|
|
||||||
panic("FlagWithRspFileInputList cannot be called if rsp file inputs have already been provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
|
// Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
|
||||||
// generated.
|
// generated.
|
||||||
if paths == nil {
|
if paths == nil {
|
||||||
paths = Paths{}
|
paths = Paths{}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.rspFileInputs = paths
|
c.rspFiles = append(c.rspFiles, rspFileAndPaths{rspFile, paths})
|
||||||
c.rspFile = rspFile
|
|
||||||
|
|
||||||
if c.rule.sbox {
|
if c.rule.sbox {
|
||||||
if _, isRel, _ := maybeRelErr(c.rule.outDir.String(), rspFile.String()); isRel {
|
if _, isRel, _ := maybeRelErr(c.rule.outDir.String(), rspFile.String()); isRel {
|
||||||
|
@ -1264,13 +1272,12 @@ func (builderContextForTests) Rule(PackageContext, string, blueprint.RuleParams,
|
||||||
}
|
}
|
||||||
func (builderContextForTests) Build(PackageContext, BuildParams) {}
|
func (builderContextForTests) Build(PackageContext, BuildParams) {}
|
||||||
|
|
||||||
func rspFileForInputs(paths []string) string {
|
func writeRspFileRule(ctx BuilderContext, rspFile WritablePath, paths Paths) {
|
||||||
s := strings.Builder{}
|
buf := &strings.Builder{}
|
||||||
for i, path := range paths {
|
err := response.WriteRspFile(buf, paths.Strings())
|
||||||
if i != 0 {
|
if err != nil {
|
||||||
s.WriteByte(' ')
|
// There should never be I/O errors writing to a bytes.Buffer.
|
||||||
}
|
panic(err)
|
||||||
s.WriteString(proptools.ShellEscape(path))
|
|
||||||
}
|
}
|
||||||
return s.String()
|
WriteFileRule(ctx, rspFile, buf.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,8 +376,6 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
|
wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
|
||||||
"out_local/module/DepFile out_local/module/depfile out_local/module/ImplicitDepFile out_local/module/depfile2"
|
"out_local/module/DepFile out_local/module/depfile out_local/module/ImplicitDepFile out_local/module/depfile2"
|
||||||
|
|
||||||
wantRspFileContent := "$in"
|
|
||||||
|
|
||||||
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
||||||
|
|
||||||
AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
|
AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
|
||||||
|
@ -389,8 +387,6 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
||||||
|
|
||||||
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
||||||
|
|
||||||
AssertSame(t, "rule.composeRspFileContent()", wantRspFileContent, rule.composeRspFileContent(rule.RspFileInputs()))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("sbox", func(t *testing.T) {
|
t.Run("sbox", func(t *testing.T) {
|
||||||
|
@ -409,8 +405,6 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
|
|
||||||
wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
|
wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
|
||||||
|
|
||||||
wantRspFileContent := "$in"
|
|
||||||
|
|
||||||
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
||||||
|
|
||||||
AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
|
AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
|
||||||
|
@ -422,8 +416,6 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
||||||
|
|
||||||
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
||||||
|
|
||||||
AssertSame(t, "rule.composeRspFileContent()", wantRspFileContent, rule.composeRspFileContent(rule.RspFileInputs()))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("sbox tools", func(t *testing.T) {
|
t.Run("sbox tools", func(t *testing.T) {
|
||||||
|
@ -442,7 +434,34 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
|
|
||||||
wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
|
wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
|
||||||
|
|
||||||
wantRspFileContent := "$in"
|
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
||||||
|
|
||||||
|
AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
|
||||||
|
AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
|
||||||
|
AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
|
||||||
|
AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
|
||||||
|
AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
|
||||||
|
AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
|
||||||
|
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
||||||
|
|
||||||
|
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("sbox inputs", func(t *testing.T) {
|
||||||
|
rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
|
||||||
|
PathForOutput(ctx, "sbox.textproto")).SandboxInputs()
|
||||||
|
addCommands(rule)
|
||||||
|
|
||||||
|
wantCommands := []string{
|
||||||
|
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
|
||||||
|
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
|
||||||
|
"FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
|
||||||
|
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
|
||||||
|
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
|
||||||
|
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
|
||||||
|
}
|
||||||
|
|
||||||
|
wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
|
||||||
|
|
||||||
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
|
||||||
|
|
||||||
|
@ -455,8 +474,6 @@ func TestRuleBuilder(t *testing.T) {
|
||||||
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
|
||||||
|
|
||||||
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
|
||||||
|
|
||||||
AssertSame(t, "rule.composeRspFileContent()", wantRspFileContent, rule.composeRspFileContent(rule.RspFileInputs()))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,8 +489,9 @@ type testRuleBuilderModule struct {
|
||||||
properties struct {
|
properties struct {
|
||||||
Srcs []string
|
Srcs []string
|
||||||
|
|
||||||
Restat bool
|
Restat bool
|
||||||
Sbox bool
|
Sbox bool
|
||||||
|
Sbox_inputs bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,9 +500,15 @@ func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||||
out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
|
out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
|
||||||
outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
|
outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
|
||||||
outDir := PathForModuleOut(ctx, "gen")
|
outDir := PathForModuleOut(ctx, "gen")
|
||||||
|
rspFile := PathForModuleOut(ctx, "rsp")
|
||||||
|
rspFile2 := PathForModuleOut(ctx, "rsp2")
|
||||||
|
rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
|
||||||
|
rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
|
||||||
manifestPath := PathForModuleOut(ctx, "sbox.textproto")
|
manifestPath := PathForModuleOut(ctx, "sbox.textproto")
|
||||||
|
|
||||||
testRuleBuilder_Build(ctx, in, out, outDep, outDir, manifestPath, t.properties.Restat, t.properties.Sbox)
|
testRuleBuilder_Build(ctx, in, out, outDep, outDir, manifestPath, t.properties.Restat,
|
||||||
|
t.properties.Sbox, t.properties.Sbox_inputs, rspFile, rspFileContents,
|
||||||
|
rspFile2, rspFileContents2)
|
||||||
}
|
}
|
||||||
|
|
||||||
type testRuleBuilderSingleton struct{}
|
type testRuleBuilderSingleton struct{}
|
||||||
|
@ -498,18 +522,35 @@ func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||||
out := PathForOutput(ctx, "singleton/gen/baz")
|
out := PathForOutput(ctx, "singleton/gen/baz")
|
||||||
outDep := PathForOutput(ctx, "singleton/gen/baz.d")
|
outDep := PathForOutput(ctx, "singleton/gen/baz.d")
|
||||||
outDir := PathForOutput(ctx, "singleton/gen")
|
outDir := PathForOutput(ctx, "singleton/gen")
|
||||||
|
rspFile := PathForOutput(ctx, "singleton/rsp")
|
||||||
|
rspFile2 := PathForOutput(ctx, "singleton/rsp2")
|
||||||
|
rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
|
||||||
|
rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
|
||||||
manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
|
manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
|
||||||
testRuleBuilder_Build(ctx, Paths{in}, out, outDep, outDir, manifestPath, true, false)
|
testRuleBuilder_Build(ctx, Paths{in}, out, outDep, outDir, manifestPath, true, false, false,
|
||||||
|
rspFile, rspFileContents, rspFile2, rspFileContents2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRuleBuilder_Build(ctx BuilderContext, in Paths, out, outDep, outDir, manifestPath WritablePath, restat, sbox bool) {
|
func testRuleBuilder_Build(ctx BuilderContext, in Paths, out, outDep, outDir, manifestPath WritablePath,
|
||||||
|
restat, sbox, sboxInputs bool,
|
||||||
|
rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
|
||||||
|
|
||||||
rule := NewRuleBuilder(pctx, ctx)
|
rule := NewRuleBuilder(pctx, ctx)
|
||||||
|
|
||||||
if sbox {
|
if sbox {
|
||||||
rule.Sbox(outDir, manifestPath)
|
rule.Sbox(outDir, manifestPath)
|
||||||
|
if sboxInputs {
|
||||||
|
rule.SandboxInputs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.Command().Tool(PathForSource(ctx, "cp")).Inputs(in).Output(out).ImplicitDepFile(outDep)
|
rule.Command().
|
||||||
|
Tool(PathForSource(ctx, "cp")).
|
||||||
|
Inputs(in).
|
||||||
|
Output(out).
|
||||||
|
ImplicitDepFile(outDep).
|
||||||
|
FlagWithRspFileInputList("@", rspFile, rspFileContents).
|
||||||
|
FlagWithRspFileInputList("@", rspFile2, rspFileContents2)
|
||||||
|
|
||||||
if restat {
|
if restat {
|
||||||
rule.Restat()
|
rule.Restat()
|
||||||
|
@ -540,6 +581,12 @@ func TestRuleBuilder_Build(t *testing.T) {
|
||||||
srcs: ["bar"],
|
srcs: ["bar"],
|
||||||
sbox: true,
|
sbox: true,
|
||||||
}
|
}
|
||||||
|
rule_builder_test {
|
||||||
|
name: "foo_sbox_inputs",
|
||||||
|
srcs: ["bar"],
|
||||||
|
sbox: true,
|
||||||
|
sbox_inputs: true,
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
result := GroupFixturePreparers(
|
result := GroupFixturePreparers(
|
||||||
|
@ -548,7 +595,10 @@ func TestRuleBuilder_Build(t *testing.T) {
|
||||||
fs.AddToFixture(),
|
fs.AddToFixture(),
|
||||||
).RunTest(t)
|
).RunTest(t)
|
||||||
|
|
||||||
check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraImplicits, extraCmdDeps []string) {
|
check := func(t *testing.T, params TestingBuildParams, rspFile2Params TestingBuildParams,
|
||||||
|
wantCommand, wantOutput, wantDepfile, wantRspFile, wantRspFile2 string,
|
||||||
|
wantRestat bool, extraImplicits, extraCmdDeps []string) {
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
command := params.RuleParams.Command
|
command := params.RuleParams.Command
|
||||||
re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
|
re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
|
||||||
|
@ -561,9 +611,19 @@ func TestRuleBuilder_Build(t *testing.T) {
|
||||||
|
|
||||||
AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
|
AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
|
||||||
|
|
||||||
|
wantInputs := []string{"rsp_in"}
|
||||||
|
AssertArrayString(t, "Inputs", wantInputs, params.Inputs.Strings())
|
||||||
|
|
||||||
wantImplicits := append([]string{"bar"}, extraImplicits...)
|
wantImplicits := append([]string{"bar"}, extraImplicits...)
|
||||||
|
// The second rsp file and the files listed in it should be in implicits
|
||||||
|
wantImplicits = append(wantImplicits, "rsp_in2", wantRspFile2)
|
||||||
AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
|
AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
|
||||||
|
|
||||||
|
wantRspFileContent := "$in"
|
||||||
|
AssertStringEquals(t, "RspfileContent", wantRspFileContent, params.RuleParams.RspfileContent)
|
||||||
|
|
||||||
|
AssertStringEquals(t, "Rspfile", wantRspFile, params.RuleParams.Rspfile)
|
||||||
|
|
||||||
AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
|
AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
|
||||||
|
|
||||||
if len(params.ImplicitOutputs) != 0 {
|
if len(params.ImplicitOutputs) != 0 {
|
||||||
|
@ -575,18 +635,42 @@ func TestRuleBuilder_Build(t *testing.T) {
|
||||||
if params.Deps != blueprint.DepsGCC {
|
if params.Deps != blueprint.DepsGCC {
|
||||||
t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
|
t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rspFile2Content := ContentFromFileRuleForTests(t, rspFile2Params)
|
||||||
|
AssertStringEquals(t, "rspFile2 content", "rsp_in2\n", rspFile2Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("module", func(t *testing.T) {
|
t.Run("module", func(t *testing.T) {
|
||||||
outFile := "out/soong/.intermediates/foo/gen/foo"
|
outFile := "out/soong/.intermediates/foo/gen/foo"
|
||||||
check(t, result.ModuleForTests("foo", "").Rule("rule").RelativeToTop(),
|
rspFile := "out/soong/.intermediates/foo/rsp"
|
||||||
"cp bar "+outFile,
|
rspFile2 := "out/soong/.intermediates/foo/rsp2"
|
||||||
outFile, outFile+".d", true, nil, nil)
|
module := result.ModuleForTests("foo", "")
|
||||||
|
check(t, module.Rule("rule").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||||
|
"cp bar "+outFile+" @"+rspFile+" @"+rspFile2,
|
||||||
|
outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
|
||||||
})
|
})
|
||||||
t.Run("sbox", func(t *testing.T) {
|
t.Run("sbox", func(t *testing.T) {
|
||||||
outDir := "out/soong/.intermediates/foo_sbox"
|
outDir := "out/soong/.intermediates/foo_sbox"
|
||||||
outFile := filepath.Join(outDir, "gen/foo_sbox")
|
outFile := filepath.Join(outDir, "gen/foo_sbox")
|
||||||
depFile := filepath.Join(outDir, "gen/foo_sbox.d")
|
depFile := filepath.Join(outDir, "gen/foo_sbox.d")
|
||||||
|
rspFile := filepath.Join(outDir, "rsp")
|
||||||
|
rspFile2 := filepath.Join(outDir, "rsp2")
|
||||||
|
manifest := filepath.Join(outDir, "sbox.textproto")
|
||||||
|
sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
|
||||||
|
sandboxPath := shared.TempDirForOutDir("out/soong")
|
||||||
|
|
||||||
|
cmd := `rm -rf ` + outDir + `/gen && ` +
|
||||||
|
sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
|
||||||
|
module := result.ModuleForTests("foo_sbox", "")
|
||||||
|
check(t, module.Output("gen/foo_sbox").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||||
|
cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
|
||||||
|
})
|
||||||
|
t.Run("sbox_inputs", func(t *testing.T) {
|
||||||
|
outDir := "out/soong/.intermediates/foo_sbox_inputs"
|
||||||
|
outFile := filepath.Join(outDir, "gen/foo_sbox_inputs")
|
||||||
|
depFile := filepath.Join(outDir, "gen/foo_sbox_inputs.d")
|
||||||
|
rspFile := filepath.Join(outDir, "rsp")
|
||||||
|
rspFile2 := filepath.Join(outDir, "rsp2")
|
||||||
manifest := filepath.Join(outDir, "sbox.textproto")
|
manifest := filepath.Join(outDir, "sbox.textproto")
|
||||||
sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
|
sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
|
||||||
sandboxPath := shared.TempDirForOutDir("out/soong")
|
sandboxPath := shared.TempDirForOutDir("out/soong")
|
||||||
|
@ -594,13 +678,18 @@ func TestRuleBuilder_Build(t *testing.T) {
|
||||||
cmd := `rm -rf ` + outDir + `/gen && ` +
|
cmd := `rm -rf ` + outDir + `/gen && ` +
|
||||||
sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
|
sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
|
||||||
|
|
||||||
check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox").RelativeToTop(),
|
module := result.ModuleForTests("foo_sbox_inputs", "")
|
||||||
cmd, outFile, depFile, false, []string{manifest}, []string{sbox})
|
check(t, module.Output("gen/foo_sbox_inputs").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||||
|
cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
|
||||||
})
|
})
|
||||||
t.Run("singleton", func(t *testing.T) {
|
t.Run("singleton", func(t *testing.T) {
|
||||||
outFile := filepath.Join("out/soong/singleton/gen/baz")
|
outFile := filepath.Join("out/soong/singleton/gen/baz")
|
||||||
check(t, result.SingletonForTests("rule_builder_test").Rule("rule").RelativeToTop(),
|
rspFile := filepath.Join("out/soong/singleton/rsp")
|
||||||
"cp bar "+outFile, outFile, outFile+".d", true, nil, nil)
|
rspFile2 := filepath.Join("out/soong/singleton/rsp2")
|
||||||
|
singleton := result.SingletonForTests("rule_builder_test")
|
||||||
|
check(t, singleton.Rule("rule").RelativeToTop(), singleton.Output(rspFile2).RelativeToTop(),
|
||||||
|
"cp bar "+outFile+" @"+rspFile+" @"+rspFile2,
|
||||||
|
outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ var (
|
||||||
Labels: map[string]string{"type": "link", "tool": "clang"},
|
Labels: map[string]string{"type": "link", "tool": "clang"},
|
||||||
ExecStrategy: "${config.RECXXLinksExecStrategy}",
|
ExecStrategy: "${config.RECXXLinksExecStrategy}",
|
||||||
Inputs: []string{"${out}.rsp", "$implicitInputs"},
|
Inputs: []string{"${out}.rsp", "$implicitInputs"},
|
||||||
RSPFile: "${out}.rsp",
|
RSPFiles: []string{"${out}.rsp"},
|
||||||
OutputFiles: []string{"${out}", "$implicitOutputs"},
|
OutputFiles: []string{"${out}", "$implicitOutputs"},
|
||||||
ToolchainInputs: []string{"$ldCmd"},
|
ToolchainInputs: []string{"$ldCmd"},
|
||||||
Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
|
Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
|
||||||
|
@ -256,7 +256,7 @@ var (
|
||||||
Labels: map[string]string{"type": "tool", "name": "abi-linker"},
|
Labels: map[string]string{"type": "tool", "name": "abi-linker"},
|
||||||
ExecStrategy: "${config.REAbiLinkerExecStrategy}",
|
ExecStrategy: "${config.REAbiLinkerExecStrategy}",
|
||||||
Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"},
|
Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"},
|
||||||
RSPFile: "${out}.rsp",
|
RSPFiles: []string{"${out}.rsp"},
|
||||||
OutputFiles: []string{"$out"},
|
OutputFiles: []string{"$out"},
|
||||||
ToolchainInputs: []string{"$sAbiLinker"},
|
ToolchainInputs: []string{"$sAbiLinker"},
|
||||||
Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"},
|
Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"},
|
||||||
|
|
|
@ -22,7 +22,7 @@ blueprint_go_binary {
|
||||||
"android-archive-zip",
|
"android-archive-zip",
|
||||||
"blueprint-pathtools",
|
"blueprint-pathtools",
|
||||||
"soong-jar",
|
"soong-jar",
|
||||||
"soong-zip",
|
"soong-response",
|
||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"merge_zips.go",
|
"merge_zips.go",
|
||||||
|
|
|
@ -25,12 +25,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"android/soong/response"
|
||||||
|
|
||||||
"github.com/google/blueprint/pathtools"
|
"github.com/google/blueprint/pathtools"
|
||||||
|
|
||||||
"android/soong/jar"
|
"android/soong/jar"
|
||||||
"android/soong/third_party/zip"
|
"android/soong/third_party/zip"
|
||||||
soongZip "android/soong/zip"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Input zip: we can open it, close it, and obtain an array of entries
|
// Input zip: we can open it, close it, and obtain an array of entries
|
||||||
|
@ -690,15 +692,20 @@ func main() {
|
||||||
inputs := make([]string, 0)
|
inputs := make([]string, 0)
|
||||||
for _, input := range args[1:] {
|
for _, input := range args[1:] {
|
||||||
if input[0] == '@' {
|
if input[0] == '@' {
|
||||||
bytes, err := ioutil.ReadFile(input[1:])
|
f, err := os.Open(strings.TrimPrefix(input[1:], "@"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
inputs = append(inputs, soongZip.ReadRespFile(bytes)...)
|
|
||||||
continue
|
rspInputs, err := response.ReadRspFile(f)
|
||||||
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
inputs = append(inputs, rspInputs...)
|
||||||
|
} else {
|
||||||
|
inputs = append(inputs, input)
|
||||||
}
|
}
|
||||||
inputs = append(inputs, input)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.SetFlags(log.Lshortfile)
|
log.SetFlags(log.Lshortfile)
|
||||||
|
|
|
@ -21,6 +21,7 @@ blueprint_go_binary {
|
||||||
deps: [
|
deps: [
|
||||||
"sbox_proto",
|
"sbox_proto",
|
||||||
"soong-makedeps",
|
"soong-makedeps",
|
||||||
|
"soong-response",
|
||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"sbox.go",
|
"sbox.go",
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
|
|
||||||
"android/soong/cmd/sbox/sbox_proto"
|
"android/soong/cmd/sbox/sbox_proto"
|
||||||
"android/soong/makedeps"
|
"android/soong/makedeps"
|
||||||
|
"android/soong/response"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
@ -218,6 +219,11 @@ func runCommand(command *sbox_proto.Command, tempDir string) (depFile string, er
|
||||||
return "", fmt.Errorf("command is required")
|
return "", fmt.Errorf("command is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathToTempDirInSbox := tempDir
|
||||||
|
if command.GetChdir() {
|
||||||
|
pathToTempDirInSbox = "."
|
||||||
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(tempDir, 0777)
|
err = os.MkdirAll(tempDir, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to create %q: %w", tempDir, err)
|
return "", fmt.Errorf("failed to create %q: %w", tempDir, err)
|
||||||
|
@ -228,10 +234,9 @@ func runCommand(command *sbox_proto.Command, tempDir string) (depFile string, er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
err = copyRspFiles(command.RspFiles, tempDir, pathToTempDirInSbox)
|
||||||
pathToTempDirInSbox := tempDir
|
if err != nil {
|
||||||
if command.GetChdir() {
|
return "", err
|
||||||
pathToTempDirInSbox = "."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(rawCommand, depFilePlaceholder) {
|
if strings.Contains(rawCommand, depFilePlaceholder) {
|
||||||
|
@ -409,6 +414,83 @@ func copyOneFile(from string, to string, executable bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copyRspFiles copies rsp files into the sandbox with path mappings, and also copies the files
|
||||||
|
// listed into the sandbox.
|
||||||
|
func copyRspFiles(rspFiles []*sbox_proto.RspFile, toDir, toDirInSandbox string) error {
|
||||||
|
for _, rspFile := range rspFiles {
|
||||||
|
err := copyOneRspFile(rspFile, toDir, toDirInSandbox)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyOneRspFiles copies an rsp file into the sandbox with path mappings, and also copies the files
|
||||||
|
// listed into the sandbox.
|
||||||
|
func copyOneRspFile(rspFile *sbox_proto.RspFile, toDir, toDirInSandbox string) error {
|
||||||
|
in, err := os.Open(rspFile.GetFile())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
files, err := response.ReadRspFile(in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, from := range files {
|
||||||
|
// Convert the real path of the input file into the path inside the sandbox using the
|
||||||
|
// path mappings.
|
||||||
|
to := applyPathMappings(rspFile.PathMappings, from)
|
||||||
|
|
||||||
|
// Copy the file into the sandbox.
|
||||||
|
err := copyOneFile(from, joinPath(toDir, to), false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite the name in the list of files to be relative to the sandbox directory.
|
||||||
|
files[i] = joinPath(toDirInSandbox, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the real path of the rsp file into the path inside the sandbox using the path
|
||||||
|
// mappings.
|
||||||
|
outRspFile := joinPath(toDir, applyPathMappings(rspFile.PathMappings, rspFile.GetFile()))
|
||||||
|
|
||||||
|
err = os.MkdirAll(filepath.Dir(outRspFile), 0777)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := os.Create(outRspFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// Write the rsp file with converted paths into the sandbox.
|
||||||
|
err = response.WriteRspFile(out, files)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyPathMappings takes a list of path mappings and a path, and returns the path with the first
|
||||||
|
// matching path mapping applied. If the path does not match any of the path mappings then it is
|
||||||
|
// returned unmodified.
|
||||||
|
func applyPathMappings(pathMappings []*sbox_proto.PathMapping, path string) string {
|
||||||
|
for _, mapping := range pathMappings {
|
||||||
|
if strings.HasPrefix(path, mapping.GetFrom()+"/") {
|
||||||
|
return joinPath(mapping.GetTo()+"/", strings.TrimPrefix(path, mapping.GetFrom()+"/"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
// moveFiles moves files specified by a set of copy rules. It uses os.Rename, so it is restricted
|
// moveFiles moves files specified by a set of copy rules. It uses os.Rename, so it is restricted
|
||||||
// to moving files where the source and destination are in the same filesystem. This is OK for
|
// to moving files where the source and destination are in the same filesystem. This is OK for
|
||||||
// sbox because the temporary directory is inside the out directory. It updates the timestamp
|
// sbox because the temporary directory is inside the out directory. It updates the timestamp
|
||||||
|
|
|
@ -86,10 +86,13 @@ type Command struct {
|
||||||
CopyAfter []*Copy `protobuf:"bytes,4,rep,name=copy_after,json=copyAfter" json:"copy_after,omitempty"`
|
CopyAfter []*Copy `protobuf:"bytes,4,rep,name=copy_after,json=copyAfter" json:"copy_after,omitempty"`
|
||||||
// An optional hash of the input files to ensure the textproto files and the sbox rule reruns
|
// An optional hash of the input files to ensure the textproto files and the sbox rule reruns
|
||||||
// when the lists of inputs changes, even if the inputs are not on the command line.
|
// when the lists of inputs changes, even if the inputs are not on the command line.
|
||||||
InputHash *string `protobuf:"bytes,5,opt,name=input_hash,json=inputHash" json:"input_hash,omitempty"`
|
InputHash *string `protobuf:"bytes,5,opt,name=input_hash,json=inputHash" json:"input_hash,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
// A list of files that will be copied before the sandboxed command, and whose contents should be
|
||||||
XXX_unrecognized []byte `json:"-"`
|
// copied as if they were listed in copy_before.
|
||||||
XXX_sizecache int32 `json:"-"`
|
RspFiles []*RspFile `protobuf:"bytes,6,rep,name=rsp_files,json=rspFiles" json:"rsp_files,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Command) Reset() { *m = Command{} }
|
func (m *Command) Reset() { *m = Command{} }
|
||||||
|
@ -152,6 +155,13 @@ func (m *Command) GetInputHash() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Command) GetRspFiles() []*RspFile {
|
||||||
|
if m != nil {
|
||||||
|
return m.RspFiles
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
|
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
|
||||||
// are relative to is specific to the context the Copy is used in and will be different for
|
// are relative to is specific to the context the Copy is used in and will be different for
|
||||||
// from and to.
|
// from and to.
|
||||||
|
@ -211,10 +221,110 @@ func (m *Copy) GetExecutable() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RspFile describes an rspfile that should be copied into the sandbox directory.
|
||||||
|
type RspFile struct {
|
||||||
|
// The path to the rsp file.
|
||||||
|
File *string `protobuf:"bytes,1,req,name=file" json:"file,omitempty"`
|
||||||
|
// A list of path mappings that should be applied to each file listed in the rsp file.
|
||||||
|
PathMappings []*PathMapping `protobuf:"bytes,2,rep,name=path_mappings,json=pathMappings" json:"path_mappings,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RspFile) Reset() { *m = RspFile{} }
|
||||||
|
func (m *RspFile) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*RspFile) ProtoMessage() {}
|
||||||
|
func (*RspFile) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_9d0425bf0de86ed1, []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RspFile) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_RspFile.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *RspFile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_RspFile.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (m *RspFile) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_RspFile.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *RspFile) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_RspFile.Size(m)
|
||||||
|
}
|
||||||
|
func (m *RspFile) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_RspFile.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_RspFile proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *RspFile) GetFile() string {
|
||||||
|
if m != nil && m.File != nil {
|
||||||
|
return *m.File
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RspFile) GetPathMappings() []*PathMapping {
|
||||||
|
if m != nil {
|
||||||
|
return m.PathMappings
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathMapping describes a mapping from a path outside the sandbox to the path inside the sandbox.
|
||||||
|
type PathMapping struct {
|
||||||
|
From *string `protobuf:"bytes,1,req,name=from" json:"from,omitempty"`
|
||||||
|
To *string `protobuf:"bytes,2,req,name=to" json:"to,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PathMapping) Reset() { *m = PathMapping{} }
|
||||||
|
func (m *PathMapping) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*PathMapping) ProtoMessage() {}
|
||||||
|
func (*PathMapping) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_9d0425bf0de86ed1, []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PathMapping) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_PathMapping.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *PathMapping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_PathMapping.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (m *PathMapping) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_PathMapping.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *PathMapping) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_PathMapping.Size(m)
|
||||||
|
}
|
||||||
|
func (m *PathMapping) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_PathMapping.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_PathMapping proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *PathMapping) GetFrom() string {
|
||||||
|
if m != nil && m.From != nil {
|
||||||
|
return *m.From
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PathMapping) GetTo() string {
|
||||||
|
if m != nil && m.To != nil {
|
||||||
|
return *m.To
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterType((*Manifest)(nil), "sbox.Manifest")
|
proto.RegisterType((*Manifest)(nil), "sbox.Manifest")
|
||||||
proto.RegisterType((*Command)(nil), "sbox.Command")
|
proto.RegisterType((*Command)(nil), "sbox.Command")
|
||||||
proto.RegisterType((*Copy)(nil), "sbox.Copy")
|
proto.RegisterType((*Copy)(nil), "sbox.Copy")
|
||||||
|
proto.RegisterType((*RspFile)(nil), "sbox.RspFile")
|
||||||
|
proto.RegisterType((*PathMapping)(nil), "sbox.PathMapping")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -222,22 +332,27 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptor_9d0425bf0de86ed1 = []byte{
|
var fileDescriptor_9d0425bf0de86ed1 = []byte{
|
||||||
// 268 bytes of a gzipped FileDescriptorProto
|
// 342 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0x4f, 0x4b, 0xc3, 0x40,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x5f, 0x4b, 0xc3, 0x30,
|
||||||
0x10, 0xc5, 0xc9, 0x9f, 0xd2, 0x64, 0x6a, 0x7b, 0x18, 0x3c, 0xec, 0x45, 0x09, 0x01, 0x21, 0x45,
|
0x14, 0xc5, 0x69, 0xd7, 0xb9, 0xf6, 0xee, 0x0f, 0x18, 0x7c, 0xc8, 0x8b, 0x32, 0x0a, 0xc2, 0xa6,
|
||||||
0xe8, 0xc1, 0x6f, 0x60, 0xf5, 0x20, 0x82, 0x97, 0x1c, 0x45, 0x08, 0x9b, 0x64, 0x43, 0x02, 0x4d,
|
0x30, 0xd0, 0x07, 0xdf, 0x9d, 0x22, 0x22, 0x0c, 0x24, 0xe0, 0x8b, 0x08, 0x25, 0xeb, 0x52, 0x5b,
|
||||||
0x26, 0xec, 0x6e, 0xa0, 0xfd, 0x56, 0x7e, 0x44, 0xd9, 0x49, 0x2a, 0x82, 0xb7, 0x99, 0xdf, 0xe3,
|
0x58, 0x9b, 0x90, 0x64, 0xb0, 0x7d, 0x57, 0x3f, 0x8c, 0xe4, 0xa6, 0xd3, 0x82, 0x2f, 0xbe, 0xdd,
|
||||||
0xcd, 0x7b, 0x0c, 0x80, 0x29, 0xe9, 0x7c, 0x18, 0x35, 0x59, 0xc2, 0xd0, 0xcd, 0xe9, 0x17, 0x44,
|
0x7b, 0x0e, 0xf7, 0xdc, 0x5f, 0xc2, 0x05, 0x30, 0x6b, 0xb9, 0x5f, 0x28, 0x2d, 0xad, 0x24, 0x91,
|
||||||
0x1f, 0x72, 0xe8, 0x1a, 0x65, 0x2c, 0xee, 0x21, 0xaa, 0xa8, 0xef, 0xe5, 0x50, 0x1b, 0xe1, 0x25,
|
0xab, 0xd3, 0x0f, 0x88, 0x57, 0xbc, 0xa9, 0x0a, 0x61, 0x2c, 0x99, 0x43, 0x9c, 0xcb, 0xba, 0xe6,
|
||||||
0x41, 0xb6, 0x79, 0xda, 0x1e, 0xd8, 0xf0, 0x32, 0xd3, 0xfc, 0x57, 0xc6, 0x07, 0xd8, 0xd1, 0x64,
|
0xcd, 0xc6, 0xd0, 0x60, 0xda, 0x9b, 0x0d, 0x6f, 0xc7, 0x0b, 0x1c, 0x78, 0xf0, 0x2a, 0xfb, 0xb1,
|
||||||
0xc7, 0xc9, 0x16, 0xb5, 0x1a, 0x9b, 0xee, 0xa4, 0x84, 0x9f, 0x78, 0x59, 0x9c, 0x6f, 0x67, 0xfa,
|
0xc9, 0x25, 0x4c, 0xe4, 0xce, 0xaa, 0x9d, 0xcd, 0x36, 0x42, 0x15, 0xd5, 0x56, 0xd0, 0x70, 0x1a,
|
||||||
0x3a, 0xc3, 0xf4, 0xdb, 0x83, 0xf5, 0x62, 0xc6, 0x47, 0xd8, 0x54, 0x34, 0x5e, 0x8a, 0x52, 0x35,
|
0xcc, 0x12, 0x36, 0xf6, 0xea, 0xa3, 0x17, 0xd3, 0xaf, 0x00, 0x06, 0xed, 0x30, 0xb9, 0x86, 0x61,
|
||||||
0xa4, 0xd5, 0x12, 0x00, 0xd7, 0x80, 0xf1, 0x92, 0x83, 0x93, 0x8f, 0xac, 0xe2, 0x2d, 0xac, 0xaa,
|
0x2e, 0xd5, 0x21, 0x5b, 0x8b, 0x42, 0x6a, 0xd1, 0x2e, 0x80, 0xe3, 0x02, 0x75, 0x60, 0xe0, 0xec,
|
||||||
0xb6, 0xee, 0x34, 0x9f, 0x8d, 0xf2, 0x79, 0x41, 0x01, 0xeb, 0xa5, 0x81, 0x08, 0x12, 0x3f, 0x8b,
|
0x25, 0xba, 0xe4, 0x0c, 0xfa, 0x79, 0xb9, 0xa9, 0x34, 0xc6, 0xc6, 0xcc, 0x37, 0x84, 0xc2, 0xa0,
|
||||||
0xf3, 0xeb, 0x8a, 0x7b, 0x60, 0x77, 0x21, 0x1b, 0xab, 0xb4, 0x08, 0xff, 0xdd, 0x8e, 0x9d, 0xfa,
|
0x25, 0xa0, 0xbd, 0x69, 0x38, 0x4b, 0xd8, 0xb1, 0x25, 0x73, 0xc0, 0xe9, 0x8c, 0x17, 0x56, 0x68,
|
||||||
0xec, 0x44, 0xbc, 0x03, 0xe8, 0x06, 0xd7, 0xbc, 0x95, 0xa6, 0x15, 0x2b, 0xae, 0x1d, 0x33, 0x79,
|
0x1a, 0xfd, 0xc9, 0x4e, 0x9c, 0x7b, 0xef, 0x4c, 0x72, 0x0e, 0x50, 0x35, 0x8e, 0xbc, 0xe4, 0xa6,
|
||||||
0x93, 0xa6, 0x4d, 0xdf, 0x21, 0x74, 0x0e, 0x44, 0x08, 0x1b, 0x4d, 0xbd, 0xf0, 0x38, 0x88, 0x67,
|
0xa4, 0x7d, 0xc4, 0x4e, 0x50, 0x79, 0xe6, 0xa6, 0x24, 0x57, 0x90, 0x68, 0xa3, 0x32, 0x87, 0x6f,
|
||||||
0xdc, 0x81, 0x6f, 0x49, 0xf8, 0x4c, 0x7c, 0x4b, 0x78, 0x0f, 0xa0, 0xce, 0xaa, 0x9a, 0xac, 0x2c,
|
0xe8, 0x49, 0xf7, 0x17, 0x98, 0x51, 0x4f, 0xd5, 0x56, 0xb0, 0x58, 0xfb, 0xc2, 0xa4, 0x2f, 0x10,
|
||||||
0x4f, 0x4a, 0x04, 0x5c, 0xf5, 0x0f, 0x39, 0xde, 0x7c, 0xf2, 0xc3, 0x0b, 0x7e, 0xf8, 0x4f, 0x00,
|
0xb9, 0x74, 0x42, 0x20, 0x2a, 0xb4, 0xac, 0x69, 0x80, 0x50, 0x58, 0x93, 0x09, 0x84, 0x56, 0xd2,
|
||||||
0x00, 0x00, 0xff, 0xff, 0x78, 0x37, 0x3e, 0x6a, 0x7d, 0x01, 0x00, 0x00,
|
0x10, 0x95, 0xd0, 0x4a, 0x72, 0x01, 0x20, 0xf6, 0x22, 0xdf, 0x59, 0xbe, 0xde, 0x0a, 0xda, 0xc3,
|
||||||
|
0x67, 0x75, 0x94, 0xf4, 0x0d, 0x06, 0xed, 0x02, 0x8c, 0x73, 0x5f, 0x7a, 0x8c, 0x73, 0xda, 0x1d,
|
||||||
|
0x8c, 0x15, 0xb7, 0x65, 0x56, 0x73, 0xa5, 0xaa, 0xe6, 0xd3, 0xd0, 0x10, 0xd1, 0x4e, 0x3d, 0xda,
|
||||||
|
0x2b, 0xb7, 0xe5, 0xca, 0x3b, 0x6c, 0xa4, 0x7e, 0x1b, 0x93, 0xde, 0xc0, 0xb0, 0x63, 0xfe, 0x87,
|
||||||
|
0x74, 0x39, 0x7a, 0xc7, 0x33, 0xc9, 0xf0, 0x4c, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0x83, 0x82,
|
||||||
|
0xb0, 0xc3, 0x33, 0x02, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,10 @@ message Command {
|
||||||
// An optional hash of the input files to ensure the textproto files and the sbox rule reruns
|
// An optional hash of the input files to ensure the textproto files and the sbox rule reruns
|
||||||
// when the lists of inputs changes, even if the inputs are not on the command line.
|
// when the lists of inputs changes, even if the inputs are not on the command line.
|
||||||
optional string input_hash = 5;
|
optional string input_hash = 5;
|
||||||
|
|
||||||
|
// A list of files that will be copied before the sandboxed command, and whose contents should be
|
||||||
|
// copied as if they were listed in copy_before.
|
||||||
|
repeated RspFile rsp_files = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
|
// Copy describes a from-to pair of files to copy. The paths may be relative, the root that they
|
||||||
|
@ -58,4 +62,19 @@ message Copy {
|
||||||
|
|
||||||
// If true, make the file executable after copying it.
|
// If true, make the file executable after copying it.
|
||||||
optional bool executable = 3;
|
optional bool executable = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RspFile describes an rspfile that should be copied into the sandbox directory.
|
||||||
|
message RspFile {
|
||||||
|
// The path to the rsp file.
|
||||||
|
required string file = 1;
|
||||||
|
|
||||||
|
// A list of path mappings that should be applied to each file listed in the rsp file.
|
||||||
|
repeated PathMapping path_mappings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathMapping describes a mapping from a path outside the sandbox to the path inside the sandbox.
|
||||||
|
message PathMapping {
|
||||||
|
required string from = 1;
|
||||||
|
required string to = 2;
|
||||||
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ var (
|
||||||
&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
|
&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
|
||||||
ExecStrategy: "${config.RETurbineExecStrategy}",
|
ExecStrategy: "${config.RETurbineExecStrategy}",
|
||||||
Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
|
Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
|
||||||
RSPFile: "${out}.rsp",
|
RSPFiles: []string{"${out}.rsp"},
|
||||||
OutputFiles: []string{"$out.tmp"},
|
OutputFiles: []string{"$out.tmp"},
|
||||||
OutputDirectories: []string{"$outDir"},
|
OutputDirectories: []string{"$outDir"},
|
||||||
ToolchainInputs: []string{"${config.JavaCmd}"},
|
ToolchainInputs: []string{"${config.JavaCmd}"},
|
||||||
|
@ -167,7 +167,7 @@ var (
|
||||||
&remoteexec.REParams{
|
&remoteexec.REParams{
|
||||||
ExecStrategy: "${config.REJarExecStrategy}",
|
ExecStrategy: "${config.REJarExecStrategy}",
|
||||||
Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp"},
|
Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp"},
|
||||||
RSPFile: "${out}.rsp",
|
RSPFiles: []string{"${out}.rsp"},
|
||||||
OutputFiles: []string{"$out"},
|
OutputFiles: []string{"$out"},
|
||||||
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
|
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
|
||||||
}, []string{"jarArgs"}, nil)
|
}, []string{"jarArgs"}, nil)
|
||||||
|
@ -182,7 +182,7 @@ var (
|
||||||
&remoteexec.REParams{
|
&remoteexec.REParams{
|
||||||
ExecStrategy: "${config.REZipExecStrategy}",
|
ExecStrategy: "${config.REZipExecStrategy}",
|
||||||
Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
|
Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
|
||||||
RSPFile: "${out}.rsp",
|
RSPFiles: []string{"${out}.rsp"},
|
||||||
OutputFiles: []string{"$out"},
|
OutputFiles: []string{"$out"},
|
||||||
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
|
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
|
||||||
}, []string{"jarArgs"}, []string{"implicits"})
|
}, []string{"jarArgs"}, []string{"implicits"})
|
||||||
|
|
|
@ -1209,7 +1209,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
|
||||||
rule.Command().Text("mkdir -p").Flag(homeDir.String())
|
rule.Command().Text("mkdir -p").Flag(homeDir.String())
|
||||||
|
|
||||||
cmd := rule.Command()
|
cmd := rule.Command()
|
||||||
cmd.FlagWithArg("ANDROID_SDK_HOME=", homeDir.String())
|
cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
|
||||||
|
|
||||||
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
|
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
|
||||||
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
|
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
|
||||||
|
@ -1231,10 +1231,10 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
ExecStrategy: execStrategy,
|
ExecStrategy: execStrategy,
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
RSPFile: implicitsRsp.String(),
|
RSPFiles: []string{implicitsRsp.String()},
|
||||||
ToolchainInputs: []string{config.JavaCmd(ctx).String()},
|
ToolchainInputs: []string{config.JavaCmd(ctx).String()},
|
||||||
Platform: map[string]string{remoteexec.PoolKey: pool},
|
Platform: map[string]string{remoteexec.PoolKey: pool},
|
||||||
EnvironmentVariables: []string{"ANDROID_SDK_HOME"},
|
EnvironmentVariables: []string{"ANDROID_PREFS_ROOT"},
|
||||||
}).NoVarTemplate(ctx.Config().RBEWrapper()))
|
}).NoVarTemplate(ctx.Config().RBEWrapper()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -628,7 +628,7 @@ prebuilt_stubs_sources {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("empty/missing directory", func(t *testing.T) {
|
t.Run("empty/missing directory", func(t *testing.T) {
|
||||||
test(t, "empty-directory", []string{})
|
test(t, "empty-directory", nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("non-empty set of sources", func(t *testing.T) {
|
t.Run("non-empty set of sources", func(t *testing.T) {
|
||||||
|
|
85
java/lint.go
85
java/lint.go
|
@ -182,11 +182,6 @@ type lintPaths struct {
|
||||||
cacheDir android.WritablePath
|
cacheDir android.WritablePath
|
||||||
homeDir android.WritablePath
|
homeDir android.WritablePath
|
||||||
srcjarDir android.WritablePath
|
srcjarDir android.WritablePath
|
||||||
|
|
||||||
deps android.Paths
|
|
||||||
|
|
||||||
remoteInputs android.Paths
|
|
||||||
remoteRSPInputs android.Paths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func lintRBEExecStrategy(ctx android.ModuleContext) string {
|
func lintRBEExecStrategy(ctx android.ModuleContext) string {
|
||||||
|
@ -194,39 +189,6 @@ func lintRBEExecStrategy(ctx android.ModuleContext) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
|
func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
|
||||||
var deps android.Paths
|
|
||||||
var remoteInputs android.Paths
|
|
||||||
var remoteRSPInputs android.Paths
|
|
||||||
|
|
||||||
// Paths passed to trackInputDependency will be added as dependencies of the rule that runs
|
|
||||||
// lint and passed as inputs to the remote execution proxy.
|
|
||||||
trackInputDependency := func(paths ...android.Path) {
|
|
||||||
deps = append(deps, paths...)
|
|
||||||
remoteInputs = append(remoteInputs, paths...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paths passed to trackRSPDependency will be added as dependencies of the rule that runs
|
|
||||||
// lint, but the RSP file will be used by the remote execution proxy to find the files so that
|
|
||||||
// it doesn't overflow command line limits.
|
|
||||||
trackRSPDependency := func(paths android.Paths, rsp android.Path) {
|
|
||||||
deps = append(deps, paths...)
|
|
||||||
remoteRSPInputs = append(remoteRSPInputs, rsp)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourcesList android.WritablePath
|
|
||||||
if len(l.resources) > 0 {
|
|
||||||
// The list of resources may be too long to put on the command line, but
|
|
||||||
// we can't use the rsp file because it is already being used for srcs.
|
|
||||||
// Insert a second rule to write out the list of resources to a file.
|
|
||||||
resourcesList = android.PathForModuleOut(ctx, "resources.list")
|
|
||||||
resListRule := android.NewRuleBuilder(pctx, ctx)
|
|
||||||
resListRule.Command().Text("cp").
|
|
||||||
FlagWithRspFileInputList("", resourcesList.ReplaceExtension(ctx, "rsp"), l.resources).
|
|
||||||
Output(resourcesList)
|
|
||||||
resListRule.Build("lint_resources_list", "lint resources list")
|
|
||||||
trackRSPDependency(l.resources, resourcesList)
|
|
||||||
}
|
|
||||||
|
|
||||||
projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
|
projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
|
||||||
// Lint looks for a lint.xml file next to the project.xml file, give it one.
|
// Lint looks for a lint.xml file next to the project.xml file, give it one.
|
||||||
configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
|
configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
|
||||||
|
@ -235,20 +197,6 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru
|
||||||
|
|
||||||
srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
|
srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
|
||||||
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
|
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
|
||||||
// TODO(ccross): this is a little fishy. The files extracted from the srcjars are referenced
|
|
||||||
// by the project.xml and used by the later lint rule, but the lint rule depends on the srcjars,
|
|
||||||
// not the extracted files.
|
|
||||||
trackRSPDependency(l.srcJars, srcJarList)
|
|
||||||
|
|
||||||
// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
|
|
||||||
// lint separately.
|
|
||||||
srcsList := android.PathForModuleOut(ctx, "lint", "srcs.list")
|
|
||||||
srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
|
|
||||||
rule.Command().Text("cp").
|
|
||||||
FlagWithRspFileInputList("", srcsListRsp, l.srcs).
|
|
||||||
Output(srcsList)
|
|
||||||
trackRSPDependency(l.srcs, srcsList)
|
|
||||||
rule.Temporary(srcsList)
|
|
||||||
|
|
||||||
cmd := rule.Command().
|
cmd := rule.Command().
|
||||||
BuiltTool("lint-project-xml").
|
BuiltTool("lint-project-xml").
|
||||||
|
@ -263,32 +211,31 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru
|
||||||
cmd.Flag("--test")
|
cmd.Flag("--test")
|
||||||
}
|
}
|
||||||
if l.manifest != nil {
|
if l.manifest != nil {
|
||||||
cmd.FlagWithArg("--manifest ", cmd.PathForInput(l.manifest))
|
cmd.FlagWithInput("--manifest ", l.manifest)
|
||||||
trackInputDependency(l.manifest)
|
|
||||||
}
|
}
|
||||||
if l.mergedManifest != nil {
|
if l.mergedManifest != nil {
|
||||||
cmd.FlagWithArg("--merged_manifest ", cmd.PathForInput(l.mergedManifest))
|
cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
|
||||||
trackInputDependency(l.mergedManifest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.FlagWithInput("--srcs ", srcsList)
|
// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
|
||||||
|
// lint separately.
|
||||||
|
srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
|
||||||
|
cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
|
||||||
|
|
||||||
cmd.FlagWithInput("--generated_srcs ", srcJarList)
|
cmd.FlagWithInput("--generated_srcs ", srcJarList)
|
||||||
|
|
||||||
if resourcesList != nil {
|
if len(l.resources) > 0 {
|
||||||
cmd.FlagWithInput("--resources ", resourcesList)
|
resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
|
||||||
|
cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.classes != nil {
|
if l.classes != nil {
|
||||||
cmd.FlagWithArg("--classes ", cmd.PathForInput(l.classes))
|
cmd.FlagWithInput("--classes ", l.classes)
|
||||||
trackInputDependency(l.classes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.FlagForEachArg("--classpath ", cmd.PathsForInputs(l.classpath))
|
cmd.FlagForEachInput("--classpath ", l.classpath)
|
||||||
trackInputDependency(l.classpath...)
|
|
||||||
|
|
||||||
cmd.FlagForEachArg("--extra_checks_jar ", cmd.PathsForInputs(l.extraLintCheckJars))
|
cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
|
||||||
trackInputDependency(l.extraLintCheckJars...)
|
|
||||||
|
|
||||||
cmd.FlagWithArg("--root_dir ", "$PWD")
|
cmd.FlagWithArg("--root_dir ", "$PWD")
|
||||||
|
|
||||||
|
@ -309,11 +256,6 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru
|
||||||
configXML: configXMLPath,
|
configXML: configXMLPath,
|
||||||
cacheDir: cacheDir,
|
cacheDir: cacheDir,
|
||||||
homeDir: homeDir,
|
homeDir: homeDir,
|
||||||
|
|
||||||
deps: deps,
|
|
||||||
|
|
||||||
remoteInputs: remoteInputs,
|
|
||||||
remoteRSPInputs: remoteRSPInputs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -424,8 +366,7 @@ func (l *linter) lint(ctx android.ModuleContext) {
|
||||||
Flag("--exitcode").
|
Flag("--exitcode").
|
||||||
Flags(l.properties.Lint.Flags).
|
Flags(l.properties.Lint.Flags).
|
||||||
Implicit(annotationsZipPath).
|
Implicit(annotationsZipPath).
|
||||||
Implicit(apiVersionsXMLPath).
|
Implicit(apiVersionsXMLPath)
|
||||||
Implicits(lintPaths.deps)
|
|
||||||
|
|
||||||
rule.Temporary(lintPaths.projectXML)
|
rule.Temporary(lintPaths.projectXML)
|
||||||
rule.Temporary(lintPaths.configXML)
|
rule.Temporary(lintPaths.configXML)
|
||||||
|
|
|
@ -64,9 +64,8 @@ type REParams struct {
|
||||||
ExecStrategy string
|
ExecStrategy string
|
||||||
// Inputs is a list of input paths or ninja variables.
|
// Inputs is a list of input paths or ninja variables.
|
||||||
Inputs []string
|
Inputs []string
|
||||||
// RSPFile is the name of the ninja variable used by the rule as a placeholder for an rsp
|
// RSPFiles is the name of the files used by the rule as a placeholder for an rsp input.
|
||||||
// input.
|
RSPFiles []string
|
||||||
RSPFile string
|
|
||||||
// OutputFiles is a list of output file paths or ninja variables as placeholders for rule
|
// OutputFiles is a list of output file paths or ninja variables as placeholders for rule
|
||||||
// outputs.
|
// outputs.
|
||||||
OutputFiles []string
|
OutputFiles []string
|
||||||
|
@ -134,8 +133,8 @@ func (r *REParams) wrapperArgs() string {
|
||||||
args += " --inputs=" + strings.Join(r.Inputs, ",")
|
args += " --inputs=" + strings.Join(r.Inputs, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.RSPFile != "" {
|
if len(r.RSPFiles) > 0 {
|
||||||
args += " --input_list_paths=" + r.RSPFile
|
args += " --input_list_paths=" + strings.Join(r.RSPFiles, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(r.OutputFiles) > 0 {
|
if len(r.OutputFiles) > 0 {
|
||||||
|
|
|
@ -45,14 +45,14 @@ func TestTemplate(t *testing.T) {
|
||||||
Inputs: []string{"$in"},
|
Inputs: []string{"$in"},
|
||||||
OutputFiles: []string{"$out"},
|
OutputFiles: []string{"$out"},
|
||||||
ExecStrategy: "remote",
|
ExecStrategy: "remote",
|
||||||
RSPFile: "$out.rsp",
|
RSPFiles: []string{"$out.rsp", "out2.rsp"},
|
||||||
ToolchainInputs: []string{"clang++"},
|
ToolchainInputs: []string{"clang++"},
|
||||||
Platform: map[string]string{
|
Platform: map[string]string{
|
||||||
ContainerImageKey: DefaultImage,
|
ContainerImageKey: DefaultImage,
|
||||||
PoolKey: "default",
|
PoolKey: "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: fmt.Sprintf("${android.RBEWrapper} --labels=compiler=clang,lang=cpp,type=compile --platform=\"Pool=default,container-image=%s\" --exec_strategy=remote --inputs=$in --input_list_paths=$out.rsp --output_files=$out --toolchain_inputs=clang++ -- ", DefaultImage),
|
want: fmt.Sprintf("${android.RBEWrapper} --labels=compiler=clang,lang=cpp,type=compile --platform=\"Pool=default,container-image=%s\" --exec_strategy=remote --inputs=$in --input_list_paths=$out.rsp,out2.rsp --output_files=$out --toolchain_inputs=clang++ -- ", DefaultImage),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package {
|
||||||
|
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap_go_package {
|
||||||
|
name: "soong-response",
|
||||||
|
pkgPath: "android/soong/response",
|
||||||
|
deps: [
|
||||||
|
],
|
||||||
|
srcs: [
|
||||||
|
"response.go",
|
||||||
|
],
|
||||||
|
testSrcs: [
|
||||||
|
"response_test.go",
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright 2021 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 response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
const noQuote = '\x00'
|
||||||
|
|
||||||
|
// ReadRspFile reads a file in Ninja's response file format and returns its contents.
|
||||||
|
func ReadRspFile(r io.Reader) ([]string, error) {
|
||||||
|
var files []string
|
||||||
|
var file []byte
|
||||||
|
|
||||||
|
buf, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isEscaping := false
|
||||||
|
quotingStart := byte(noQuote)
|
||||||
|
for _, c := range buf {
|
||||||
|
switch {
|
||||||
|
case isEscaping:
|
||||||
|
if quotingStart == '"' {
|
||||||
|
if !(c == '"' || c == '\\') {
|
||||||
|
// '\"' or '\\' will be escaped under double quoting.
|
||||||
|
file = append(file, '\\')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file = append(file, c)
|
||||||
|
isEscaping = false
|
||||||
|
case c == '\\' && quotingStart != '\'':
|
||||||
|
isEscaping = true
|
||||||
|
case quotingStart == noQuote && (c == '\'' || c == '"'):
|
||||||
|
quotingStart = c
|
||||||
|
case quotingStart != noQuote && c == quotingStart:
|
||||||
|
quotingStart = noQuote
|
||||||
|
case quotingStart == noQuote && unicode.IsSpace(rune(c)):
|
||||||
|
// Current character is a space outside quotes
|
||||||
|
if len(file) != 0 {
|
||||||
|
files = append(files, string(file))
|
||||||
|
}
|
||||||
|
file = file[:0]
|
||||||
|
default:
|
||||||
|
file = append(file, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(file) != 0 {
|
||||||
|
files = append(files, string(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rspUnsafeChar(r rune) bool {
|
||||||
|
switch {
|
||||||
|
case 'A' <= r && r <= 'Z',
|
||||||
|
'a' <= r && r <= 'z',
|
||||||
|
'0' <= r && r <= '9',
|
||||||
|
r == '_',
|
||||||
|
r == '+',
|
||||||
|
r == '-',
|
||||||
|
r == '.',
|
||||||
|
r == '/':
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rspEscaper = strings.NewReplacer(`'`, `'\''`)
|
||||||
|
|
||||||
|
// WriteRspFile writes a list of files to a file in Ninja's response file format.
|
||||||
|
func WriteRspFile(w io.Writer, files []string) error {
|
||||||
|
for i, f := range files {
|
||||||
|
if i != 0 {
|
||||||
|
_, err := io.WriteString(w, " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.IndexFunc(f, rspUnsafeChar) != -1 {
|
||||||
|
f = `'` + rspEscaper.Replace(f) + `'`
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := io.WriteString(w, f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Copyright 2021 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 response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadRspFile(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name, in string
|
||||||
|
out []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single quoting test case 1",
|
||||||
|
in: `./cmd '"'-C`,
|
||||||
|
out: []string{"./cmd", `"-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single quoting test case 2",
|
||||||
|
in: `./cmd '-C`,
|
||||||
|
out: []string{"./cmd", `-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single quoting test case 3",
|
||||||
|
in: `./cmd '\"'-C`,
|
||||||
|
out: []string{"./cmd", `\"-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single quoting test case 4",
|
||||||
|
in: `./cmd '\\'-C`,
|
||||||
|
out: []string{"./cmd", `\\-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "none quoting test case 1",
|
||||||
|
in: `./cmd \'-C`,
|
||||||
|
out: []string{"./cmd", `'-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "none quoting test case 2",
|
||||||
|
in: `./cmd \\-C`,
|
||||||
|
out: []string{"./cmd", `\-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "none quoting test case 3",
|
||||||
|
in: `./cmd \"-C`,
|
||||||
|
out: []string{"./cmd", `"-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double quoting test case 1",
|
||||||
|
in: `./cmd "'"-C`,
|
||||||
|
out: []string{"./cmd", `'-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double quoting test case 2",
|
||||||
|
in: `./cmd "\\"-C`,
|
||||||
|
out: []string{"./cmd", `\-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double quoting test case 3",
|
||||||
|
in: `./cmd "\""-C`,
|
||||||
|
out: []string{"./cmd", `"-C`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ninja rsp file",
|
||||||
|
in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'",
|
||||||
|
out: []string{"a", "b", "@", "foo'bar", `foo"bar`},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
got, err := ReadRspFile(bytes.NewBuffer([]byte(testCase.in)))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %q", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, testCase.out) {
|
||||||
|
t.Errorf("expected %q got %q", testCase.out, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteRspFile(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
in []string
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ninja rsp file",
|
||||||
|
in: []string{"a", "b", "@", "foo'bar", `foo"bar`},
|
||||||
|
out: "a b '@' 'foo'\\''bar' 'foo\"bar'",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := WriteRspFile(buf, testCase.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %q", err)
|
||||||
|
}
|
||||||
|
if buf.String() != testCase.out {
|
||||||
|
t.Errorf("expected %q got %q", testCase.out, buf.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ bootstrap_go_package {
|
||||||
"android-archive-zip",
|
"android-archive-zip",
|
||||||
"blueprint-pathtools",
|
"blueprint-pathtools",
|
||||||
"soong-jar",
|
"soong-jar",
|
||||||
|
"soong-response",
|
||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"zip.go",
|
"zip.go",
|
||||||
|
|
|
@ -24,7 +24,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
@ -32,6 +31,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"android/soong/response"
|
||||||
"android/soong/zip"
|
"android/soong/zip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -125,12 +125,18 @@ func main() {
|
||||||
var expandedArgs []string
|
var expandedArgs []string
|
||||||
for _, arg := range os.Args {
|
for _, arg := range os.Args {
|
||||||
if strings.HasPrefix(arg, "@") {
|
if strings.HasPrefix(arg, "@") {
|
||||||
bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@"))
|
f, err := os.Open(strings.TrimPrefix(arg, "@"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
respArgs, err := response.ReadRspFile(f)
|
||||||
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
respArgs := zip.ReadRespFile(bytes)
|
|
||||||
expandedArgs = append(expandedArgs, respArgs...)
|
expandedArgs = append(expandedArgs, respArgs...)
|
||||||
} else {
|
} else {
|
||||||
expandedArgs = append(expandedArgs, arg)
|
expandedArgs = append(expandedArgs, arg)
|
||||||
|
|
52
zip/zip.go
52
zip/zip.go
|
@ -29,7 +29,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
"android/soong/response"
|
||||||
|
|
||||||
"github.com/google/blueprint/pathtools"
|
"github.com/google/blueprint/pathtools"
|
||||||
|
|
||||||
|
@ -164,14 +165,12 @@ func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
list, err := ioutil.ReadAll(f)
|
arg := b.state
|
||||||
|
arg.SourceFiles, err = response.ReadRspFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.err = err
|
b.err = err
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
arg := b.state
|
|
||||||
arg.SourceFiles = ReadRespFile(list)
|
|
||||||
for i := range arg.SourceFiles {
|
for i := range arg.SourceFiles {
|
||||||
arg.SourceFiles[i] = pathtools.MatchEscape(arg.SourceFiles[i])
|
arg.SourceFiles[i] = pathtools.MatchEscape(arg.SourceFiles[i])
|
||||||
}
|
}
|
||||||
|
@ -253,49 +252,6 @@ type ZipArgs struct {
|
||||||
Filesystem pathtools.FileSystem
|
Filesystem pathtools.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
const NOQUOTE = '\x00'
|
|
||||||
|
|
||||||
func ReadRespFile(bytes []byte) []string {
|
|
||||||
var args []string
|
|
||||||
var arg []rune
|
|
||||||
|
|
||||||
isEscaping := false
|
|
||||||
quotingStart := NOQUOTE
|
|
||||||
for _, c := range string(bytes) {
|
|
||||||
switch {
|
|
||||||
case isEscaping:
|
|
||||||
if quotingStart == '"' {
|
|
||||||
if !(c == '"' || c == '\\') {
|
|
||||||
// '\"' or '\\' will be escaped under double quoting.
|
|
||||||
arg = append(arg, '\\')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arg = append(arg, c)
|
|
||||||
isEscaping = false
|
|
||||||
case c == '\\' && quotingStart != '\'':
|
|
||||||
isEscaping = true
|
|
||||||
case quotingStart == NOQUOTE && (c == '\'' || c == '"'):
|
|
||||||
quotingStart = c
|
|
||||||
case quotingStart != NOQUOTE && c == quotingStart:
|
|
||||||
quotingStart = NOQUOTE
|
|
||||||
case quotingStart == NOQUOTE && unicode.IsSpace(c):
|
|
||||||
// Current character is a space outside quotes
|
|
||||||
if len(arg) != 0 {
|
|
||||||
args = append(args, string(arg))
|
|
||||||
}
|
|
||||||
arg = arg[:0]
|
|
||||||
default:
|
|
||||||
arg = append(arg, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg) != 0 {
|
|
||||||
args = append(args, string(arg))
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
func zipTo(args ZipArgs, w io.Writer) error {
|
func zipTo(args ZipArgs, w io.Writer) error {
|
||||||
if args.EmulateJar {
|
if args.EmulateJar {
|
||||||
args.AddDirectoryEntriesToZip = true
|
args.AddDirectoryEntriesToZip = true
|
||||||
|
|
|
@ -535,78 +535,6 @@ func TestZip(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadRespFile(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name, in string
|
|
||||||
out []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "single quoting test case 1",
|
|
||||||
in: `./cmd '"'-C`,
|
|
||||||
out: []string{"./cmd", `"-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single quoting test case 2",
|
|
||||||
in: `./cmd '-C`,
|
|
||||||
out: []string{"./cmd", `-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single quoting test case 3",
|
|
||||||
in: `./cmd '\"'-C`,
|
|
||||||
out: []string{"./cmd", `\"-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single quoting test case 4",
|
|
||||||
in: `./cmd '\\'-C`,
|
|
||||||
out: []string{"./cmd", `\\-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "none quoting test case 1",
|
|
||||||
in: `./cmd \'-C`,
|
|
||||||
out: []string{"./cmd", `'-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "none quoting test case 2",
|
|
||||||
in: `./cmd \\-C`,
|
|
||||||
out: []string{"./cmd", `\-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "none quoting test case 3",
|
|
||||||
in: `./cmd \"-C`,
|
|
||||||
out: []string{"./cmd", `"-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "double quoting test case 1",
|
|
||||||
in: `./cmd "'"-C`,
|
|
||||||
out: []string{"./cmd", `'-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "double quoting test case 2",
|
|
||||||
in: `./cmd "\\"-C`,
|
|
||||||
out: []string{"./cmd", `\-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "double quoting test case 3",
|
|
||||||
in: `./cmd "\""-C`,
|
|
||||||
out: []string{"./cmd", `"-C`},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ninja rsp file",
|
|
||||||
in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'",
|
|
||||||
out: []string{"a", "b", "@", "foo'bar", `foo"bar`},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
|
||||||
got := ReadRespFile([]byte(testCase.in))
|
|
||||||
if !reflect.DeepEqual(got, testCase.out) {
|
|
||||||
t.Errorf("expected %q got %q", testCase.out, got)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSrcJar(t *testing.T) {
|
func TestSrcJar(t *testing.T) {
|
||||||
mockFs := pathtools.MockFs(map[string][]byte{
|
mockFs := pathtools.MockFs(map[string][]byte{
|
||||||
"wrong_package.java": []byte("package foo;"),
|
"wrong_package.java": []byte("package foo;"),
|
||||||
|
|
Loading…
Reference in New Issue