diff --git a/zip/cmd/main.go b/zip/cmd/main.go index dfd56dc62..e379b07f2 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -15,10 +15,8 @@ package main import ( - "bytes" "flag" "fmt" - "io" "io/ioutil" "os" "runtime" @@ -28,16 +26,6 @@ import ( "android/soong/zip" ) -type byteReaderCloser struct { - *bytes.Reader - io.Closer -} - -type pathMapping struct { - dest, src string - zipMethod uint16 -} - type uniqueSet map[string]bool func (u *uniqueSet) String() string { @@ -56,106 +44,67 @@ func (u *uniqueSet) Set(s string) error { type file struct{} +func (file) String() string { return `""` } + +func (file) Set(s string) error { + fileArgsBuilder.File(s) + return nil +} + type listFiles struct{} +func (listFiles) String() string { return `""` } + +func (listFiles) Set(s string) error { + fileArgsBuilder.List(s) + return nil +} + type dir struct{} -func (f *file) String() string { - return `""` -} - -func (f *file) Set(s string) error { - if relativeRoot == "" && !junkPaths { - return fmt.Errorf("must pass -C or -j before -f") - } - - fArgs = append(fArgs, zip.FileArg{ - PathPrefixInZip: *rootPrefix, - SourcePrefixToStrip: relativeRoot, - JunkPaths: junkPaths, - SourceFiles: []string{s}, - }) +func (dir) String() string { return `""` } +func (dir) Set(s string) error { + fileArgsBuilder.Dir(s) return nil } -func (l *listFiles) String() string { - return `""` -} +type relativeRoot struct{} -func (l *listFiles) Set(s string) error { - if relativeRoot == "" && !junkPaths { - return fmt.Errorf("must pass -C or -j before -l") - } - - list, err := ioutil.ReadFile(s) - if err != nil { - return err - } - - fArgs = append(fArgs, zip.FileArg{ - PathPrefixInZip: *rootPrefix, - SourcePrefixToStrip: relativeRoot, - JunkPaths: junkPaths, - SourceFiles: strings.Split(string(list), "\n"), - }) +func (relativeRoot) String() string { return "" } +func (relativeRoot) Set(s string) error { + fileArgsBuilder.SourcePrefixToStrip(s) return nil } -func (d *dir) String() string { - return `""` -} +type junkPaths struct{} -func (d *dir) Set(s string) error { - if relativeRoot == "" && !junkPaths { - return fmt.Errorf("must pass -C or -j before -D") - } +func (junkPaths) IsBoolFlag() bool { return true } +func (junkPaths) String() string { return "" } - fArgs = append(fArgs, zip.FileArg{ - PathPrefixInZip: *rootPrefix, - SourcePrefixToStrip: relativeRoot, - JunkPaths: junkPaths, - GlobDir: s, - }) - - return nil -} - -type relativeRootImpl struct{} - -func (*relativeRootImpl) String() string { return relativeRoot } - -func (*relativeRootImpl) Set(s string) error { - relativeRoot = s - junkPaths = false - return nil -} - -type junkPathsImpl struct{} - -func (*junkPathsImpl) IsBoolFlag() bool { return true } - -func (*junkPathsImpl) String() string { return relativeRoot } - -func (*junkPathsImpl) Set(s string) error { - var err error - junkPaths, err = strconv.ParseBool(s) - relativeRoot = "" +func (junkPaths) Set(s string) error { + v, err := strconv.ParseBool(s) + fileArgsBuilder.JunkPaths(v) return err } -var ( - rootPrefix *string - relativeRoot string - junkPaths bool +type rootPrefix struct{} - fArgs zip.FileArgs +func (rootPrefix) String() string { return "" } + +func (rootPrefix) Set(s string) error { + fileArgsBuilder.PathPrefixInZip(s) + return nil +} + +var ( + fileArgsBuilder = zip.NewFileArgsBuilder() nonDeflatedFiles = make(uniqueSet) ) func usage() { - fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n") + fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n") flag.PrintDefaults() os.Exit(2) } @@ -177,11 +126,11 @@ func main() { } flags := flag.NewFlagSet("flags", flag.ExitOnError) + flags.Usage = usage 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") 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") @@ -190,17 +139,28 @@ func main() { cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") traceFile := flags.String("trace", "", "write trace to file") + flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") 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.Var(&relativeRootImpl{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments") - flags.Var(&junkPathsImpl{}, "j", "junk paths, zip files without directory names") + flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments") + flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names") flags.Parse(expandedArgs[1:]) + if flags.NArg() > 0 { + fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " ")) + flags.Usage() + } + + if fileArgsBuilder.Error() != nil { + fmt.Fprintln(os.Stderr, fileArgsBuilder.Error()) + os.Exit(1) + } + err := zip.Run(zip.ZipArgs{ - FileArgs: fArgs, + FileArgs: fileArgsBuilder.FileArgs(), OutputFilePath: *out, CpuProfileFilePath: *cpuProfile, TraceFilePath: *traceFile, diff --git a/zip/zip.go b/zip/zip.go index 6b36e102c..80173f3d4 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -68,22 +68,6 @@ type pathMapping struct { zipMethod uint16 } -type uniqueSet map[string]bool - -func (u *uniqueSet) String() string { - return `""` -} - -func (u *uniqueSet) Set(s string) error { - if _, found := (*u)[s]; found { - return fmt.Errorf("File %q was specified twice as a file to not deflate", s) - } else { - (*u)[s] = true - } - - return nil -} - type FileArg struct { PathPrefixInZip, SourcePrefixToStrip string SourceFiles []string @@ -91,7 +75,96 @@ type FileArg struct { GlobDir string } -type FileArgs []FileArg +type FileArgsBuilder struct { + state FileArg + err error + fs pathtools.FileSystem + + fileArgs []FileArg +} + +func NewFileArgsBuilder() *FileArgsBuilder { + return &FileArgsBuilder{ + fs: pathtools.OsFs, + } +} + +func (b *FileArgsBuilder) JunkPaths(v bool) *FileArgsBuilder { + b.state.JunkPaths = v + b.state.SourcePrefixToStrip = "" + return b +} + +func (b *FileArgsBuilder) SourcePrefixToStrip(prefixToStrip string) *FileArgsBuilder { + b.state.JunkPaths = false + b.state.SourcePrefixToStrip = prefixToStrip + return b +} + +func (b *FileArgsBuilder) PathPrefixInZip(rootPrefix string) *FileArgsBuilder { + b.state.PathPrefixInZip = rootPrefix + return b +} + +func (b *FileArgsBuilder) File(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + arg := b.state + arg.SourceFiles = []string{name} + b.fileArgs = append(b.fileArgs, arg) + return b +} + +func (b *FileArgsBuilder) Dir(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + arg := b.state + arg.GlobDir = name + b.fileArgs = append(b.fileArgs, arg) + return b +} + +func (b *FileArgsBuilder) List(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + f, err := b.fs.Open(name) + if err != nil { + b.err = err + return b + } + defer f.Close() + + list, err := ioutil.ReadAll(f) + if err != nil { + b.err = err + return b + } + + arg := b.state + arg.SourceFiles = strings.Split(string(list), "\n") + b.fileArgs = append(b.fileArgs, arg) + return b +} + +func (b *FileArgsBuilder) Error() error { + if b == nil { + return nil + } + return b.err +} + +func (b *FileArgsBuilder) FileArgs() []FileArg { + if b == nil { + return nil + } + return b.fileArgs +} type ZipWriter struct { time time.Time @@ -121,7 +194,7 @@ type zipEntry struct { } type ZipArgs struct { - FileArgs FileArgs + FileArgs []FileArg OutputFilePath string CpuProfileFilePath string TraceFilePath string