split soong_zip into a library and a binary

to make it faster/easier to invoke from other Go programs
(such as multiproduct_kati)

Bug: 67478260
Test: m -j
Change-Id: Idd2671a44290550197c88f53dd11a6dd39c85cc5
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
new file mode 100644
index 0000000..348728c
--- /dev/null
+++ b/zip/cmd/main.go
@@ -0,0 +1,171 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"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 {
+	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 file struct{}
+
+type listFiles struct{}
+
+type dir struct{}
+
+func (f *file) String() string {
+	return `""`
+}
+
+func (f *file) Set(s string) error {
+	if *relativeRoot == "" {
+		return fmt.Errorf("must pass -C before -f")
+	}
+
+	fArgs = append(fArgs, zip.FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         []string{s},
+	})
+
+	return nil
+}
+
+func (l *listFiles) String() string {
+	return `""`
+}
+
+func (l *listFiles) Set(s string) error {
+	if *relativeRoot == "" {
+		return fmt.Errorf("must pass -C before -l")
+	}
+
+	list, err := ioutil.ReadFile(s)
+	if err != nil {
+		return err
+	}
+
+	fArgs = append(fArgs, zip.FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		SourceFiles:         strings.Split(string(list), "\n"),
+	})
+
+	return nil
+}
+
+func (d *dir) String() string {
+	return `""`
+}
+
+func (d *dir) Set(s string) error {
+	if *relativeRoot == "" {
+		return fmt.Errorf("must pass -C before -D")
+	}
+
+	fArgs = append(fArgs, zip.FileArg{
+		PathPrefixInZip:     filepath.Clean(*rootPrefix),
+		SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+		GlobDir:             filepath.Clean(s),
+	})
+
+	return nil
+}
+
+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'")
+
+	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()
+	os.Exit(2)
+}
+
+func main() {
+	flag.Parse()
+
+	err := zip.Run(zip.ZipArgs{
+		FileArgs:                 fArgs,
+		OutputFilePath:           *out,
+		CpuProfileFilePath:       *cpuProfile,
+		TraceFilePath:            *traceFile,
+		EmulateJar:               *emulateJar,
+		AddDirectoryEntriesToZip: *directories,
+		CompressionLevel:         *compLevel,
+		ManifestSourcePath:       *manifest,
+		NumParallelJobs:          *parallelJobs,
+		NonDeflatedFiles:         nonDeflatedFiles,
+	})
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(1)
+	}
+}