1*333d2b36SAndroid Build Coastguard Worker// Copyright 2015 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Worker// soong_zip is a utility used during the build to create a zip archive by pulling the entries from 16*333d2b36SAndroid Build Coastguard Worker// various sources: 17*333d2b36SAndroid Build Coastguard Worker// * explicitly specified files 18*333d2b36SAndroid Build Coastguard Worker// * files whose paths are read from a file 19*333d2b36SAndroid Build Coastguard Worker// * directories traversed recursively 20*333d2b36SAndroid Build Coastguard Worker// It can optionally change the recorded path of an entry. 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Workerpackage main 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Workerimport ( 25*333d2b36SAndroid Build Coastguard Worker "flag" 26*333d2b36SAndroid Build Coastguard Worker "fmt" 27*333d2b36SAndroid Build Coastguard Worker "os" 28*333d2b36SAndroid Build Coastguard Worker "runtime" 29*333d2b36SAndroid Build Coastguard Worker "runtime/pprof" 30*333d2b36SAndroid Build Coastguard Worker "runtime/trace" 31*333d2b36SAndroid Build Coastguard Worker "strconv" 32*333d2b36SAndroid Build Coastguard Worker "strings" 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Worker "android/soong/response" 35*333d2b36SAndroid Build Coastguard Worker "android/soong/zip" 36*333d2b36SAndroid Build Coastguard Worker) 37*333d2b36SAndroid Build Coastguard Worker 38*333d2b36SAndroid Build Coastguard Workertype uniqueSet map[string]bool 39*333d2b36SAndroid Build Coastguard Worker 40*333d2b36SAndroid Build Coastguard Workerfunc (u *uniqueSet) String() string { 41*333d2b36SAndroid Build Coastguard Worker return `""` 42*333d2b36SAndroid Build Coastguard Worker} 43*333d2b36SAndroid Build Coastguard Worker 44*333d2b36SAndroid Build Coastguard Workerfunc (u *uniqueSet) Set(s string) error { 45*333d2b36SAndroid Build Coastguard Worker if _, found := (*u)[s]; found { 46*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("File %q was specified twice as a file to not deflate", s) 47*333d2b36SAndroid Build Coastguard Worker } else { 48*333d2b36SAndroid Build Coastguard Worker (*u)[s] = true 49*333d2b36SAndroid Build Coastguard Worker } 50*333d2b36SAndroid Build Coastguard Worker 51*333d2b36SAndroid Build Coastguard Worker return nil 52*333d2b36SAndroid Build Coastguard Worker} 53*333d2b36SAndroid Build Coastguard Worker 54*333d2b36SAndroid Build Coastguard Workertype file struct{} 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Workerfunc (file) String() string { return `""` } 57*333d2b36SAndroid Build Coastguard Worker 58*333d2b36SAndroid Build Coastguard Workerfunc (file) Set(s string) error { 59*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.File(s) 60*333d2b36SAndroid Build Coastguard Worker return nil 61*333d2b36SAndroid Build Coastguard Worker} 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Workertype listFiles struct{} 64*333d2b36SAndroid Build Coastguard Worker 65*333d2b36SAndroid Build Coastguard Workerfunc (listFiles) String() string { return `""` } 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Workerfunc (listFiles) Set(s string) error { 68*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.List(s) 69*333d2b36SAndroid Build Coastguard Worker return nil 70*333d2b36SAndroid Build Coastguard Worker} 71*333d2b36SAndroid Build Coastguard Worker 72*333d2b36SAndroid Build Coastguard Workertype rspFiles struct{} 73*333d2b36SAndroid Build Coastguard Worker 74*333d2b36SAndroid Build Coastguard Workerfunc (rspFiles) String() string { return `""` } 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Workerfunc (rspFiles) Set(s string) error { 77*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.RspFile(s) 78*333d2b36SAndroid Build Coastguard Worker return nil 79*333d2b36SAndroid Build Coastguard Worker} 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Workertype explicitFile struct{} 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Workerfunc (explicitFile) String() string { return `""` } 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Workerfunc (explicitFile) Set(s string) error { 86*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.ExplicitPathInZip(s) 87*333d2b36SAndroid Build Coastguard Worker return nil 88*333d2b36SAndroid Build Coastguard Worker} 89*333d2b36SAndroid Build Coastguard Worker 90*333d2b36SAndroid Build Coastguard Workertype dir struct{} 91*333d2b36SAndroid Build Coastguard Worker 92*333d2b36SAndroid Build Coastguard Workerfunc (dir) String() string { return `""` } 93*333d2b36SAndroid Build Coastguard Worker 94*333d2b36SAndroid Build Coastguard Workerfunc (dir) Set(s string) error { 95*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.Dir(s) 96*333d2b36SAndroid Build Coastguard Worker return nil 97*333d2b36SAndroid Build Coastguard Worker} 98*333d2b36SAndroid Build Coastguard Worker 99*333d2b36SAndroid Build Coastguard Workertype relativeRoot struct{} 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Workerfunc (relativeRoot) String() string { return "" } 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Workerfunc (relativeRoot) Set(s string) error { 104*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.SourcePrefixToStrip(s) 105*333d2b36SAndroid Build Coastguard Worker return nil 106*333d2b36SAndroid Build Coastguard Worker} 107*333d2b36SAndroid Build Coastguard Worker 108*333d2b36SAndroid Build Coastguard Workertype junkPaths struct{} 109*333d2b36SAndroid Build Coastguard Worker 110*333d2b36SAndroid Build Coastguard Workerfunc (junkPaths) IsBoolFlag() bool { return true } 111*333d2b36SAndroid Build Coastguard Workerfunc (junkPaths) String() string { return "" } 112*333d2b36SAndroid Build Coastguard Worker 113*333d2b36SAndroid Build Coastguard Workerfunc (junkPaths) Set(s string) error { 114*333d2b36SAndroid Build Coastguard Worker v, err := strconv.ParseBool(s) 115*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.JunkPaths(v) 116*333d2b36SAndroid Build Coastguard Worker return err 117*333d2b36SAndroid Build Coastguard Worker} 118*333d2b36SAndroid Build Coastguard Worker 119*333d2b36SAndroid Build Coastguard Workertype rootPrefix struct{} 120*333d2b36SAndroid Build Coastguard Worker 121*333d2b36SAndroid Build Coastguard Workerfunc (rootPrefix) String() string { return "" } 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Workerfunc (rootPrefix) Set(s string) error { 124*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder.PathPrefixInZip(s) 125*333d2b36SAndroid Build Coastguard Worker return nil 126*333d2b36SAndroid Build Coastguard Worker} 127*333d2b36SAndroid Build Coastguard Worker 128*333d2b36SAndroid Build Coastguard Workervar ( 129*333d2b36SAndroid Build Coastguard Worker fileArgsBuilder = zip.NewFileArgsBuilder() 130*333d2b36SAndroid Build Coastguard Worker nonDeflatedFiles = make(uniqueSet) 131*333d2b36SAndroid Build Coastguard Worker) 132*333d2b36SAndroid Build Coastguard Worker 133*333d2b36SAndroid Build Coastguard Workerfunc main() { 134*333d2b36SAndroid Build Coastguard Worker var expandedArgs []string 135*333d2b36SAndroid Build Coastguard Worker for _, arg := range os.Args { 136*333d2b36SAndroid Build Coastguard Worker if strings.HasPrefix(arg, "@") { 137*333d2b36SAndroid Build Coastguard Worker f, err := os.Open(strings.TrimPrefix(arg, "@")) 138*333d2b36SAndroid Build Coastguard Worker if err != nil { 139*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 140*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker 143*333d2b36SAndroid Build Coastguard Worker respArgs, err := response.ReadRspFile(f) 144*333d2b36SAndroid Build Coastguard Worker f.Close() 145*333d2b36SAndroid Build Coastguard Worker if err != nil { 146*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 147*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, respArgs...) 150*333d2b36SAndroid Build Coastguard Worker } else { 151*333d2b36SAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, arg) 152*333d2b36SAndroid Build Coastguard Worker } 153*333d2b36SAndroid Build Coastguard Worker } 154*333d2b36SAndroid Build Coastguard Worker 155*333d2b36SAndroid Build Coastguard Worker flags := flag.NewFlagSet("flags", flag.ExitOnError) 156*333d2b36SAndroid Build Coastguard Worker flags.Usage = func() { 157*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n") 158*333d2b36SAndroid Build Coastguard Worker flags.PrintDefaults() 159*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 160*333d2b36SAndroid Build Coastguard Worker } 161*333d2b36SAndroid Build Coastguard Worker 162*333d2b36SAndroid Build Coastguard Worker out := flags.String("o", "", "file to write zip file to") 163*333d2b36SAndroid Build Coastguard Worker manifest := flags.String("m", "", "input jar manifest file name") 164*333d2b36SAndroid Build Coastguard Worker directories := flags.Bool("d", false, "include directories in zip") 165*333d2b36SAndroid Build Coastguard Worker compLevel := flags.Int("L", 5, "deflate compression level (0-9)") 166*333d2b36SAndroid Build Coastguard Worker emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") 167*333d2b36SAndroid Build Coastguard Worker writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") 168*333d2b36SAndroid Build Coastguard Worker ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist") 169*333d2b36SAndroid Build Coastguard Worker symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them") 170*333d2b36SAndroid Build Coastguard Worker srcJar := flags.Bool("srcjar", false, "move .java files to locations that match their package statement") 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Worker parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use") 173*333d2b36SAndroid Build Coastguard Worker cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") 174*333d2b36SAndroid Build Coastguard Worker traceFile := flags.String("trace", "", "write trace to file") 175*333d2b36SAndroid Build Coastguard Worker sha256Checksum := flags.Bool("sha256", false, "add a zip header to each file containing its SHA256 digest") 176*333d2b36SAndroid Build Coastguard Worker doNotWrite := flags.Bool("n", false, "Nothing is written to disk -- all other work happens") 177*333d2b36SAndroid Build Coastguard Worker quiet := flags.Bool("quiet", false, "do not print warnings to console") 178*333d2b36SAndroid Build Coastguard Worker 179*333d2b36SAndroid Build Coastguard Worker flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") 180*333d2b36SAndroid Build Coastguard Worker flags.Var(&listFiles{}, "l", "file containing list of files to zip") 181*333d2b36SAndroid Build Coastguard Worker flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping") 182*333d2b36SAndroid Build Coastguard Worker flags.Var(&dir{}, "D", "directory to include in zip") 183*333d2b36SAndroid Build Coastguard Worker flags.Var(&file{}, "f", "file to include in zip") 184*333d2b36SAndroid Build Coastguard Worker flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") 185*333d2b36SAndroid Build Coastguard Worker flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments") 186*333d2b36SAndroid Build Coastguard Worker flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names") 187*333d2b36SAndroid Build Coastguard Worker flags.Var(&explicitFile{}, "e", "filename to use in the zip file for the next -f argument") 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Worker flags.Parse(expandedArgs[1:]) 190*333d2b36SAndroid Build Coastguard Worker 191*333d2b36SAndroid Build Coastguard Worker if flags.NArg() > 0 { 192*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " ")) 193*333d2b36SAndroid Build Coastguard Worker flags.Usage() 194*333d2b36SAndroid Build Coastguard Worker } 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Worker if *cpuProfile != "" { 197*333d2b36SAndroid Build Coastguard Worker f, err := os.Create(*cpuProfile) 198*333d2b36SAndroid Build Coastguard Worker if err != nil { 199*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 200*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 201*333d2b36SAndroid Build Coastguard Worker } 202*333d2b36SAndroid Build Coastguard Worker defer f.Close() 203*333d2b36SAndroid Build Coastguard Worker pprof.StartCPUProfile(f) 204*333d2b36SAndroid Build Coastguard Worker defer pprof.StopCPUProfile() 205*333d2b36SAndroid Build Coastguard Worker } 206*333d2b36SAndroid Build Coastguard Worker 207*333d2b36SAndroid Build Coastguard Worker if *traceFile != "" { 208*333d2b36SAndroid Build Coastguard Worker f, err := os.Create(*traceFile) 209*333d2b36SAndroid Build Coastguard Worker if err != nil { 210*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 211*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 212*333d2b36SAndroid Build Coastguard Worker } 213*333d2b36SAndroid Build Coastguard Worker defer f.Close() 214*333d2b36SAndroid Build Coastguard Worker err = trace.Start(f) 215*333d2b36SAndroid Build Coastguard Worker if err != nil { 216*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 217*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 218*333d2b36SAndroid Build Coastguard Worker } 219*333d2b36SAndroid Build Coastguard Worker defer trace.Stop() 220*333d2b36SAndroid Build Coastguard Worker } 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Worker if fileArgsBuilder.Error() != nil { 223*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, fileArgsBuilder.Error()) 224*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 225*333d2b36SAndroid Build Coastguard Worker } 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Worker err := zip.Zip(zip.ZipArgs{ 228*333d2b36SAndroid Build Coastguard Worker FileArgs: fileArgsBuilder.FileArgs(), 229*333d2b36SAndroid Build Coastguard Worker OutputFilePath: *out, 230*333d2b36SAndroid Build Coastguard Worker EmulateJar: *emulateJar, 231*333d2b36SAndroid Build Coastguard Worker SrcJar: *srcJar, 232*333d2b36SAndroid Build Coastguard Worker AddDirectoryEntriesToZip: *directories, 233*333d2b36SAndroid Build Coastguard Worker CompressionLevel: *compLevel, 234*333d2b36SAndroid Build Coastguard Worker ManifestSourcePath: *manifest, 235*333d2b36SAndroid Build Coastguard Worker NumParallelJobs: *parallelJobs, 236*333d2b36SAndroid Build Coastguard Worker NonDeflatedFiles: nonDeflatedFiles, 237*333d2b36SAndroid Build Coastguard Worker WriteIfChanged: *writeIfChanged, 238*333d2b36SAndroid Build Coastguard Worker StoreSymlinks: *symlinks, 239*333d2b36SAndroid Build Coastguard Worker IgnoreMissingFiles: *ignoreMissingFiles, 240*333d2b36SAndroid Build Coastguard Worker Sha256Checksum: *sha256Checksum, 241*333d2b36SAndroid Build Coastguard Worker DoNotWrite: *doNotWrite, 242*333d2b36SAndroid Build Coastguard Worker Quiet: *quiet, 243*333d2b36SAndroid Build Coastguard Worker }) 244*333d2b36SAndroid Build Coastguard Worker if err != nil { 245*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "error:", err.Error()) 246*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 247*333d2b36SAndroid Build Coastguard Worker } 248*333d2b36SAndroid Build Coastguard Worker} 249