blob: c4e1196d653f80a22fc61f4b620d95ac03c79d10 [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
15package main
16
17import (
18 "bytes"
19 "flag"
20 "fmt"
21 "io"
22 "io/ioutil"
23 "os"
Jeff Gaston11b5c512017-10-12 12:19:14 -070024 "runtime"
Colin Crossb7c69112018-09-18 16:51:43 -070025 "strconv"
Jeff Gaston11b5c512017-10-12 12:19:14 -070026 "strings"
27
28 "android/soong/zip"
29)
30
31type byteReaderCloser struct {
32 *bytes.Reader
33 io.Closer
34}
35
36type pathMapping struct {
37 dest, src string
38 zipMethod uint16
39}
40
41type uniqueSet map[string]bool
42
43func (u *uniqueSet) String() string {
44 return `""`
45}
46
47func (u *uniqueSet) Set(s string) error {
48 if _, found := (*u)[s]; found {
49 return fmt.Errorf("File %q was specified twice as a file to not deflate", s)
50 } else {
51 (*u)[s] = true
52 }
53
54 return nil
55}
56
57type file struct{}
58
59type listFiles struct{}
60
61type dir struct{}
62
63func (f *file) String() string {
64 return `""`
65}
66
67func (f *file) Set(s string) error {
Colin Crossb7c69112018-09-18 16:51:43 -070068 if relativeRoot == "" && !junkPaths {
69 return fmt.Errorf("must pass -C or -j before -f")
Jeff Gaston11b5c512017-10-12 12:19:14 -070070 }
71
72 fArgs = append(fArgs, zip.FileArg{
Colin Crossb7c69112018-09-18 16:51:43 -070073 PathPrefixInZip: *rootPrefix,
74 SourcePrefixToStrip: relativeRoot,
75 JunkPaths: junkPaths,
Jeff Gaston11b5c512017-10-12 12:19:14 -070076 SourceFiles: []string{s},
77 })
78
79 return nil
80}
81
82func (l *listFiles) String() string {
83 return `""`
84}
85
86func (l *listFiles) Set(s string) error {
Colin Crossb7c69112018-09-18 16:51:43 -070087 if relativeRoot == "" && !junkPaths {
88 return fmt.Errorf("must pass -C or -j before -l")
Jeff Gaston11b5c512017-10-12 12:19:14 -070089 }
90
91 list, err := ioutil.ReadFile(s)
92 if err != nil {
93 return err
94 }
95
96 fArgs = append(fArgs, zip.FileArg{
Colin Crossb7c69112018-09-18 16:51:43 -070097 PathPrefixInZip: *rootPrefix,
98 SourcePrefixToStrip: relativeRoot,
99 JunkPaths: junkPaths,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700100 SourceFiles: strings.Split(string(list), "\n"),
101 })
102
103 return nil
104}
105
106func (d *dir) String() string {
107 return `""`
108}
109
110func (d *dir) Set(s string) error {
Colin Crossb7c69112018-09-18 16:51:43 -0700111 if relativeRoot == "" && !junkPaths {
112 return fmt.Errorf("must pass -C or -j before -D")
Jeff Gaston11b5c512017-10-12 12:19:14 -0700113 }
114
115 fArgs = append(fArgs, zip.FileArg{
Colin Crossb7c69112018-09-18 16:51:43 -0700116 PathPrefixInZip: *rootPrefix,
117 SourcePrefixToStrip: relativeRoot,
118 JunkPaths: junkPaths,
119 GlobDir: s,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700120 })
121
122 return nil
123}
124
Colin Crossb7c69112018-09-18 16:51:43 -0700125type relativeRootImpl struct{}
126
127func (*relativeRootImpl) String() string { return relativeRoot }
128
129func (*relativeRootImpl) Set(s string) error {
130 relativeRoot = s
131 junkPaths = false
132 return nil
133}
134
135type junkPathsImpl struct{}
136
137func (*junkPathsImpl) IsBoolFlag() bool { return true }
138
139func (*junkPathsImpl) String() string { return relativeRoot }
140
141func (*junkPathsImpl) Set(s string) error {
142 var err error
143 junkPaths, err = strconv.ParseBool(s)
144 relativeRoot = ""
145 return err
146}
147
Jeff Gaston11b5c512017-10-12 12:19:14 -0700148var (
Colin Crossb7c69112018-09-18 16:51:43 -0700149 rootPrefix *string
150 relativeRoot string
151 junkPaths bool
Jeff Gaston11b5c512017-10-12 12:19:14 -0700152
153 fArgs zip.FileArgs
154 nonDeflatedFiles = make(uniqueSet)
Jeff Gaston11b5c512017-10-12 12:19:14 -0700155)
156
Jeff Gaston11b5c512017-10-12 12:19:14 -0700157func usage() {
158 fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
159 flag.PrintDefaults()
160 os.Exit(2)
161}
162
163func main() {
Nan Zhang674dd932018-01-26 18:30:36 -0800164 var expandedArgs []string
165 for _, arg := range os.Args {
166 if strings.HasPrefix(arg, "@") {
167 bytes, err := ioutil.ReadFile(strings.TrimPrefix(arg, "@"))
168 if err != nil {
169 fmt.Fprintln(os.Stderr, err.Error())
170 os.Exit(1)
171 }
172 respArgs := zip.ReadRespFile(bytes)
173 expandedArgs = append(expandedArgs, respArgs...)
174 } else {
175 expandedArgs = append(expandedArgs, arg)
176 }
177 }
178
179 flags := flag.NewFlagSet("flags", flag.ExitOnError)
180
181 out := flags.String("o", "", "file to write zip file to")
182 manifest := flags.String("m", "", "input jar manifest file name")
183 directories := flags.Bool("d", false, "include directories in zip")
184 rootPrefix = flags.String("P", "", "path prefix within the zip at which to place files")
Nan Zhang674dd932018-01-26 18:30:36 -0800185 compLevel := flags.Int("L", 5, "deflate compression level (0-9)")
186 emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
187 writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
188
Colin Crossd59dab92018-09-21 15:12:39 -0700189 symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them")
190
Colin Crossdf3f4c82018-09-18 16:31:09 -0700191 parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use")
Nan Zhang674dd932018-01-26 18:30:36 -0800192 cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file")
193 traceFile := flags.String("trace", "", "write trace to file")
194
195 flags.Var(&listFiles{}, "l", "file containing list of .class files")
196 flags.Var(&dir{}, "D", "directory to include in zip")
197 flags.Var(&file{}, "f", "file to include in zip")
198 flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
Colin Crossb7c69112018-09-18 16:51:43 -0700199 flags.Var(&relativeRootImpl{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments")
200 flags.Var(&junkPathsImpl{}, "j", "junk paths, zip files without directory names")
Nan Zhang674dd932018-01-26 18:30:36 -0800201
202 flags.Parse(expandedArgs[1:])
Jeff Gaston11b5c512017-10-12 12:19:14 -0700203
Colin Cross08e28ab2018-09-18 17:05:15 -0700204 if flags.NArg() > 0 {
205 fmt.Fprintf(os.Stderr, "unexpected arguments %s\n", strings.Join(flags.Args(), " "))
206 usage()
207 }
208
Jeff Gaston11b5c512017-10-12 12:19:14 -0700209 err := zip.Run(zip.ZipArgs{
210 FileArgs: fArgs,
211 OutputFilePath: *out,
212 CpuProfileFilePath: *cpuProfile,
213 TraceFilePath: *traceFile,
214 EmulateJar: *emulateJar,
215 AddDirectoryEntriesToZip: *directories,
216 CompressionLevel: *compLevel,
217 ManifestSourcePath: *manifest,
218 NumParallelJobs: *parallelJobs,
219 NonDeflatedFiles: nonDeflatedFiles,
Colin Crossf83c1502017-11-10 13:11:02 -0800220 WriteIfChanged: *writeIfChanged,
Colin Crossd59dab92018-09-21 15:12:39 -0700221 StoreSymlinks: *symlinks,
Jeff Gaston11b5c512017-10-12 12:19:14 -0700222 })
223 if err != nil {
Colin Crossd59dab92018-09-21 15:12:39 -0700224 fmt.Fprintln(os.Stderr, "error:", err.Error())
Jeff Gaston11b5c512017-10-12 12:19:14 -0700225 os.Exit(1)
226 }
227}