blob: 37537ab8b4a3a2418ce60fd9c124c9369f00aba7 [file] [log] [blame]
Jeff Gaston11b5c512017-10-12 12:19:14 -07001// 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
Sasha Smundak8eedba62020-11-16 19:00:27 -080015// 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
Jeff Gaston11b5c512017-10-12 12:19:14 -070022package main
23
24import (
Jeff Gaston11b5c512017-10-12 12:19:14 -070025 "flag"
26 "fmt"
Jeff Gaston11b5c512017-10-12 12:19:14 -070027 "os"
Jeff Gaston11b5c512017-10-12 12:19:14 -070028 "runtime"
Colin Crossb051ab52018-09-27 15:04:24 -070029 "runtime/pprof"
30 "runtime/trace"
Colin Crossb7c69112018-09-18 16:51:43 -070031 "strconv"
Jeff Gaston11b5c512017-10-12 12:19:14 -070032 "strings"
33
Colin Crossfd708b52021-03-23 14:16:05 -070034 "android/soong/response"
Jeff Gaston11b5c512017-10-12 12:19:14 -070035 "android/soong/zip"
36)
37
Jeff Gaston11b5c512017-10-12 12:19:14 -070038type 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
Colin Crossfe945b42018-09-27 15:00:07 -070056func (file) String() string { return `""` }
57
58func (file) Set(s string) error {
59 fileArgsBuilder.File(s)
60 return nil
61}
62
Jeff Gaston11b5c512017-10-12 12:19:14 -070063type listFiles struct{}
64
Colin Crossfe945b42018-09-27 15:00:07 -070065func (listFiles) String() string { return `""` }
66
67func (listFiles) Set(s string) error {
68 fileArgsBuilder.List(s)
69 return nil
70}
71
Colin Cross053fca12020-08-19 13:51:47 -070072type rspFiles struct{}
73
74func (rspFiles) String() string { return `""` }
75
76func (rspFiles) Set(s string) error {
77 fileArgsBuilder.RspFile(s)
78 return nil
79}
80
Colin Cross25ff3052023-05-08 15:05:29 -070081type explicitFile struct{}
82
83func (explicitFile) String() string { return `""` }
84
85func (explicitFile) Set(s string) error {
86 fileArgsBuilder.ExplicitPathInZip(s)
87 return nil
88}
89
Jeff Gaston11b5c512017-10-12 12:19:14 -070090type dir struct{}
91
Colin Crossfe945b42018-09-27 15:00:07 -070092func (dir) String() string { return `""` }
Jeff Gaston11b5c512017-10-12 12:19:14 -070093
Colin Crossfe945b42018-09-27 15:00:07 -070094func (dir) Set(s string) error {
95 fileArgsBuilder.Dir(s)
Jeff Gaston11b5c512017-10-12 12:19:14 -070096 return nil
97}
98
Colin Crossfe945b42018-09-27 15:00:07 -070099type relativeRoot struct{}
Jeff Gaston11b5c512017-10-12 12:19:14 -0700100
Colin Crossfe945b42018-09-27 15:00:07 -0700101func (relativeRoot) String() string { return "" }
Jeff Gaston11b5c512017-10-12 12:19:14 -0700102
Colin Crossfe945b42018-09-27 15:00:07 -0700103func (relativeRoot) Set(s string) error {
104 fileArgsBuilder.SourcePrefixToStrip(s)
Jeff Gaston11b5c512017-10-12 12:19:14 -0700105 return nil
106}
107
Colin Crossfe945b42018-09-27 15:00:07 -0700108type junkPaths struct{}
Jeff Gaston11b5c512017-10-12 12:19:14 -0700109
Colin Crossfe945b42018-09-27 15:00:07 -0700110func (junkPaths) IsBoolFlag() bool { return true }
111func (junkPaths) String() string { return "" }
Jeff Gaston11b5c512017-10-12 12:19:14 -0700112
Colin Crossfe945b42018-09-27 15:00:07 -0700113func (junkPaths) Set(s string) error {
114 v, err := strconv.ParseBool(s)
115 fileArgsBuilder.JunkPaths(v)
Colin Crossb7c69112018-09-18 16:51:43 -0700116 return err
117}
118
Colin Crossfe945b42018-09-27 15:00:07 -0700119type rootPrefix struct{}
Jeff Gaston11b5c512017-10-12 12:19:14 -0700120
Colin Crossfe945b42018-09-27 15:00:07 -0700121func (rootPrefix) String() string { return "" }
122
123func (rootPrefix) Set(s string) error {
124 fileArgsBuilder.PathPrefixInZip(s)
125 return nil
126}
127
128var (
129 fileArgsBuilder = zip.NewFileArgsBuilder()
Jeff Gaston11b5c512017-10-12 12:19:14 -0700130 nonDeflatedFiles = make(uniqueSet)
Jeff Gaston11b5c512017-10-12 12:19:14 -0700131)
132
Jeff Gaston11b5c512017-10-12 12:19:14 -0700133func main() {
Nan Zhang674dd932018-01-26 18:30:36 -0800134 var expandedArgs []string
135 for _, arg := range os.Args {
136 if strings.HasPrefix(arg, "@") {
Colin Crossfd708b52021-03-23 14:16:05 -0700137 f, err := os.Open(strings.TrimPrefix(arg, "@"))
Nan Zhang674dd932018-01-26 18:30:36 -0800138 if err != nil {
139 fmt.Fprintln(os.Stderr, err.Error())
140 os.Exit(1)
141 }
Colin Crossfd708b52021-03-23 14:16:05 -0700142
143 respArgs, err := response.ReadRspFile(f)
144 f.Close()
145 if err != nil {
146 fmt.Fprintln(os.Stderr, err.Error())
147 os.Exit(1)
148 }
Nan Zhang674dd932018-01-26 18:30:36 -0800149 expandedArgs = append(expandedArgs, respArgs...)
150 } else {
151 expandedArgs = append(expandedArgs, arg)
152 }
153 }
154
155 flags := flag.NewFlagSet("flags", flag.ExitOnError)
Dan Willemsen7f276c62019-04-20 21:44:18 -0700156 flags.Usage = func() {
157 fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n")
158 flags.PrintDefaults()
159 os.Exit(2)
160 }
Nan Zhang674dd932018-01-26 18:30:36 -0800161
162 out := flags.String("o", "", "file to write zip file to")
163 manifest := flags.String("m", "", "input jar manifest file name")
164 directories := flags.Bool("d", false, "include directories in zip")
Nan Zhang674dd932018-01-26 18:30:36 -0800165 compLevel := flags.Int("L", 5, "deflate compression level (0-9)")
166 emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
167 writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
Colin Cross4be8f9e2018-09-28 15:16:48 -0700168 ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist")
Colin Cross09f11052018-09-21 15:12:39 -0700169 symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them")
Colin Cross9cb51db2019-06-17 14:12:41 -0700170 srcJar := flags.Bool("srcjar", false, "move .java files to locations that match their package statement")
Colin Cross09f11052018-09-21 15:12:39 -0700171
Colin Crossdf3f4c82018-09-18 16:31:09 -0700172 parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use")
Nan Zhang674dd932018-01-26 18:30:36 -0800173 cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file")
174 traceFile := flags.String("trace", "", "write trace to file")
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800175 sha256Checksum := flags.Bool("sha256", false, "add a zip header to each file containing its SHA256 digest")
Dan Albert1cec6d52023-07-13 17:41:04 +0000176 doNotWrite := flags.Bool("n", false, "Nothing is written to disk -- all other work happens")
Jihoon Kang3730d7e2023-09-12 23:52:36 +0000177 quiet := flags.Bool("quiet", false, "do not print warnings to console")
Nan Zhang674dd932018-01-26 18:30:36 -0800178
Colin Crossfe945b42018-09-27 15:00:07 -0700179 flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files")
Colin Cross053fca12020-08-19 13:51:47 -0700180 flags.Var(&listFiles{}, "l", "file containing list of files to zip")
181 flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping")
Nan Zhang674dd932018-01-26 18:30:36 -0800182 flags.Var(&dir{}, "D", "directory to include in zip")
183 flags.Var(&file{}, "f", "file to include in zip")
184 flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
Colin Crossfe945b42018-09-27 15:00:07 -0700185 flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments")
186 flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names")
Colin Cross25ff3052023-05-08 15:05:29 -0700187 flags.Var(&explicitFile{}, "e", "filename to use in the zip file for the next -f argument")
Nan Zhang674dd932018-01-26 18:30:36 -0800188
189 flags.Parse(expandedArgs[1:])
Jeff Gaston11b5c512017-10-12 12:19:14 -0700190
Colin Crossfe945b42018-09-27 15:00:07 -0700191 if flags.NArg() > 0 {
192 fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " "))
193 flags.Usage()
194 }
195
Colin Crossb051ab52018-09-27 15:04:24 -0700196 if *cpuProfile != "" {
197 f, err := os.Create(*cpuProfile)
198 if err != nil {
199 fmt.Fprintln(os.Stderr, err.Error())
200 os.Exit(1)
201 }
202 defer f.Close()
203 pprof.StartCPUProfile(f)
204 defer pprof.StopCPUProfile()
205 }
206
207 if *traceFile != "" {
208 f, err := os.Create(*traceFile)
209 if err != nil {
210 fmt.Fprintln(os.Stderr, err.Error())
211 os.Exit(1)
212 }
213 defer f.Close()
214 err = trace.Start(f)
215 if err != nil {
216 fmt.Fprintln(os.Stderr, err.Error())
217 os.Exit(1)
218 }
219 defer trace.Stop()
220 }
221
Colin Crossfe945b42018-09-27 15:00:07 -0700222 if fileArgsBuilder.Error() != nil {
223 fmt.Fprintln(os.Stderr, fileArgsBuilder.Error())
224 os.Exit(1)
225 }
226
Colin Cross05518bc2018-09-27 15:06:19 -0700227 err := zip.Zip(zip.ZipArgs{
Colin Crossfe945b42018-09-27 15:00:07 -0700228 FileArgs: fileArgsBuilder.FileArgs(),
Jeff Gaston11b5c512017-10-12 12:19:14 -0700229 OutputFilePath: *out,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700230 EmulateJar: *emulateJar,
Colin Cross9cb51db2019-06-17 14:12:41 -0700231 SrcJar: *srcJar,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700232 AddDirectoryEntriesToZip: *directories,
233 CompressionLevel: *compLevel,
234 ManifestSourcePath: *manifest,
235 NumParallelJobs: *parallelJobs,
236 NonDeflatedFiles: nonDeflatedFiles,
Colin Crossf83c1502017-11-10 13:11:02 -0800237 WriteIfChanged: *writeIfChanged,
Colin Cross09f11052018-09-21 15:12:39 -0700238 StoreSymlinks: *symlinks,
Colin Cross4be8f9e2018-09-28 15:16:48 -0700239 IgnoreMissingFiles: *ignoreMissingFiles,
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800240 Sha256Checksum: *sha256Checksum,
Dan Albert1cec6d52023-07-13 17:41:04 +0000241 DoNotWrite: *doNotWrite,
Jihoon Kang3730d7e2023-09-12 23:52:36 +0000242 Quiet: *quiet,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700243 })
244 if err != nil {
Colin Cross09f11052018-09-21 15:12:39 -0700245 fmt.Fprintln(os.Stderr, "error:", err.Error())
Jeff Gaston11b5c512017-10-12 12:19:14 -0700246 os.Exit(1)
247 }
248}