Merge "Add Respfile support for soong_zip." am: 3bb5f2f2fa
am: afe289114a
Change-Id: I38229a6aaaad1b8394927e6da31741f4e2f95476
This commit is contained in:
commit
ba85cb38f3
5 changed files with 175 additions and 22 deletions
|
@ -123,8 +123,10 @@ var (
|
|||
|
||||
jar = pctx.AndroidStaticRule("jar",
|
||||
blueprint.RuleParams{
|
||||
Command: `${config.SoongZipCmd} -jar -o $out $jarArgs`,
|
||||
Command: `${config.SoongZipCmd} -jar -o $out @$out.rsp`,
|
||||
CommandDeps: []string{"${config.SoongZipCmd}"},
|
||||
Rspfile: "$out.rsp",
|
||||
RspfileContent: "$jarArgs",
|
||||
},
|
||||
"jarArgs")
|
||||
|
||||
|
|
|
@ -26,5 +26,8 @@ bootstrap_go_package {
|
|||
"zip.go",
|
||||
"rate_limit.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"zip_test.go",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -120,30 +120,12 @@ func (d *dir) Set(s string) error {
|
|||
}
|
||||
|
||||
var (
|
||||
out = flag.String("o", "", "file to write zip file to")
|
||||
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")
|
||||
rootPrefix, relativeRoot *string
|
||||
|
||||
fArgs zip.FileArgs
|
||||
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() {
|
||||
fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
|
||||
flag.PrintDefaults()
|
||||
|
@ -151,7 +133,42 @@ func usage() {
|
|||
}
|
||||
|
||||
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{
|
||||
FileArgs: fArgs,
|
||||
|
|
44
zip/zip.go
44
zip/zip.go
|
@ -31,6 +31,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/google/blueprint/pathtools"
|
||||
|
||||
|
@ -132,6 +133,49 @@ type ZipArgs struct {
|
|||
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) {
|
||||
if 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue