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 15package main 16 17import ( 18 "flag" 19 "fmt" 20 "io/ioutil" 21 "os" 22 "runtime" 23 "runtime/pprof" 24 "runtime/trace" 25 "strconv" 26 "strings" 27 28 "android/soong/zip" 29) 30 31type uniqueSet map[string]bool 32 33func (u *uniqueSet) String() string { 34 return `""` 35} 36 37func (u *uniqueSet) Set(s string) error { 38 if _, found := (*u)[s]; found { 39 return fmt.Errorf("File %q was specified twice as a file to not deflate", s) 40 } else { 41 (*u)[s] = true 42 } 43 44 return nil 45} 46 47type file struct{} 48 49func (file) String() string { return `""` } 50 51func (file) Set(s string) error { 52 fileArgsBuilder.File(s) 53 return nil 54} 55 56type listFiles struct{} 57 58func (listFiles) String() string { return `""` } 59 60func (listFiles) Set(s string) error { 61 fileArgsBuilder.List(s) 62 return nil 63} 64 65type dir struct{} 66 67func (dir) String() string { return `""` } 68 69func (dir) Set(s string) error { 70 fileArgsBuilder.Dir(s) 71 return nil 72} 73 74type relativeRoot struct{} 75 76func (relativeRoot) String() string { return "" } 77 78func (relativeRoot) Set(s string) error { 79 fileArgsBuilder.SourcePrefixToStrip(s) 80 return nil 81} 82 83type junkPaths struct{} 84 85func (junkPaths) IsBoolFlag() bool { return true } 86func (junkPaths) String() string { return "" } 87 88func (junkPaths) Set(s string) error { 89 v, err := strconv.ParseBool(s) 90 fileArgsBuilder.JunkPaths(v) 91 return err 92} 93 94type rootPrefix struct{} 95 96func (rootPrefix) String() string { return "" } 97 98func (rootPrefix) Set(s string) error { 99 fileArgsBuilder.PathPrefixInZip(s) 100 return nil 101} 102 103var ( 104 fileArgsBuilder = zip.NewFileArgsBuilder() 105 nonDeflatedFiles = make(uniqueSet) 106) 107 108func main() { 109 var expandedArgs []string 110 for _, arg := range os.Args { 111 if strings.HasPrefix(arg, "@") { 112 bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@")) 113 if err != nil { 114 fmt.Fprintln(os.Stderr, err.Error()) 115 os.Exit(1) 116 } 117 respArgs := zip.ReadRespFile(bytes) 118 expandedArgs = append(expandedArgs, respArgs...) 119 } else { 120 expandedArgs = append(expandedArgs, arg) 121 } 122 } 123 124 flags := flag.NewFlagSet("flags", flag.ExitOnError) 125 flags.Usage = func() { 126 fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n") 127 flags.PrintDefaults() 128 os.Exit(2) 129 } 130 131 out := flags.String("o", "", "file to write zip file to") 132 manifest := flags.String("m", "", "input jar manifest file name") 133 directories := flags.Bool("d", false, "include directories in zip") 134 compLevel := flags.Int("L", 5, "deflate compression level (0-9)") 135 emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") 136 writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") 137 ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist") 138 symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them") 139 srcJar := flags.Bool("srcjar", false, "move .java files to locations that match their package statement") 140 141 parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use") 142 cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") 143 traceFile := flags.String("trace", "", "write trace to file") 144 145 flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") 146 flags.Var(&listFiles{}, "l", "file containing list of .class files") 147 flags.Var(&dir{}, "D", "directory to include in zip") 148 flags.Var(&file{}, "f", "file to include in zip") 149 flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") 150 flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments") 151 flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names") 152 153 flags.Parse(expandedArgs[1:]) 154 155 if flags.NArg() > 0 { 156 fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " ")) 157 flags.Usage() 158 } 159 160 if *cpuProfile != "" { 161 f, err := os.Create(*cpuProfile) 162 if err != nil { 163 fmt.Fprintln(os.Stderr, err.Error()) 164 os.Exit(1) 165 } 166 defer f.Close() 167 pprof.StartCPUProfile(f) 168 defer pprof.StopCPUProfile() 169 } 170 171 if *traceFile != "" { 172 f, err := os.Create(*traceFile) 173 if err != nil { 174 fmt.Fprintln(os.Stderr, err.Error()) 175 os.Exit(1) 176 } 177 defer f.Close() 178 err = trace.Start(f) 179 if err != nil { 180 fmt.Fprintln(os.Stderr, err.Error()) 181 os.Exit(1) 182 } 183 defer trace.Stop() 184 } 185 186 if fileArgsBuilder.Error() != nil { 187 fmt.Fprintln(os.Stderr, fileArgsBuilder.Error()) 188 os.Exit(1) 189 } 190 191 err := zip.Zip(zip.ZipArgs{ 192 FileArgs: fileArgsBuilder.FileArgs(), 193 OutputFilePath: *out, 194 EmulateJar: *emulateJar, 195 SrcJar: *srcJar, 196 AddDirectoryEntriesToZip: *directories, 197 CompressionLevel: *compLevel, 198 ManifestSourcePath: *manifest, 199 NumParallelJobs: *parallelJobs, 200 NonDeflatedFiles: nonDeflatedFiles, 201 WriteIfChanged: *writeIfChanged, 202 StoreSymlinks: *symlinks, 203 IgnoreMissingFiles: *ignoreMissingFiles, 204 }) 205 if err != nil { 206 fmt.Fprintln(os.Stderr, "error:", err.Error()) 207 os.Exit(1) 208 } 209} 210