xref: /aosp_15_r20/build/soong/cmd/merge_zips/merge_zips.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 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 Workerpackage main
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"errors"
19*333d2b36SAndroid Build Coastguard Worker	"flag"
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"hash/crc32"
22*333d2b36SAndroid Build Coastguard Worker	"io"
23*333d2b36SAndroid Build Coastguard Worker	"io/ioutil"
24*333d2b36SAndroid Build Coastguard Worker	"log"
25*333d2b36SAndroid Build Coastguard Worker	"os"
26*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
27*333d2b36SAndroid Build Coastguard Worker	"sort"
28*333d2b36SAndroid Build Coastguard Worker	"strings"
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Worker	"android/soong/response"
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/pathtools"
33*333d2b36SAndroid Build Coastguard Worker
34*333d2b36SAndroid Build Coastguard Worker	"android/soong/jar"
35*333d2b36SAndroid Build Coastguard Worker	"android/soong/third_party/zip"
36*333d2b36SAndroid Build Coastguard Worker)
37*333d2b36SAndroid Build Coastguard Worker
38*333d2b36SAndroid Build Coastguard Worker// Input zip: we can open it, close it, and obtain an array of entries
39*333d2b36SAndroid Build Coastguard Workertype InputZip interface {
40*333d2b36SAndroid Build Coastguard Worker	Name() string
41*333d2b36SAndroid Build Coastguard Worker	Open() error
42*333d2b36SAndroid Build Coastguard Worker	Close() error
43*333d2b36SAndroid Build Coastguard Worker	Entries() []*zip.File
44*333d2b36SAndroid Build Coastguard Worker	IsOpen() bool
45*333d2b36SAndroid Build Coastguard Worker}
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker// An entry that can be written to the output zip
48*333d2b36SAndroid Build Coastguard Workertype ZipEntryContents interface {
49*333d2b36SAndroid Build Coastguard Worker	String() string
50*333d2b36SAndroid Build Coastguard Worker	IsDir() bool
51*333d2b36SAndroid Build Coastguard Worker	CRC32() uint32
52*333d2b36SAndroid Build Coastguard Worker	Size() uint64
53*333d2b36SAndroid Build Coastguard Worker	WriteToZip(dest string, zw *zip.Writer) error
54*333d2b36SAndroid Build Coastguard Worker}
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Worker// a ZipEntryFromZip is a ZipEntryContents that pulls its content from another zip
57*333d2b36SAndroid Build Coastguard Worker// identified by the input zip and the index of the entry in its entries array
58*333d2b36SAndroid Build Coastguard Workertype ZipEntryFromZip struct {
59*333d2b36SAndroid Build Coastguard Worker	inputZip InputZip
60*333d2b36SAndroid Build Coastguard Worker	index    int
61*333d2b36SAndroid Build Coastguard Worker	name     string
62*333d2b36SAndroid Build Coastguard Worker	isDir    bool
63*333d2b36SAndroid Build Coastguard Worker	crc32    uint32
64*333d2b36SAndroid Build Coastguard Worker	size     uint64
65*333d2b36SAndroid Build Coastguard Worker}
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Workerfunc NewZipEntryFromZip(inputZip InputZip, entryIndex int) *ZipEntryFromZip {
68*333d2b36SAndroid Build Coastguard Worker	fi := inputZip.Entries()[entryIndex]
69*333d2b36SAndroid Build Coastguard Worker	newEntry := ZipEntryFromZip{inputZip: inputZip,
70*333d2b36SAndroid Build Coastguard Worker		index: entryIndex,
71*333d2b36SAndroid Build Coastguard Worker		name:  fi.Name,
72*333d2b36SAndroid Build Coastguard Worker		isDir: fi.FileInfo().IsDir(),
73*333d2b36SAndroid Build Coastguard Worker		crc32: fi.CRC32,
74*333d2b36SAndroid Build Coastguard Worker		size:  fi.UncompressedSize64,
75*333d2b36SAndroid Build Coastguard Worker	}
76*333d2b36SAndroid Build Coastguard Worker	return &newEntry
77*333d2b36SAndroid Build Coastguard Worker}
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Workerfunc (ze ZipEntryFromZip) String() string {
80*333d2b36SAndroid Build Coastguard Worker	return fmt.Sprintf("%s!%s", ze.inputZip.Name(), ze.name)
81*333d2b36SAndroid Build Coastguard Worker}
82*333d2b36SAndroid Build Coastguard Worker
83*333d2b36SAndroid Build Coastguard Workerfunc (ze ZipEntryFromZip) IsDir() bool {
84*333d2b36SAndroid Build Coastguard Worker	return ze.isDir
85*333d2b36SAndroid Build Coastguard Worker}
86*333d2b36SAndroid Build Coastguard Worker
87*333d2b36SAndroid Build Coastguard Workerfunc (ze ZipEntryFromZip) CRC32() uint32 {
88*333d2b36SAndroid Build Coastguard Worker	return ze.crc32
89*333d2b36SAndroid Build Coastguard Worker}
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Workerfunc (ze ZipEntryFromZip) Size() uint64 {
92*333d2b36SAndroid Build Coastguard Worker	return ze.size
93*333d2b36SAndroid Build Coastguard Worker}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Workerfunc (ze ZipEntryFromZip) WriteToZip(dest string, zw *zip.Writer) error {
96*333d2b36SAndroid Build Coastguard Worker	if err := ze.inputZip.Open(); err != nil {
97*333d2b36SAndroid Build Coastguard Worker		return err
98*333d2b36SAndroid Build Coastguard Worker	}
99*333d2b36SAndroid Build Coastguard Worker	entry := ze.inputZip.Entries()[ze.index]
100*333d2b36SAndroid Build Coastguard Worker	entry.SetModTime(jar.DefaultTime)
101*333d2b36SAndroid Build Coastguard Worker	return zw.CopyFrom(entry, dest)
102*333d2b36SAndroid Build Coastguard Worker}
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Worker// a ZipEntryFromBuffer is a ZipEntryContents that pulls its content from a []byte
105*333d2b36SAndroid Build Coastguard Workertype ZipEntryFromBuffer struct {
106*333d2b36SAndroid Build Coastguard Worker	fh      *zip.FileHeader
107*333d2b36SAndroid Build Coastguard Worker	content []byte
108*333d2b36SAndroid Build Coastguard Worker}
109*333d2b36SAndroid Build Coastguard Worker
110*333d2b36SAndroid Build Coastguard Workerfunc (be ZipEntryFromBuffer) String() string {
111*333d2b36SAndroid Build Coastguard Worker	return "internal buffer"
112*333d2b36SAndroid Build Coastguard Worker}
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Workerfunc (be ZipEntryFromBuffer) IsDir() bool {
115*333d2b36SAndroid Build Coastguard Worker	return be.fh.FileInfo().IsDir()
116*333d2b36SAndroid Build Coastguard Worker}
117*333d2b36SAndroid Build Coastguard Worker
118*333d2b36SAndroid Build Coastguard Workerfunc (be ZipEntryFromBuffer) CRC32() uint32 {
119*333d2b36SAndroid Build Coastguard Worker	return crc32.ChecksumIEEE(be.content)
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Workerfunc (be ZipEntryFromBuffer) Size() uint64 {
123*333d2b36SAndroid Build Coastguard Worker	return uint64(len(be.content))
124*333d2b36SAndroid Build Coastguard Worker}
125*333d2b36SAndroid Build Coastguard Worker
126*333d2b36SAndroid Build Coastguard Workerfunc (be ZipEntryFromBuffer) WriteToZip(dest string, zw *zip.Writer) error {
127*333d2b36SAndroid Build Coastguard Worker	w, err := zw.CreateHeaderAndroid(be.fh)
128*333d2b36SAndroid Build Coastguard Worker	if err != nil {
129*333d2b36SAndroid Build Coastguard Worker		return err
130*333d2b36SAndroid Build Coastguard Worker	}
131*333d2b36SAndroid Build Coastguard Worker
132*333d2b36SAndroid Build Coastguard Worker	if !be.IsDir() {
133*333d2b36SAndroid Build Coastguard Worker		_, err = w.Write(be.content)
134*333d2b36SAndroid Build Coastguard Worker		if err != nil {
135*333d2b36SAndroid Build Coastguard Worker			return err
136*333d2b36SAndroid Build Coastguard Worker		}
137*333d2b36SAndroid Build Coastguard Worker	}
138*333d2b36SAndroid Build Coastguard Worker
139*333d2b36SAndroid Build Coastguard Worker	return nil
140*333d2b36SAndroid Build Coastguard Worker}
141*333d2b36SAndroid Build Coastguard Worker
142*333d2b36SAndroid Build Coastguard Worker// Processing state.
143*333d2b36SAndroid Build Coastguard Workertype OutputZip struct {
144*333d2b36SAndroid Build Coastguard Worker	outputWriter     *zip.Writer
145*333d2b36SAndroid Build Coastguard Worker	stripDirEntries  bool
146*333d2b36SAndroid Build Coastguard Worker	emulateJar       bool
147*333d2b36SAndroid Build Coastguard Worker	sortEntries      bool
148*333d2b36SAndroid Build Coastguard Worker	ignoreDuplicates bool
149*333d2b36SAndroid Build Coastguard Worker	excludeDirs      []string
150*333d2b36SAndroid Build Coastguard Worker	excludeFiles     []string
151*333d2b36SAndroid Build Coastguard Worker	sourceByDest     map[string]ZipEntryContents
152*333d2b36SAndroid Build Coastguard Worker}
153*333d2b36SAndroid Build Coastguard Worker
154*333d2b36SAndroid Build Coastguard Workerfunc NewOutputZip(outputWriter *zip.Writer, sortEntries, emulateJar, stripDirEntries, ignoreDuplicates bool) *OutputZip {
155*333d2b36SAndroid Build Coastguard Worker	return &OutputZip{
156*333d2b36SAndroid Build Coastguard Worker		outputWriter:     outputWriter,
157*333d2b36SAndroid Build Coastguard Worker		stripDirEntries:  stripDirEntries,
158*333d2b36SAndroid Build Coastguard Worker		emulateJar:       emulateJar,
159*333d2b36SAndroid Build Coastguard Worker		sortEntries:      sortEntries,
160*333d2b36SAndroid Build Coastguard Worker		sourceByDest:     make(map[string]ZipEntryContents, 0),
161*333d2b36SAndroid Build Coastguard Worker		ignoreDuplicates: ignoreDuplicates,
162*333d2b36SAndroid Build Coastguard Worker	}
163*333d2b36SAndroid Build Coastguard Worker}
164*333d2b36SAndroid Build Coastguard Worker
165*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) setExcludeDirs(excludeDirs []string) {
166*333d2b36SAndroid Build Coastguard Worker	oz.excludeDirs = make([]string, len(excludeDirs))
167*333d2b36SAndroid Build Coastguard Worker	for i, dir := range excludeDirs {
168*333d2b36SAndroid Build Coastguard Worker		oz.excludeDirs[i] = filepath.Clean(dir)
169*333d2b36SAndroid Build Coastguard Worker	}
170*333d2b36SAndroid Build Coastguard Worker}
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) setExcludeFiles(excludeFiles []string) {
173*333d2b36SAndroid Build Coastguard Worker	oz.excludeFiles = excludeFiles
174*333d2b36SAndroid Build Coastguard Worker}
175*333d2b36SAndroid Build Coastguard Worker
176*333d2b36SAndroid Build Coastguard Worker// Adds an entry with given name whose source is given ZipEntryContents. Returns old ZipEntryContents
177*333d2b36SAndroid Build Coastguard Worker// if entry with given name already exists.
178*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) addZipEntry(name string, source ZipEntryContents) (ZipEntryContents, error) {
179*333d2b36SAndroid Build Coastguard Worker	if existingSource, exists := oz.sourceByDest[name]; exists {
180*333d2b36SAndroid Build Coastguard Worker		return existingSource, nil
181*333d2b36SAndroid Build Coastguard Worker	}
182*333d2b36SAndroid Build Coastguard Worker	oz.sourceByDest[name] = source
183*333d2b36SAndroid Build Coastguard Worker	// Delay writing an entry if entries need to be rearranged.
184*333d2b36SAndroid Build Coastguard Worker	if oz.emulateJar || oz.sortEntries {
185*333d2b36SAndroid Build Coastguard Worker		return nil, nil
186*333d2b36SAndroid Build Coastguard Worker	}
187*333d2b36SAndroid Build Coastguard Worker	return nil, source.WriteToZip(name, oz.outputWriter)
188*333d2b36SAndroid Build Coastguard Worker}
189*333d2b36SAndroid Build Coastguard Worker
190*333d2b36SAndroid Build Coastguard Worker// Adds an entry for the manifest (META-INF/MANIFEST.MF from the given file
191*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) addManifest(manifestPath string) error {
192*333d2b36SAndroid Build Coastguard Worker	if !oz.stripDirEntries {
193*333d2b36SAndroid Build Coastguard Worker		if _, err := oz.addZipEntry(jar.MetaDir, ZipEntryFromBuffer{jar.MetaDirFileHeader(), nil}); err != nil {
194*333d2b36SAndroid Build Coastguard Worker			return err
195*333d2b36SAndroid Build Coastguard Worker		}
196*333d2b36SAndroid Build Coastguard Worker	}
197*333d2b36SAndroid Build Coastguard Worker	contents, err := ioutil.ReadFile(manifestPath)
198*333d2b36SAndroid Build Coastguard Worker	if err == nil {
199*333d2b36SAndroid Build Coastguard Worker		fh, buf, err := jar.ManifestFileContents(contents)
200*333d2b36SAndroid Build Coastguard Worker		if err == nil {
201*333d2b36SAndroid Build Coastguard Worker			_, err = oz.addZipEntry(jar.ManifestFile, ZipEntryFromBuffer{fh, buf})
202*333d2b36SAndroid Build Coastguard Worker		}
203*333d2b36SAndroid Build Coastguard Worker	}
204*333d2b36SAndroid Build Coastguard Worker	return err
205*333d2b36SAndroid Build Coastguard Worker}
206*333d2b36SAndroid Build Coastguard Worker
207*333d2b36SAndroid Build Coastguard Worker// Adds an entry with given name and contents read from given file
208*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) addZipEntryFromFile(name string, path string) error {
209*333d2b36SAndroid Build Coastguard Worker	buf, err := ioutil.ReadFile(path)
210*333d2b36SAndroid Build Coastguard Worker	if err == nil {
211*333d2b36SAndroid Build Coastguard Worker		fh := &zip.FileHeader{
212*333d2b36SAndroid Build Coastguard Worker			Name:               name,
213*333d2b36SAndroid Build Coastguard Worker			Method:             zip.Store,
214*333d2b36SAndroid Build Coastguard Worker			UncompressedSize64: uint64(len(buf)),
215*333d2b36SAndroid Build Coastguard Worker		}
216*333d2b36SAndroid Build Coastguard Worker		fh.SetMode(0700)
217*333d2b36SAndroid Build Coastguard Worker		fh.SetModTime(jar.DefaultTime)
218*333d2b36SAndroid Build Coastguard Worker		_, err = oz.addZipEntry(name, ZipEntryFromBuffer{fh, buf})
219*333d2b36SAndroid Build Coastguard Worker	}
220*333d2b36SAndroid Build Coastguard Worker	return err
221*333d2b36SAndroid Build Coastguard Worker}
222*333d2b36SAndroid Build Coastguard Worker
223*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) addEmptyEntry(entry string) error {
224*333d2b36SAndroid Build Coastguard Worker	var emptyBuf []byte
225*333d2b36SAndroid Build Coastguard Worker	fh := &zip.FileHeader{
226*333d2b36SAndroid Build Coastguard Worker		Name:               entry,
227*333d2b36SAndroid Build Coastguard Worker		Method:             zip.Store,
228*333d2b36SAndroid Build Coastguard Worker		UncompressedSize64: uint64(len(emptyBuf)),
229*333d2b36SAndroid Build Coastguard Worker	}
230*333d2b36SAndroid Build Coastguard Worker	fh.SetMode(0700)
231*333d2b36SAndroid Build Coastguard Worker	fh.SetModTime(jar.DefaultTime)
232*333d2b36SAndroid Build Coastguard Worker	_, err := oz.addZipEntry(entry, ZipEntryFromBuffer{fh, emptyBuf})
233*333d2b36SAndroid Build Coastguard Worker	return err
234*333d2b36SAndroid Build Coastguard Worker}
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Worker// Returns true if given entry is to be excluded
237*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) isEntryExcluded(name string) bool {
238*333d2b36SAndroid Build Coastguard Worker	for _, dir := range oz.excludeDirs {
239*333d2b36SAndroid Build Coastguard Worker		dir = filepath.Clean(dir)
240*333d2b36SAndroid Build Coastguard Worker		patterns := []string{
241*333d2b36SAndroid Build Coastguard Worker			dir + "/",      // the directory itself
242*333d2b36SAndroid Build Coastguard Worker			dir + "/**/*",  // files recursively in the directory
243*333d2b36SAndroid Build Coastguard Worker			dir + "/**/*/", // directories recursively in the directory
244*333d2b36SAndroid Build Coastguard Worker		}
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Worker		for _, pattern := range patterns {
247*333d2b36SAndroid Build Coastguard Worker			match, err := pathtools.Match(pattern, name)
248*333d2b36SAndroid Build Coastguard Worker			if err != nil {
249*333d2b36SAndroid Build Coastguard Worker				panic(fmt.Errorf("%s: %s", err.Error(), pattern))
250*333d2b36SAndroid Build Coastguard Worker			}
251*333d2b36SAndroid Build Coastguard Worker			if match {
252*333d2b36SAndroid Build Coastguard Worker				if oz.emulateJar {
253*333d2b36SAndroid Build Coastguard Worker					// When merging jar files, don't strip META-INF/MANIFEST.MF even if stripping META-INF is
254*333d2b36SAndroid Build Coastguard Worker					// requested.
255*333d2b36SAndroid Build Coastguard Worker					// TODO(ccross): which files does this affect?
256*333d2b36SAndroid Build Coastguard Worker					if name != jar.MetaDir && name != jar.ManifestFile {
257*333d2b36SAndroid Build Coastguard Worker						return true
258*333d2b36SAndroid Build Coastguard Worker					}
259*333d2b36SAndroid Build Coastguard Worker				}
260*333d2b36SAndroid Build Coastguard Worker				return true
261*333d2b36SAndroid Build Coastguard Worker			}
262*333d2b36SAndroid Build Coastguard Worker		}
263*333d2b36SAndroid Build Coastguard Worker	}
264*333d2b36SAndroid Build Coastguard Worker
265*333d2b36SAndroid Build Coastguard Worker	for _, pattern := range oz.excludeFiles {
266*333d2b36SAndroid Build Coastguard Worker		match, err := pathtools.Match(pattern, name)
267*333d2b36SAndroid Build Coastguard Worker		if err != nil {
268*333d2b36SAndroid Build Coastguard Worker			panic(fmt.Errorf("%s: %s", err.Error(), pattern))
269*333d2b36SAndroid Build Coastguard Worker		}
270*333d2b36SAndroid Build Coastguard Worker		if match {
271*333d2b36SAndroid Build Coastguard Worker			return true
272*333d2b36SAndroid Build Coastguard Worker		}
273*333d2b36SAndroid Build Coastguard Worker	}
274*333d2b36SAndroid Build Coastguard Worker	return false
275*333d2b36SAndroid Build Coastguard Worker}
276*333d2b36SAndroid Build Coastguard Worker
277*333d2b36SAndroid Build Coastguard Worker// Creates a zip entry whose contents is an entry from the given input zip.
278*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) copyEntry(inputZip InputZip, index int) error {
279*333d2b36SAndroid Build Coastguard Worker	entry := NewZipEntryFromZip(inputZip, index)
280*333d2b36SAndroid Build Coastguard Worker	if oz.stripDirEntries && entry.IsDir() {
281*333d2b36SAndroid Build Coastguard Worker		return nil
282*333d2b36SAndroid Build Coastguard Worker	}
283*333d2b36SAndroid Build Coastguard Worker	existingEntry, err := oz.addZipEntry(entry.name, entry)
284*333d2b36SAndroid Build Coastguard Worker	if err != nil {
285*333d2b36SAndroid Build Coastguard Worker		return err
286*333d2b36SAndroid Build Coastguard Worker	}
287*333d2b36SAndroid Build Coastguard Worker	if existingEntry == nil {
288*333d2b36SAndroid Build Coastguard Worker		return nil
289*333d2b36SAndroid Build Coastguard Worker	}
290*333d2b36SAndroid Build Coastguard Worker
291*333d2b36SAndroid Build Coastguard Worker	// File types should match
292*333d2b36SAndroid Build Coastguard Worker	if existingEntry.IsDir() != entry.IsDir() {
293*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
294*333d2b36SAndroid Build Coastguard Worker			entry.name, existingEntry, entry)
295*333d2b36SAndroid Build Coastguard Worker	}
296*333d2b36SAndroid Build Coastguard Worker
297*333d2b36SAndroid Build Coastguard Worker	if oz.ignoreDuplicates ||
298*333d2b36SAndroid Build Coastguard Worker		// Skip manifest and module info files that are not from the first input file
299*333d2b36SAndroid Build Coastguard Worker		(oz.emulateJar && entry.name == jar.ManifestFile || entry.name == jar.ModuleInfoClass) ||
300*333d2b36SAndroid Build Coastguard Worker		// Identical entries
301*333d2b36SAndroid Build Coastguard Worker		(existingEntry.CRC32() == entry.CRC32() && existingEntry.Size() == entry.Size()) ||
302*333d2b36SAndroid Build Coastguard Worker		// Directory entries
303*333d2b36SAndroid Build Coastguard Worker		entry.IsDir() {
304*333d2b36SAndroid Build Coastguard Worker		return nil
305*333d2b36SAndroid Build Coastguard Worker	}
306*333d2b36SAndroid Build Coastguard Worker
307*333d2b36SAndroid Build Coastguard Worker	return fmt.Errorf("Duplicate path %v found in %v and %v\n", entry.name, existingEntry, inputZip.Name())
308*333d2b36SAndroid Build Coastguard Worker}
309*333d2b36SAndroid Build Coastguard Worker
310*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) entriesArray() []string {
311*333d2b36SAndroid Build Coastguard Worker	entries := make([]string, len(oz.sourceByDest))
312*333d2b36SAndroid Build Coastguard Worker	i := 0
313*333d2b36SAndroid Build Coastguard Worker	for entry := range oz.sourceByDest {
314*333d2b36SAndroid Build Coastguard Worker		entries[i] = entry
315*333d2b36SAndroid Build Coastguard Worker		i++
316*333d2b36SAndroid Build Coastguard Worker	}
317*333d2b36SAndroid Build Coastguard Worker	return entries
318*333d2b36SAndroid Build Coastguard Worker}
319*333d2b36SAndroid Build Coastguard Worker
320*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) jarSorted() []string {
321*333d2b36SAndroid Build Coastguard Worker	entries := oz.entriesArray()
322*333d2b36SAndroid Build Coastguard Worker	sort.SliceStable(entries, func(i, j int) bool { return jar.EntryNamesLess(entries[i], entries[j]) })
323*333d2b36SAndroid Build Coastguard Worker	return entries
324*333d2b36SAndroid Build Coastguard Worker}
325*333d2b36SAndroid Build Coastguard Worker
326*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) alphanumericSorted() []string {
327*333d2b36SAndroid Build Coastguard Worker	entries := oz.entriesArray()
328*333d2b36SAndroid Build Coastguard Worker	sort.Strings(entries)
329*333d2b36SAndroid Build Coastguard Worker	return entries
330*333d2b36SAndroid Build Coastguard Worker}
331*333d2b36SAndroid Build Coastguard Worker
332*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) writeEntries(entries []string) error {
333*333d2b36SAndroid Build Coastguard Worker	for _, entry := range entries {
334*333d2b36SAndroid Build Coastguard Worker		source, _ := oz.sourceByDest[entry]
335*333d2b36SAndroid Build Coastguard Worker		if err := source.WriteToZip(entry, oz.outputWriter); err != nil {
336*333d2b36SAndroid Build Coastguard Worker			return err
337*333d2b36SAndroid Build Coastguard Worker		}
338*333d2b36SAndroid Build Coastguard Worker	}
339*333d2b36SAndroid Build Coastguard Worker	return nil
340*333d2b36SAndroid Build Coastguard Worker}
341*333d2b36SAndroid Build Coastguard Worker
342*333d2b36SAndroid Build Coastguard Workerfunc (oz *OutputZip) getUninitializedPythonPackages(inputZips []InputZip) ([]string, error) {
343*333d2b36SAndroid Build Coastguard Worker	// the runfiles packages needs to be populated with "__init__.py".
344*333d2b36SAndroid Build Coastguard Worker	// the runfiles dirs have been treated as packages.
345*333d2b36SAndroid Build Coastguard Worker	var allPackages []string // Using a slice to preserve input order.
346*333d2b36SAndroid Build Coastguard Worker	seenPkgs := make(map[string]bool)
347*333d2b36SAndroid Build Coastguard Worker	initedPackages := make(map[string]bool)
348*333d2b36SAndroid Build Coastguard Worker	getPackage := func(path string) string {
349*333d2b36SAndroid Build Coastguard Worker		ret := filepath.Dir(path)
350*333d2b36SAndroid Build Coastguard Worker		// filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/".
351*333d2b36SAndroid Build Coastguard Worker		if ret == "." || ret == "/" {
352*333d2b36SAndroid Build Coastguard Worker			return ""
353*333d2b36SAndroid Build Coastguard Worker		}
354*333d2b36SAndroid Build Coastguard Worker		return ret
355*333d2b36SAndroid Build Coastguard Worker	}
356*333d2b36SAndroid Build Coastguard Worker
357*333d2b36SAndroid Build Coastguard Worker	// put existing __init__.py files to a set first. This set is used for preventing
358*333d2b36SAndroid Build Coastguard Worker	// generated __init__.py files from overwriting existing ones.
359*333d2b36SAndroid Build Coastguard Worker	for _, inputZip := range inputZips {
360*333d2b36SAndroid Build Coastguard Worker		if err := inputZip.Open(); err != nil {
361*333d2b36SAndroid Build Coastguard Worker			return nil, err
362*333d2b36SAndroid Build Coastguard Worker		}
363*333d2b36SAndroid Build Coastguard Worker		for _, file := range inputZip.Entries() {
364*333d2b36SAndroid Build Coastguard Worker			pyPkg := getPackage(file.Name)
365*333d2b36SAndroid Build Coastguard Worker			baseName := filepath.Base(file.Name)
366*333d2b36SAndroid Build Coastguard Worker			if baseName == "__init__.py" || baseName == "__init__.pyc" {
367*333d2b36SAndroid Build Coastguard Worker				if _, found := initedPackages[pyPkg]; found {
368*333d2b36SAndroid Build Coastguard Worker					panic(fmt.Errorf("found __init__.py path duplicates during pars merging: %q", file.Name))
369*333d2b36SAndroid Build Coastguard Worker				}
370*333d2b36SAndroid Build Coastguard Worker				initedPackages[pyPkg] = true
371*333d2b36SAndroid Build Coastguard Worker			}
372*333d2b36SAndroid Build Coastguard Worker			for pyPkg != "" {
373*333d2b36SAndroid Build Coastguard Worker				if _, found := seenPkgs[pyPkg]; found {
374*333d2b36SAndroid Build Coastguard Worker					break
375*333d2b36SAndroid Build Coastguard Worker				}
376*333d2b36SAndroid Build Coastguard Worker				seenPkgs[pyPkg] = true
377*333d2b36SAndroid Build Coastguard Worker				allPackages = append(allPackages, pyPkg)
378*333d2b36SAndroid Build Coastguard Worker				pyPkg = getPackage(pyPkg)
379*333d2b36SAndroid Build Coastguard Worker			}
380*333d2b36SAndroid Build Coastguard Worker		}
381*333d2b36SAndroid Build Coastguard Worker	}
382*333d2b36SAndroid Build Coastguard Worker	noInitPackages := make([]string, 0)
383*333d2b36SAndroid Build Coastguard Worker	for _, pyPkg := range allPackages {
384*333d2b36SAndroid Build Coastguard Worker		if _, found := initedPackages[pyPkg]; !found {
385*333d2b36SAndroid Build Coastguard Worker			noInitPackages = append(noInitPackages, pyPkg)
386*333d2b36SAndroid Build Coastguard Worker		}
387*333d2b36SAndroid Build Coastguard Worker	}
388*333d2b36SAndroid Build Coastguard Worker	return noInitPackages, nil
389*333d2b36SAndroid Build Coastguard Worker}
390*333d2b36SAndroid Build Coastguard Worker
391*333d2b36SAndroid Build Coastguard Worker// An InputZip owned by the InputZipsManager. Opened ManagedInputZip's are chained in the open order.
392*333d2b36SAndroid Build Coastguard Workertype ManagedInputZip struct {
393*333d2b36SAndroid Build Coastguard Worker	owner        *InputZipsManager
394*333d2b36SAndroid Build Coastguard Worker	realInputZip InputZip
395*333d2b36SAndroid Build Coastguard Worker	older        *ManagedInputZip
396*333d2b36SAndroid Build Coastguard Worker	newer        *ManagedInputZip
397*333d2b36SAndroid Build Coastguard Worker}
398*333d2b36SAndroid Build Coastguard Worker
399*333d2b36SAndroid Build Coastguard Worker// Maintains the array of ManagedInputZips, keeping track of open input ones. When an InputZip is opened,
400*333d2b36SAndroid Build Coastguard Worker// may close some other InputZip to limit the number of open ones.
401*333d2b36SAndroid Build Coastguard Workertype InputZipsManager struct {
402*333d2b36SAndroid Build Coastguard Worker	inputZips     []*ManagedInputZip
403*333d2b36SAndroid Build Coastguard Worker	nOpenZips     int
404*333d2b36SAndroid Build Coastguard Worker	maxOpenZips   int
405*333d2b36SAndroid Build Coastguard Worker	openInputZips *ManagedInputZip
406*333d2b36SAndroid Build Coastguard Worker}
407*333d2b36SAndroid Build Coastguard Worker
408*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) unlink() {
409*333d2b36SAndroid Build Coastguard Worker	olderMiz := miz.older
410*333d2b36SAndroid Build Coastguard Worker	newerMiz := miz.newer
411*333d2b36SAndroid Build Coastguard Worker	if newerMiz.older != miz || olderMiz.newer != miz {
412*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("removing %p:%#v: broken list between %p:%#v and %p:%#v",
413*333d2b36SAndroid Build Coastguard Worker			miz, miz, newerMiz, newerMiz, olderMiz, olderMiz))
414*333d2b36SAndroid Build Coastguard Worker	}
415*333d2b36SAndroid Build Coastguard Worker	olderMiz.newer = newerMiz
416*333d2b36SAndroid Build Coastguard Worker	newerMiz.older = olderMiz
417*333d2b36SAndroid Build Coastguard Worker	miz.newer = nil
418*333d2b36SAndroid Build Coastguard Worker	miz.older = nil
419*333d2b36SAndroid Build Coastguard Worker}
420*333d2b36SAndroid Build Coastguard Worker
421*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) link(olderMiz *ManagedInputZip) {
422*333d2b36SAndroid Build Coastguard Worker	if olderMiz.newer != nil || olderMiz.older != nil {
423*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("inputZip is already open"))
424*333d2b36SAndroid Build Coastguard Worker	}
425*333d2b36SAndroid Build Coastguard Worker	oldOlderMiz := miz.older
426*333d2b36SAndroid Build Coastguard Worker	if oldOlderMiz.newer != miz {
427*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("broken list between %p:%#v and %p:%#v", miz, miz, oldOlderMiz, oldOlderMiz))
428*333d2b36SAndroid Build Coastguard Worker	}
429*333d2b36SAndroid Build Coastguard Worker	miz.older = olderMiz
430*333d2b36SAndroid Build Coastguard Worker	olderMiz.older = oldOlderMiz
431*333d2b36SAndroid Build Coastguard Worker	oldOlderMiz.newer = olderMiz
432*333d2b36SAndroid Build Coastguard Worker	olderMiz.newer = miz
433*333d2b36SAndroid Build Coastguard Worker}
434*333d2b36SAndroid Build Coastguard Worker
435*333d2b36SAndroid Build Coastguard Workerfunc NewInputZipsManager(nInputZips, maxOpenZips int) *InputZipsManager {
436*333d2b36SAndroid Build Coastguard Worker	if maxOpenZips < 3 {
437*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("open zips limit should be above 3"))
438*333d2b36SAndroid Build Coastguard Worker	}
439*333d2b36SAndroid Build Coastguard Worker	// In the fake element .older points to the most recently opened InputZip, and .newer points to the oldest.
440*333d2b36SAndroid Build Coastguard Worker	head := new(ManagedInputZip)
441*333d2b36SAndroid Build Coastguard Worker	head.older = head
442*333d2b36SAndroid Build Coastguard Worker	head.newer = head
443*333d2b36SAndroid Build Coastguard Worker	return &InputZipsManager{
444*333d2b36SAndroid Build Coastguard Worker		inputZips:     make([]*ManagedInputZip, 0, nInputZips),
445*333d2b36SAndroid Build Coastguard Worker		maxOpenZips:   maxOpenZips,
446*333d2b36SAndroid Build Coastguard Worker		openInputZips: head,
447*333d2b36SAndroid Build Coastguard Worker	}
448*333d2b36SAndroid Build Coastguard Worker}
449*333d2b36SAndroid Build Coastguard Worker
450*333d2b36SAndroid Build Coastguard Worker// InputZip factory
451*333d2b36SAndroid Build Coastguard Workerfunc (izm *InputZipsManager) Manage(inz InputZip) InputZip {
452*333d2b36SAndroid Build Coastguard Worker	iz := &ManagedInputZip{owner: izm, realInputZip: inz}
453*333d2b36SAndroid Build Coastguard Worker	izm.inputZips = append(izm.inputZips, iz)
454*333d2b36SAndroid Build Coastguard Worker	return iz
455*333d2b36SAndroid Build Coastguard Worker}
456*333d2b36SAndroid Build Coastguard Worker
457*333d2b36SAndroid Build Coastguard Worker// Opens or reopens ManagedInputZip.
458*333d2b36SAndroid Build Coastguard Workerfunc (izm *InputZipsManager) reopen(miz *ManagedInputZip) error {
459*333d2b36SAndroid Build Coastguard Worker	if miz.realInputZip.IsOpen() {
460*333d2b36SAndroid Build Coastguard Worker		if miz != izm.openInputZips {
461*333d2b36SAndroid Build Coastguard Worker			miz.unlink()
462*333d2b36SAndroid Build Coastguard Worker			izm.openInputZips.link(miz)
463*333d2b36SAndroid Build Coastguard Worker		}
464*333d2b36SAndroid Build Coastguard Worker		return nil
465*333d2b36SAndroid Build Coastguard Worker	}
466*333d2b36SAndroid Build Coastguard Worker	if izm.nOpenZips >= izm.maxOpenZips {
467*333d2b36SAndroid Build Coastguard Worker		if err := izm.close(izm.openInputZips.older); err != nil {
468*333d2b36SAndroid Build Coastguard Worker			return err
469*333d2b36SAndroid Build Coastguard Worker		}
470*333d2b36SAndroid Build Coastguard Worker	}
471*333d2b36SAndroid Build Coastguard Worker	if err := miz.realInputZip.Open(); err != nil {
472*333d2b36SAndroid Build Coastguard Worker		return err
473*333d2b36SAndroid Build Coastguard Worker	}
474*333d2b36SAndroid Build Coastguard Worker	izm.openInputZips.link(miz)
475*333d2b36SAndroid Build Coastguard Worker	izm.nOpenZips++
476*333d2b36SAndroid Build Coastguard Worker	return nil
477*333d2b36SAndroid Build Coastguard Worker}
478*333d2b36SAndroid Build Coastguard Worker
479*333d2b36SAndroid Build Coastguard Workerfunc (izm *InputZipsManager) close(miz *ManagedInputZip) error {
480*333d2b36SAndroid Build Coastguard Worker	if miz.IsOpen() {
481*333d2b36SAndroid Build Coastguard Worker		err := miz.realInputZip.Close()
482*333d2b36SAndroid Build Coastguard Worker		izm.nOpenZips--
483*333d2b36SAndroid Build Coastguard Worker		miz.unlink()
484*333d2b36SAndroid Build Coastguard Worker		return err
485*333d2b36SAndroid Build Coastguard Worker	}
486*333d2b36SAndroid Build Coastguard Worker	return nil
487*333d2b36SAndroid Build Coastguard Worker}
488*333d2b36SAndroid Build Coastguard Worker
489*333d2b36SAndroid Build Coastguard Worker// Checks that openInputZips deque is valid
490*333d2b36SAndroid Build Coastguard Workerfunc (izm *InputZipsManager) checkOpenZipsDeque() {
491*333d2b36SAndroid Build Coastguard Worker	nReallyOpen := 0
492*333d2b36SAndroid Build Coastguard Worker	el := izm.openInputZips
493*333d2b36SAndroid Build Coastguard Worker	for {
494*333d2b36SAndroid Build Coastguard Worker		elNext := el.older
495*333d2b36SAndroid Build Coastguard Worker		if elNext.newer != el {
496*333d2b36SAndroid Build Coastguard Worker			panic(fmt.Errorf("Element:\n  %p: %v\nNext:\n  %p %v", el, el, elNext, elNext))
497*333d2b36SAndroid Build Coastguard Worker		}
498*333d2b36SAndroid Build Coastguard Worker		if elNext == izm.openInputZips {
499*333d2b36SAndroid Build Coastguard Worker			break
500*333d2b36SAndroid Build Coastguard Worker		}
501*333d2b36SAndroid Build Coastguard Worker		el = elNext
502*333d2b36SAndroid Build Coastguard Worker		if !el.IsOpen() {
503*333d2b36SAndroid Build Coastguard Worker			panic(fmt.Errorf("Found unopened element"))
504*333d2b36SAndroid Build Coastguard Worker		}
505*333d2b36SAndroid Build Coastguard Worker		nReallyOpen++
506*333d2b36SAndroid Build Coastguard Worker		if nReallyOpen > izm.nOpenZips {
507*333d2b36SAndroid Build Coastguard Worker			panic(fmt.Errorf("found %d open zips, should be %d", nReallyOpen, izm.nOpenZips))
508*333d2b36SAndroid Build Coastguard Worker		}
509*333d2b36SAndroid Build Coastguard Worker	}
510*333d2b36SAndroid Build Coastguard Worker	if nReallyOpen > izm.nOpenZips {
511*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("found %d open zips, should be %d", nReallyOpen, izm.nOpenZips))
512*333d2b36SAndroid Build Coastguard Worker	}
513*333d2b36SAndroid Build Coastguard Worker}
514*333d2b36SAndroid Build Coastguard Worker
515*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) Name() string {
516*333d2b36SAndroid Build Coastguard Worker	return miz.realInputZip.Name()
517*333d2b36SAndroid Build Coastguard Worker}
518*333d2b36SAndroid Build Coastguard Worker
519*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) Open() error {
520*333d2b36SAndroid Build Coastguard Worker	return miz.owner.reopen(miz)
521*333d2b36SAndroid Build Coastguard Worker}
522*333d2b36SAndroid Build Coastguard Worker
523*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) Close() error {
524*333d2b36SAndroid Build Coastguard Worker	return miz.owner.close(miz)
525*333d2b36SAndroid Build Coastguard Worker}
526*333d2b36SAndroid Build Coastguard Worker
527*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) IsOpen() bool {
528*333d2b36SAndroid Build Coastguard Worker	return miz.realInputZip.IsOpen()
529*333d2b36SAndroid Build Coastguard Worker}
530*333d2b36SAndroid Build Coastguard Worker
531*333d2b36SAndroid Build Coastguard Workerfunc (miz *ManagedInputZip) Entries() []*zip.File {
532*333d2b36SAndroid Build Coastguard Worker	if !miz.IsOpen() {
533*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("%s: is not open", miz.Name()))
534*333d2b36SAndroid Build Coastguard Worker	}
535*333d2b36SAndroid Build Coastguard Worker	return miz.realInputZip.Entries()
536*333d2b36SAndroid Build Coastguard Worker}
537*333d2b36SAndroid Build Coastguard Worker
538*333d2b36SAndroid Build Coastguard Worker// Actual processing.
539*333d2b36SAndroid Build Coastguard Workerfunc mergeZips(inputZips []InputZip, writer *zip.Writer, manifest, pyMain string,
540*333d2b36SAndroid Build Coastguard Worker	sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool,
541*333d2b36SAndroid Build Coastguard Worker	excludeFiles, excludeDirs []string, zipsToNotStrip map[string]bool) error {
542*333d2b36SAndroid Build Coastguard Worker
543*333d2b36SAndroid Build Coastguard Worker	out := NewOutputZip(writer, sortEntries, emulateJar, stripDirEntries, ignoreDuplicates)
544*333d2b36SAndroid Build Coastguard Worker	out.setExcludeFiles(excludeFiles)
545*333d2b36SAndroid Build Coastguard Worker	out.setExcludeDirs(excludeDirs)
546*333d2b36SAndroid Build Coastguard Worker	if manifest != "" {
547*333d2b36SAndroid Build Coastguard Worker		if err := out.addManifest(manifest); err != nil {
548*333d2b36SAndroid Build Coastguard Worker			return err
549*333d2b36SAndroid Build Coastguard Worker		}
550*333d2b36SAndroid Build Coastguard Worker	}
551*333d2b36SAndroid Build Coastguard Worker	if pyMain != "" {
552*333d2b36SAndroid Build Coastguard Worker		if err := out.addZipEntryFromFile("__main__.py", pyMain); err != nil {
553*333d2b36SAndroid Build Coastguard Worker			return err
554*333d2b36SAndroid Build Coastguard Worker		}
555*333d2b36SAndroid Build Coastguard Worker	}
556*333d2b36SAndroid Build Coastguard Worker
557*333d2b36SAndroid Build Coastguard Worker	if emulatePar {
558*333d2b36SAndroid Build Coastguard Worker		noInitPackages, err := out.getUninitializedPythonPackages(inputZips)
559*333d2b36SAndroid Build Coastguard Worker		if err != nil {
560*333d2b36SAndroid Build Coastguard Worker			return err
561*333d2b36SAndroid Build Coastguard Worker		}
562*333d2b36SAndroid Build Coastguard Worker		for _, uninitializedPyPackage := range noInitPackages {
563*333d2b36SAndroid Build Coastguard Worker			if err = out.addEmptyEntry(filepath.Join(uninitializedPyPackage, "__init__.py")); err != nil {
564*333d2b36SAndroid Build Coastguard Worker				return err
565*333d2b36SAndroid Build Coastguard Worker			}
566*333d2b36SAndroid Build Coastguard Worker		}
567*333d2b36SAndroid Build Coastguard Worker	}
568*333d2b36SAndroid Build Coastguard Worker
569*333d2b36SAndroid Build Coastguard Worker	var jarServices jar.Services
570*333d2b36SAndroid Build Coastguard Worker
571*333d2b36SAndroid Build Coastguard Worker	// Finally, add entries from all the input zips.
572*333d2b36SAndroid Build Coastguard Worker	for _, inputZip := range inputZips {
573*333d2b36SAndroid Build Coastguard Worker		_, copyFully := zipsToNotStrip[inputZip.Name()]
574*333d2b36SAndroid Build Coastguard Worker		if err := inputZip.Open(); err != nil {
575*333d2b36SAndroid Build Coastguard Worker			return err
576*333d2b36SAndroid Build Coastguard Worker		}
577*333d2b36SAndroid Build Coastguard Worker
578*333d2b36SAndroid Build Coastguard Worker		for i, entry := range inputZip.Entries() {
579*333d2b36SAndroid Build Coastguard Worker			if emulateJar && jarServices.IsServiceFile(entry) {
580*333d2b36SAndroid Build Coastguard Worker				// If this is a jar, collect service files to combine  instead of adding them to the zip.
581*333d2b36SAndroid Build Coastguard Worker				err := jarServices.AddServiceFile(entry)
582*333d2b36SAndroid Build Coastguard Worker				if err != nil {
583*333d2b36SAndroid Build Coastguard Worker					return err
584*333d2b36SAndroid Build Coastguard Worker				}
585*333d2b36SAndroid Build Coastguard Worker				continue
586*333d2b36SAndroid Build Coastguard Worker			}
587*333d2b36SAndroid Build Coastguard Worker			if copyFully || !out.isEntryExcluded(entry.Name) {
588*333d2b36SAndroid Build Coastguard Worker				if err := out.copyEntry(inputZip, i); err != nil {
589*333d2b36SAndroid Build Coastguard Worker					return err
590*333d2b36SAndroid Build Coastguard Worker				}
591*333d2b36SAndroid Build Coastguard Worker			}
592*333d2b36SAndroid Build Coastguard Worker		}
593*333d2b36SAndroid Build Coastguard Worker		// Unless we need to rearrange the entries, the input zip can now be closed.
594*333d2b36SAndroid Build Coastguard Worker		if !(emulateJar || sortEntries) {
595*333d2b36SAndroid Build Coastguard Worker			if err := inputZip.Close(); err != nil {
596*333d2b36SAndroid Build Coastguard Worker				return err
597*333d2b36SAndroid Build Coastguard Worker			}
598*333d2b36SAndroid Build Coastguard Worker		}
599*333d2b36SAndroid Build Coastguard Worker	}
600*333d2b36SAndroid Build Coastguard Worker
601*333d2b36SAndroid Build Coastguard Worker	if emulateJar {
602*333d2b36SAndroid Build Coastguard Worker		// Combine all the service files into a single list of combined service files and add them to the zip.
603*333d2b36SAndroid Build Coastguard Worker		for _, serviceFile := range jarServices.ServiceFiles() {
604*333d2b36SAndroid Build Coastguard Worker			_, err := out.addZipEntry(serviceFile.Name, ZipEntryFromBuffer{
605*333d2b36SAndroid Build Coastguard Worker				fh:      serviceFile.FileHeader,
606*333d2b36SAndroid Build Coastguard Worker				content: serviceFile.Contents,
607*333d2b36SAndroid Build Coastguard Worker			})
608*333d2b36SAndroid Build Coastguard Worker			if err != nil {
609*333d2b36SAndroid Build Coastguard Worker				return err
610*333d2b36SAndroid Build Coastguard Worker			}
611*333d2b36SAndroid Build Coastguard Worker		}
612*333d2b36SAndroid Build Coastguard Worker		return out.writeEntries(out.jarSorted())
613*333d2b36SAndroid Build Coastguard Worker	} else if sortEntries {
614*333d2b36SAndroid Build Coastguard Worker		return out.writeEntries(out.alphanumericSorted())
615*333d2b36SAndroid Build Coastguard Worker	}
616*333d2b36SAndroid Build Coastguard Worker	return nil
617*333d2b36SAndroid Build Coastguard Worker}
618*333d2b36SAndroid Build Coastguard Worker
619*333d2b36SAndroid Build Coastguard Worker// Process command line
620*333d2b36SAndroid Build Coastguard Workertype fileList []string
621*333d2b36SAndroid Build Coastguard Worker
622*333d2b36SAndroid Build Coastguard Workerfunc (f *fileList) String() string {
623*333d2b36SAndroid Build Coastguard Worker	return `""`
624*333d2b36SAndroid Build Coastguard Worker}
625*333d2b36SAndroid Build Coastguard Worker
626*333d2b36SAndroid Build Coastguard Workerfunc (f *fileList) Set(name string) error {
627*333d2b36SAndroid Build Coastguard Worker	*f = append(*f, filepath.Clean(name))
628*333d2b36SAndroid Build Coastguard Worker
629*333d2b36SAndroid Build Coastguard Worker	return nil
630*333d2b36SAndroid Build Coastguard Worker}
631*333d2b36SAndroid Build Coastguard Worker
632*333d2b36SAndroid Build Coastguard Workertype zipsToNotStripSet map[string]bool
633*333d2b36SAndroid Build Coastguard Worker
634*333d2b36SAndroid Build Coastguard Workerfunc (s zipsToNotStripSet) String() string {
635*333d2b36SAndroid Build Coastguard Worker	return `""`
636*333d2b36SAndroid Build Coastguard Worker}
637*333d2b36SAndroid Build Coastguard Worker
638*333d2b36SAndroid Build Coastguard Workerfunc (s zipsToNotStripSet) Set(path string) error {
639*333d2b36SAndroid Build Coastguard Worker	s[path] = true
640*333d2b36SAndroid Build Coastguard Worker	return nil
641*333d2b36SAndroid Build Coastguard Worker}
642*333d2b36SAndroid Build Coastguard Worker
643*333d2b36SAndroid Build Coastguard Workervar (
644*333d2b36SAndroid Build Coastguard Worker	sortEntries      = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
645*333d2b36SAndroid Build Coastguard Worker	emulateJar       = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
646*333d2b36SAndroid Build Coastguard Worker	emulatePar       = flag.Bool("p", false, "merge zip entries based on par format")
647*333d2b36SAndroid Build Coastguard Worker	excludeDirs      fileList
648*333d2b36SAndroid Build Coastguard Worker	excludeFiles     fileList
649*333d2b36SAndroid Build Coastguard Worker	zipsToNotStrip   = make(zipsToNotStripSet)
650*333d2b36SAndroid Build Coastguard Worker	stripDirEntries  = flag.Bool("D", false, "strip directory entries from the output zip file")
651*333d2b36SAndroid Build Coastguard Worker	manifest         = flag.String("m", "", "manifest file to insert in jar")
652*333d2b36SAndroid Build Coastguard Worker	pyMain           = flag.String("pm", "", "__main__.py file to insert in par")
653*333d2b36SAndroid Build Coastguard Worker	prefix           = flag.String("prefix", "", "A file to prefix to the zip file")
654*333d2b36SAndroid Build Coastguard Worker	ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
655*333d2b36SAndroid Build Coastguard Worker)
656*333d2b36SAndroid Build Coastguard Worker
657*333d2b36SAndroid Build Coastguard Workerfunc init() {
658*333d2b36SAndroid Build Coastguard Worker	flag.Var(&excludeDirs, "stripDir", "directories to be excluded from the output zip, accepts wildcards")
659*333d2b36SAndroid Build Coastguard Worker	flag.Var(&excludeFiles, "stripFile", "files to be excluded from the output zip, accepts wildcards")
660*333d2b36SAndroid Build Coastguard Worker	flag.Var(&zipsToNotStrip, "zipToNotStrip", "the input zip file which is not applicable for stripping")
661*333d2b36SAndroid Build Coastguard Worker}
662*333d2b36SAndroid Build Coastguard Worker
663*333d2b36SAndroid Build Coastguard Workertype FileInputZip struct {
664*333d2b36SAndroid Build Coastguard Worker	name   string
665*333d2b36SAndroid Build Coastguard Worker	reader *zip.ReadCloser
666*333d2b36SAndroid Build Coastguard Worker}
667*333d2b36SAndroid Build Coastguard Worker
668*333d2b36SAndroid Build Coastguard Workerfunc (fiz *FileInputZip) Name() string {
669*333d2b36SAndroid Build Coastguard Worker	return fiz.name
670*333d2b36SAndroid Build Coastguard Worker}
671*333d2b36SAndroid Build Coastguard Worker
672*333d2b36SAndroid Build Coastguard Workerfunc (fiz *FileInputZip) Close() error {
673*333d2b36SAndroid Build Coastguard Worker	if fiz.IsOpen() {
674*333d2b36SAndroid Build Coastguard Worker		reader := fiz.reader
675*333d2b36SAndroid Build Coastguard Worker		fiz.reader = nil
676*333d2b36SAndroid Build Coastguard Worker		return reader.Close()
677*333d2b36SAndroid Build Coastguard Worker	}
678*333d2b36SAndroid Build Coastguard Worker	return nil
679*333d2b36SAndroid Build Coastguard Worker}
680*333d2b36SAndroid Build Coastguard Worker
681*333d2b36SAndroid Build Coastguard Workerfunc (fiz *FileInputZip) Entries() []*zip.File {
682*333d2b36SAndroid Build Coastguard Worker	if !fiz.IsOpen() {
683*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("%s: is not open", fiz.Name()))
684*333d2b36SAndroid Build Coastguard Worker	}
685*333d2b36SAndroid Build Coastguard Worker	return fiz.reader.File
686*333d2b36SAndroid Build Coastguard Worker}
687*333d2b36SAndroid Build Coastguard Worker
688*333d2b36SAndroid Build Coastguard Workerfunc (fiz *FileInputZip) IsOpen() bool {
689*333d2b36SAndroid Build Coastguard Worker	return fiz.reader != nil
690*333d2b36SAndroid Build Coastguard Worker}
691*333d2b36SAndroid Build Coastguard Worker
692*333d2b36SAndroid Build Coastguard Workerfunc (fiz *FileInputZip) Open() error {
693*333d2b36SAndroid Build Coastguard Worker	if fiz.IsOpen() {
694*333d2b36SAndroid Build Coastguard Worker		return nil
695*333d2b36SAndroid Build Coastguard Worker	}
696*333d2b36SAndroid Build Coastguard Worker	var err error
697*333d2b36SAndroid Build Coastguard Worker	if fiz.reader, err = zip.OpenReader(fiz.Name()); err != nil {
698*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("%s: %s", fiz.Name(), err.Error())
699*333d2b36SAndroid Build Coastguard Worker	}
700*333d2b36SAndroid Build Coastguard Worker	return nil
701*333d2b36SAndroid Build Coastguard Worker}
702*333d2b36SAndroid Build Coastguard Worker
703*333d2b36SAndroid Build Coastguard Workerfunc main() {
704*333d2b36SAndroid Build Coastguard Worker	flag.Usage = func() {
705*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [--prefix script] [-pm __main__.py] OutputZip [inputs...]")
706*333d2b36SAndroid Build Coastguard Worker		flag.PrintDefaults()
707*333d2b36SAndroid Build Coastguard Worker	}
708*333d2b36SAndroid Build Coastguard Worker
709*333d2b36SAndroid Build Coastguard Worker	// parse args
710*333d2b36SAndroid Build Coastguard Worker	flag.Parse()
711*333d2b36SAndroid Build Coastguard Worker	args := flag.Args()
712*333d2b36SAndroid Build Coastguard Worker	if len(args) < 1 {
713*333d2b36SAndroid Build Coastguard Worker		flag.Usage()
714*333d2b36SAndroid Build Coastguard Worker		os.Exit(1)
715*333d2b36SAndroid Build Coastguard Worker	}
716*333d2b36SAndroid Build Coastguard Worker	outputPath := args[0]
717*333d2b36SAndroid Build Coastguard Worker	inputs := make([]string, 0)
718*333d2b36SAndroid Build Coastguard Worker	for _, input := range args[1:] {
719*333d2b36SAndroid Build Coastguard Worker		if input[0] == '@' {
720*333d2b36SAndroid Build Coastguard Worker			f, err := os.Open(strings.TrimPrefix(input[1:], "@"))
721*333d2b36SAndroid Build Coastguard Worker			if err != nil {
722*333d2b36SAndroid Build Coastguard Worker				log.Fatal(err)
723*333d2b36SAndroid Build Coastguard Worker			}
724*333d2b36SAndroid Build Coastguard Worker
725*333d2b36SAndroid Build Coastguard Worker			rspInputs, err := response.ReadRspFile(f)
726*333d2b36SAndroid Build Coastguard Worker			f.Close()
727*333d2b36SAndroid Build Coastguard Worker			if err != nil {
728*333d2b36SAndroid Build Coastguard Worker				log.Fatal(err)
729*333d2b36SAndroid Build Coastguard Worker			}
730*333d2b36SAndroid Build Coastguard Worker			inputs = append(inputs, rspInputs...)
731*333d2b36SAndroid Build Coastguard Worker		} else {
732*333d2b36SAndroid Build Coastguard Worker			inputs = append(inputs, input)
733*333d2b36SAndroid Build Coastguard Worker		}
734*333d2b36SAndroid Build Coastguard Worker	}
735*333d2b36SAndroid Build Coastguard Worker
736*333d2b36SAndroid Build Coastguard Worker	log.SetFlags(log.Lshortfile)
737*333d2b36SAndroid Build Coastguard Worker
738*333d2b36SAndroid Build Coastguard Worker	// make writer
739*333d2b36SAndroid Build Coastguard Worker	outputZip, err := os.Create(outputPath)
740*333d2b36SAndroid Build Coastguard Worker	if err != nil {
741*333d2b36SAndroid Build Coastguard Worker		log.Fatal(err)
742*333d2b36SAndroid Build Coastguard Worker	}
743*333d2b36SAndroid Build Coastguard Worker	defer outputZip.Close()
744*333d2b36SAndroid Build Coastguard Worker
745*333d2b36SAndroid Build Coastguard Worker	var offset int64
746*333d2b36SAndroid Build Coastguard Worker	if *prefix != "" {
747*333d2b36SAndroid Build Coastguard Worker		prefixFile, err := os.Open(*prefix)
748*333d2b36SAndroid Build Coastguard Worker		if err != nil {
749*333d2b36SAndroid Build Coastguard Worker			log.Fatal(err)
750*333d2b36SAndroid Build Coastguard Worker		}
751*333d2b36SAndroid Build Coastguard Worker		offset, err = io.Copy(outputZip, prefixFile)
752*333d2b36SAndroid Build Coastguard Worker		if err != nil {
753*333d2b36SAndroid Build Coastguard Worker			log.Fatal(err)
754*333d2b36SAndroid Build Coastguard Worker		}
755*333d2b36SAndroid Build Coastguard Worker	}
756*333d2b36SAndroid Build Coastguard Worker
757*333d2b36SAndroid Build Coastguard Worker	writer := zip.NewWriter(outputZip)
758*333d2b36SAndroid Build Coastguard Worker	defer func() {
759*333d2b36SAndroid Build Coastguard Worker		err := writer.Close()
760*333d2b36SAndroid Build Coastguard Worker		if err != nil {
761*333d2b36SAndroid Build Coastguard Worker			log.Fatal(err)
762*333d2b36SAndroid Build Coastguard Worker		}
763*333d2b36SAndroid Build Coastguard Worker	}()
764*333d2b36SAndroid Build Coastguard Worker	writer.SetOffset(offset)
765*333d2b36SAndroid Build Coastguard Worker
766*333d2b36SAndroid Build Coastguard Worker	if *manifest != "" && !*emulateJar {
767*333d2b36SAndroid Build Coastguard Worker		log.Fatal(errors.New("must specify -j when specifying a manifest via -m"))
768*333d2b36SAndroid Build Coastguard Worker	}
769*333d2b36SAndroid Build Coastguard Worker
770*333d2b36SAndroid Build Coastguard Worker	if *pyMain != "" && !*emulatePar {
771*333d2b36SAndroid Build Coastguard Worker		log.Fatal(errors.New("must specify -p when specifying a Python __main__.py via -pm"))
772*333d2b36SAndroid Build Coastguard Worker	}
773*333d2b36SAndroid Build Coastguard Worker
774*333d2b36SAndroid Build Coastguard Worker	// do merge
775*333d2b36SAndroid Build Coastguard Worker	inputZipsManager := NewInputZipsManager(len(inputs), 1000)
776*333d2b36SAndroid Build Coastguard Worker	inputZips := make([]InputZip, len(inputs))
777*333d2b36SAndroid Build Coastguard Worker	for i, input := range inputs {
778*333d2b36SAndroid Build Coastguard Worker		inputZips[i] = inputZipsManager.Manage(&FileInputZip{name: input})
779*333d2b36SAndroid Build Coastguard Worker	}
780*333d2b36SAndroid Build Coastguard Worker	err = mergeZips(inputZips, writer, *manifest, *pyMain, *sortEntries, *emulateJar, *emulatePar,
781*333d2b36SAndroid Build Coastguard Worker		*stripDirEntries, *ignoreDuplicates, []string(excludeFiles), []string(excludeDirs),
782*333d2b36SAndroid Build Coastguard Worker		map[string]bool(zipsToNotStrip))
783*333d2b36SAndroid Build Coastguard Worker	if err != nil {
784*333d2b36SAndroid Build Coastguard Worker		log.Fatal(err)
785*333d2b36SAndroid Build Coastguard Worker	}
786*333d2b36SAndroid Build Coastguard Worker}
787