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 usage() { 109 fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n") 110 flag.PrintDefaults() 111 os.Exit(2) 112} 113 114func main() { 115 var expandedArgs []string 116 for _, arg := range os.Args { 117 if strings.HasPrefix(arg, "@") { 118 bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@")) 119 if err != nil { 120 fmt.Fprintln(os.Stderr, err.Error()) 121 os.Exit(1) 122 } 123 respArgs := zip.ReadRespFile(bytes) 124 expandedArgs = append(expandedArgs, respArgs...) 125 } else { 126 expandedArgs = append(expandedArgs, arg) 127 } 128 } 129 130 flags := flag.NewFlagSet("flags", flag.ExitOnError) 131 flags.Usage = usage 132 133 out := flags.String("o", "", "file to write zip file to") 134 manifest := flags.String("m", "", "input jar manifest file name") 135 directories := flags.Bool("d", false, "include directories in zip") 136 compLevel := flags.Int("L", 5, "deflate compression level (0-9)") 137 emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") 138 writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") 139 ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist") 140 symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them") 141 142 parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use") 143 cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") 144 traceFile := flags.String("trace", "", "write trace to file") 145 146 flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") 147 flags.Var(&listFiles{}, "l", "file containing list of .class files") 148 flags.Var(&dir{}, "D", "directory to include in zip") 149 flags.Var(&file{}, "f", "file to include in zip") 150 flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") 151 flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments") 152 flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names") 153 154 flags.Parse(expandedArgs[1:]) 155 156 if flags.NArg() > 0 { 157 fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " ")) 158 flags.Usage() 159 } 160 161 if *cpuProfile != "" { 162 f, err := os.Create(*cpuProfile) 163 if err != nil { 164 fmt.Fprintln(os.Stderr, err.Error()) 165 os.Exit(1) 166 } 167 defer f.Close() 168 pprof.StartCPUProfile(f) 169 defer pprof.StopCPUProfile() 170 } 171 172 if *traceFile != "" { 173 f, err := os.Create(*traceFile) 174 if err != nil { 175 fmt.Fprintln(os.Stderr, err.Error()) 176 os.Exit(1) 177 } 178 defer f.Close() 179 err = trace.Start(f) 180 if err != nil { 181 fmt.Fprintln(os.Stderr, err.Error()) 182 os.Exit(1) 183 } 184 defer trace.Stop() 185 } 186 187 if fileArgsBuilder.Error() != nil { 188 fmt.Fprintln(os.Stderr, fileArgsBuilder.Error()) 189 os.Exit(1) 190 } 191 192 err := zip.Zip(zip.ZipArgs{ 193 FileArgs: fileArgsBuilder.FileArgs(), 194 OutputFilePath: *out, 195 EmulateJar: *emulateJar, 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