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