| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 1 | // Copyright 2015 Google Inc. All rights reserved. | 
|  | 2 | // | 
|  | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 4 | // you may not use this file except in compliance with the License. | 
|  | 5 | // You may obtain a copy of the License at | 
|  | 6 | // | 
|  | 7 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 8 | // | 
|  | 9 | // Unless required by applicable law or agreed to in writing, software | 
|  | 10 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 12 | // See the License for the specific language governing permissions and | 
|  | 13 | // limitations under the License. | 
|  | 14 |  | 
|  | 15 | package main | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "bytes" | 
|  | 19 | "flag" | 
|  | 20 | "fmt" | 
|  | 21 | "io" | 
|  | 22 | "io/ioutil" | 
|  | 23 | "os" | 
|  | 24 | "path/filepath" | 
|  | 25 | "runtime" | 
|  | 26 | "strings" | 
|  | 27 |  | 
|  | 28 | "android/soong/zip" | 
|  | 29 | ) | 
|  | 30 |  | 
|  | 31 | type byteReaderCloser struct { | 
|  | 32 | *bytes.Reader | 
|  | 33 | io.Closer | 
|  | 34 | } | 
|  | 35 |  | 
|  | 36 | type pathMapping struct { | 
|  | 37 | dest, src string | 
|  | 38 | zipMethod uint16 | 
|  | 39 | } | 
|  | 40 |  | 
|  | 41 | type uniqueSet map[string]bool | 
|  | 42 |  | 
|  | 43 | func (u *uniqueSet) String() string { | 
|  | 44 | return `""` | 
|  | 45 | } | 
|  | 46 |  | 
|  | 47 | func (u *uniqueSet) Set(s string) error { | 
|  | 48 | if _, found := (*u)[s]; found { | 
|  | 49 | return fmt.Errorf("File %q was specified twice as a file to not deflate", s) | 
|  | 50 | } else { | 
|  | 51 | (*u)[s] = true | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | return nil | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | type file struct{} | 
|  | 58 |  | 
|  | 59 | type listFiles struct{} | 
|  | 60 |  | 
|  | 61 | type dir struct{} | 
|  | 62 |  | 
|  | 63 | func (f *file) String() string { | 
|  | 64 | return `""` | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | func (f *file) Set(s string) error { | 
|  | 68 | if *relativeRoot == "" { | 
|  | 69 | return fmt.Errorf("must pass -C before -f") | 
|  | 70 | } | 
|  | 71 |  | 
|  | 72 | fArgs = append(fArgs, zip.FileArg{ | 
|  | 73 | PathPrefixInZip:     filepath.Clean(*rootPrefix), | 
|  | 74 | SourcePrefixToStrip: filepath.Clean(*relativeRoot), | 
|  | 75 | SourceFiles:         []string{s}, | 
|  | 76 | }) | 
|  | 77 |  | 
|  | 78 | return nil | 
|  | 79 | } | 
|  | 80 |  | 
|  | 81 | func (l *listFiles) String() string { | 
|  | 82 | return `""` | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | func (l *listFiles) Set(s string) error { | 
|  | 86 | if *relativeRoot == "" { | 
|  | 87 | return fmt.Errorf("must pass -C before -l") | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | list, err := ioutil.ReadFile(s) | 
|  | 91 | if err != nil { | 
|  | 92 | return err | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | fArgs = append(fArgs, zip.FileArg{ | 
|  | 96 | PathPrefixInZip:     filepath.Clean(*rootPrefix), | 
|  | 97 | SourcePrefixToStrip: filepath.Clean(*relativeRoot), | 
|  | 98 | SourceFiles:         strings.Split(string(list), "\n"), | 
|  | 99 | }) | 
|  | 100 |  | 
|  | 101 | return nil | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | func (d *dir) String() string { | 
|  | 105 | return `""` | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | func (d *dir) Set(s string) error { | 
|  | 109 | if *relativeRoot == "" { | 
|  | 110 | return fmt.Errorf("must pass -C before -D") | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | fArgs = append(fArgs, zip.FileArg{ | 
|  | 114 | PathPrefixInZip:     filepath.Clean(*rootPrefix), | 
|  | 115 | SourcePrefixToStrip: filepath.Clean(*relativeRoot), | 
|  | 116 | GlobDir:             filepath.Clean(s), | 
|  | 117 | }) | 
|  | 118 |  | 
|  | 119 | return nil | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | var ( | 
| Nan Zhang | 674dd93 | 2018-01-26 18:30:36 -0800 | [diff] [blame] | 123 | rootPrefix, relativeRoot *string | 
| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 124 |  | 
|  | 125 | fArgs            zip.FileArgs | 
|  | 126 | nonDeflatedFiles = make(uniqueSet) | 
| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 127 | ) | 
|  | 128 |  | 
| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 129 | func usage() { | 
|  | 130 | fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n") | 
|  | 131 | flag.PrintDefaults() | 
|  | 132 | os.Exit(2) | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | func main() { | 
| Nan Zhang | 674dd93 | 2018-01-26 18:30:36 -0800 | [diff] [blame] | 136 | var expandedArgs []string | 
|  | 137 | for _, arg := range os.Args { | 
|  | 138 | if strings.HasPrefix(arg, "@") { | 
|  | 139 | bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@")) | 
|  | 140 | if err != nil { | 
|  | 141 | fmt.Fprintln(os.Stderr, err.Error()) | 
|  | 142 | os.Exit(1) | 
|  | 143 | } | 
|  | 144 | respArgs := zip.ReadRespFile(bytes) | 
|  | 145 | expandedArgs = append(expandedArgs, respArgs...) | 
|  | 146 | } else { | 
|  | 147 | expandedArgs = append(expandedArgs, arg) | 
|  | 148 | } | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | flags := flag.NewFlagSet("flags", flag.ExitOnError) | 
|  | 152 |  | 
|  | 153 | out := flags.String("o", "", "file to write zip file to") | 
|  | 154 | manifest := flags.String("m", "", "input jar manifest file name") | 
|  | 155 | directories := flags.Bool("d", false, "include directories in zip") | 
|  | 156 | rootPrefix = flags.String("P", "", "path prefix within the zip at which to place files") | 
|  | 157 | relativeRoot = flags.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments") | 
| Nan Zhang | 674dd93 | 2018-01-26 18:30:36 -0800 | [diff] [blame] | 158 | compLevel := flags.Int("L", 5, "deflate compression level (0-9)") | 
|  | 159 | emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") | 
|  | 160 | writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") | 
|  | 161 |  | 
| Colin Cross | df3f4c8 | 2018-09-18 16:31:09 -0700 | [diff] [blame^] | 162 | parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use") | 
| Nan Zhang | 674dd93 | 2018-01-26 18:30:36 -0800 | [diff] [blame] | 163 | cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") | 
|  | 164 | traceFile := flags.String("trace", "", "write trace to file") | 
|  | 165 |  | 
|  | 166 | flags.Var(&listFiles{}, "l", "file containing list of .class files") | 
|  | 167 | flags.Var(&dir{}, "D", "directory to include in zip") | 
|  | 168 | flags.Var(&file{}, "f", "file to include in zip") | 
|  | 169 | flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") | 
|  | 170 |  | 
|  | 171 | flags.Parse(expandedArgs[1:]) | 
| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 172 |  | 
|  | 173 | err := zip.Run(zip.ZipArgs{ | 
|  | 174 | FileArgs:                 fArgs, | 
|  | 175 | OutputFilePath:           *out, | 
|  | 176 | CpuProfileFilePath:       *cpuProfile, | 
|  | 177 | TraceFilePath:            *traceFile, | 
|  | 178 | EmulateJar:               *emulateJar, | 
|  | 179 | AddDirectoryEntriesToZip: *directories, | 
|  | 180 | CompressionLevel:         *compLevel, | 
|  | 181 | ManifestSourcePath:       *manifest, | 
|  | 182 | NumParallelJobs:          *parallelJobs, | 
|  | 183 | NonDeflatedFiles:         nonDeflatedFiles, | 
| Colin Cross | f83c150 | 2017-11-10 13:11:02 -0800 | [diff] [blame] | 184 | WriteIfChanged:           *writeIfChanged, | 
| Jeff Gaston | 11b5c51 | 2017-10-12 12:19:14 -0700 | [diff] [blame] | 185 | }) | 
|  | 186 | if err != nil { | 
|  | 187 | fmt.Fprintln(os.Stderr, err.Error()) | 
|  | 188 | os.Exit(1) | 
|  | 189 | } | 
|  | 190 | } |