Add a --sort_entries flag to soong_zip

I want to build zips that can be diffed against each other easily.
Add a --sort_entries flag so that you don't need to write the flags
in the same order each time.

Bug: 376539388
Test: Manually
Change-Id: Ic7b6b9d1755abffdb609068712d68dc6c1bb6761
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index 37537ab..831f6d4 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -164,6 +164,7 @@
 	directories := flags.Bool("d", false, "include directories in zip")
 	compLevel := flags.Int("L", 5, "deflate compression level (0-9)")
 	emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
+	sortEntries := flags.Bool("sort_entries", false, "sort the zip entries")
 	writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
 	ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist")
 	symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them")
@@ -228,6 +229,7 @@
 		FileArgs:                 fileArgsBuilder.FileArgs(),
 		OutputFilePath:           *out,
 		EmulateJar:               *emulateJar,
+		SortEntries:              *sortEntries,
 		SrcJar:                   *srcJar,
 		AddDirectoryEntriesToZip: *directories,
 		CompressionLevel:         *compLevel,
diff --git a/zip/zip.go b/zip/zip.go
index f91a5f2..e4e9585 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -272,6 +272,7 @@
 	FileArgs                 []FileArg
 	OutputFilePath           string
 	EmulateJar               bool
+	SortEntries              bool
 	SrcJar                   bool
 	AddDirectoryEntriesToZip bool
 	CompressionLevel         int
@@ -394,7 +395,7 @@
 		}
 	}
 
-	return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SrcJar, args.NumParallelJobs)
+	return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SortEntries, args.SrcJar, args.NumParallelJobs)
 }
 
 // Zip creates an output zip archive from given sources.
@@ -481,7 +482,8 @@
 	})
 }
 
-func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar, srcJar bool,
+func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string,
+	emulateJar, sortEntries, srcJar bool,
 	parallelJobs int) error {
 
 	z.errors = make(chan error)
@@ -511,12 +513,20 @@
 		return errors.New("must specify --jar when specifying a manifest via -m")
 	}
 
+	if emulateJar && sortEntries {
+		return errors.New("Cannot specify both --jar and --sort_entries (--jar implies sorting with a different algorithm)")
+	}
 	if emulateJar {
 		// manifest may be empty, in which case addManifest will fill in a default
 		pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate})
 
 		jarSort(pathMappings)
 	}
+	if sortEntries {
+		sort.SliceStable(pathMappings, func(i int, j int) bool {
+			return pathMappings[i].dest < pathMappings[j].dest
+		})
+	}
 
 	go func() {
 		var err error