Merge "Add Respfile support for soong_zip."
am: 3bb5f2f2fa
Change-Id: Ifc59ddbd16a5cf82f7750f9927c2d0f24627fc81
This commit is contained in:
@@ -123,8 +123,10 @@ var (
|
|||||||
|
|
||||||
jar = pctx.AndroidStaticRule("jar",
|
jar = pctx.AndroidStaticRule("jar",
|
||||||
blueprint.RuleParams{
|
blueprint.RuleParams{
|
||||||
Command: `${config.SoongZipCmd} -jar -o $out $jarArgs`,
|
Command: `${config.SoongZipCmd} -jar -o $out @$out.rsp`,
|
||||||
CommandDeps: []string{"${config.SoongZipCmd}"},
|
CommandDeps: []string{"${config.SoongZipCmd}"},
|
||||||
|
Rspfile: "$out.rsp",
|
||||||
|
RspfileContent: "$jarArgs",
|
||||||
},
|
},
|
||||||
"jarArgs")
|
"jarArgs")
|
||||||
|
|
||||||
|
@@ -26,5 +26,8 @@ bootstrap_go_package {
|
|||||||
"zip.go",
|
"zip.go",
|
||||||
"rate_limit.go",
|
"rate_limit.go",
|
||||||
],
|
],
|
||||||
|
testSrcs: [
|
||||||
|
"zip_test.go",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -120,30 +120,12 @@ func (d *dir) Set(s string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
out = flag.String("o", "", "file to write zip file to")
|
rootPrefix, relativeRoot *string
|
||||||
manifest = flag.String("m", "", "input jar manifest file name")
|
|
||||||
directories = flag.Bool("d", false, "include directories in zip")
|
|
||||||
rootPrefix = flag.String("P", "", "path prefix within the zip at which to place files")
|
|
||||||
relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
|
|
||||||
parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
|
|
||||||
compLevel = flag.Int("L", 5, "deflate compression level (0-9)")
|
|
||||||
emulateJar = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
|
|
||||||
writeIfChanged = flag.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
|
|
||||||
|
|
||||||
fArgs zip.FileArgs
|
fArgs zip.FileArgs
|
||||||
nonDeflatedFiles = make(uniqueSet)
|
nonDeflatedFiles = make(uniqueSet)
|
||||||
|
|
||||||
cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
|
|
||||||
traceFile = flag.String("trace", "", "write trace to file")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.Var(&listFiles{}, "l", "file containing list of .class files")
|
|
||||||
flag.Var(&dir{}, "D", "directory to include in zip")
|
|
||||||
flag.Var(&file{}, "f", "file to include in zip")
|
|
||||||
flag.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
|
|
||||||
}
|
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
|
fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
@@ -151,7 +133,42 @@ func usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
var expandedArgs []string
|
||||||
|
for _, arg := range os.Args {
|
||||||
|
if strings.HasPrefix(arg, "@") {
|
||||||
|
bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
respArgs := zip.ReadRespFile(bytes)
|
||||||
|
expandedArgs = append(expandedArgs, respArgs...)
|
||||||
|
} else {
|
||||||
|
expandedArgs = append(expandedArgs, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := flag.NewFlagSet("flags", flag.ExitOnError)
|
||||||
|
|
||||||
|
out := flags.String("o", "", "file to write zip file to")
|
||||||
|
manifest := flags.String("m", "", "input jar manifest file name")
|
||||||
|
directories := flags.Bool("d", false, "include directories in zip")
|
||||||
|
rootPrefix = flags.String("P", "", "path prefix within the zip at which to place files")
|
||||||
|
relativeRoot = flags.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
|
||||||
|
parallelJobs := flags.Int("j", runtime.NumCPU(), "number of parallel threads to use")
|
||||||
|
compLevel := flags.Int("L", 5, "deflate compression level (0-9)")
|
||||||
|
emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
|
||||||
|
writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
|
||||||
|
|
||||||
|
cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file")
|
||||||
|
traceFile := flags.String("trace", "", "write trace to file")
|
||||||
|
|
||||||
|
flags.Var(&listFiles{}, "l", "file containing list of .class files")
|
||||||
|
flags.Var(&dir{}, "D", "directory to include in zip")
|
||||||
|
flags.Var(&file{}, "f", "file to include in zip")
|
||||||
|
flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
|
||||||
|
|
||||||
|
flags.Parse(expandedArgs[1:])
|
||||||
|
|
||||||
err := zip.Run(zip.ZipArgs{
|
err := zip.Run(zip.ZipArgs{
|
||||||
FileArgs: fArgs,
|
FileArgs: fArgs,
|
||||||
|
44
zip/zip.go
44
zip/zip.go
@@ -31,6 +31,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"github.com/google/blueprint/pathtools"
|
"github.com/google/blueprint/pathtools"
|
||||||
|
|
||||||
@@ -132,6 +133,49 @@ type ZipArgs struct {
|
|||||||
WriteIfChanged bool
|
WriteIfChanged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 Run(args ZipArgs) (err error) {
|
func Run(args ZipArgs) (err error) {
|
||||||
if args.CpuProfileFilePath != "" {
|
if args.CpuProfileFilePath != "" {
|
||||||
f, err := os.Create(args.CpuProfileFilePath)
|
f, err := os.Create(args.CpuProfileFilePath)
|
||||||
|
87
zip/zip_test.go
Normal file
87
zip/zip_test.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2018 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 zip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
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`},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user