From 8936b02b58901cda6a14788a299d65f384b7b30d Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 23 Jun 2017 13:00:17 -0700 Subject: [PATCH] Add jar sorting to zip2zip Jars have a strange sorting order; the META-INF/ directory should come first, then META-INF/MANIFEST.MF, then any other files in META-INF/, and then any files outside META-INF. Add a -j argument to zip2zip that sorts using jar ordering. Test: zip2zip_test Change-Id: I80e2bc7e284ef74f6561c26cb6541298834db1bc --- cmd/zip2zip/zip2zip.go | 57 +++++++++++++++++++++++++++++++------ cmd/zip2zip/zip2zip_test.go | 32 ++++++++++++++++++++- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go index 48c36ccc2..fb2fa620e 100644 --- a/cmd/zip2zip/zip2zip.go +++ b/cmd/zip2zip/zip2zip.go @@ -31,6 +31,7 @@ var ( input = flag.String("i", "", "zip file to read from") output = flag.String("o", "", "output file") sortGlobs = flag.Bool("s", false, "sort matches from each glob (defaults to the order from the input zip file)") + sortJava = flag.Bool("j", false, "sort using jar ordering within each glob (META-INF/MANIFEST.MF first)") setTime = flag.Bool("t", false, "set timestamps to 2009-01-01 00:00:00") staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC) @@ -38,7 +39,7 @@ var ( func main() { flag.Usage = func() { - fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [-s] [-t] [filespec]...") + fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [-s|-j] [-t] [filespec]...") flag.PrintDefaults() fmt.Fprintln(os.Stderr, " filespec:") fmt.Fprintln(os.Stderr, " ") @@ -81,12 +82,17 @@ func main() { } }() - if err := zip2zip(&reader.Reader, writer, *sortGlobs, *setTime, flag.Args()); err != nil { + if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime, flag.Args()); err != nil { log.Fatal(err) } } -func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, setTime bool, args []string) error { +type pair struct { + *zip.File + newName string +} + +func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, sortJava, setTime bool, args []string) error { for _, arg := range args { var input string var output string @@ -103,11 +109,6 @@ func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, setTime bool, ar output = args[1] } - type pair struct { - *zip.File - newName string - } - matches := []pair{} if strings.IndexAny(input, "*?[") >= 0 { matchAll := input == "**" @@ -138,7 +139,9 @@ func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, setTime bool, ar } } - if sortGlobs { + if sortJava { + jarSort(matches) + } else if sortGlobs { sort.SliceStable(matches, func(i, j int) bool { return matches[i].newName < matches[j].newName }) @@ -167,3 +170,39 @@ func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, setTime bool, ar return nil } + +func jarSort(files []pair) { + // Treats trailing * as a prefix match + match := func(pattern, name string) bool { + if strings.HasSuffix(pattern, "*") { + return strings.HasPrefix(name, strings.TrimSuffix(pattern, "*")) + } else { + return name == pattern + } + } + + var jarOrder = []string{ + "META-INF/", + "META-INF/MANIFEST.MF", + "META-INF/*", + "*", + } + + index := func(name string) int { + for i, pattern := range jarOrder { + if match(pattern, name) { + return i + } + } + panic(fmt.Errorf("file %q did not match any pattern", name)) + } + + sort.SliceStable(files, func(i, j int) bool { + diff := index(files[i].newName) - index(files[j].newName) + if diff == 0 { + return files[i].newName < files[j].newName + } else { + return diff < 0 + } + }) +} diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go index 7f2e31a4d..2b5b5623a 100644 --- a/cmd/zip2zip/zip2zip_test.go +++ b/cmd/zip2zip/zip2zip_test.go @@ -28,6 +28,7 @@ var testCases = []struct { inputFiles []string sortGlobs bool + sortJava bool args []string outputFiles []string @@ -115,6 +116,35 @@ var testCases = []struct { "RADIO/a", }, }, + { + name: "sort jar", + + inputFiles: []string{ + "MANIFEST.MF", + "META-INF/MANIFEST.MF", + "META-INF/aaa/", + "META-INF/aaa/aaa", + "META-INF/AAA", + "META-INF.txt", + "META-INF/", + "AAA", + "aaa", + }, + sortJava: true, + args: nil, + + outputFiles: []string{ + "META-INF/", + "META-INF/MANIFEST.MF", + "META-INF/AAA", + "META-INF/aaa/", + "META-INF/aaa/aaa", + "AAA", + "MANIFEST.MF", + "META-INF.txt", + "aaa", + }, + }, { name: "double input", @@ -161,7 +191,7 @@ func TestZip2Zip(t *testing.T) { } outputWriter := zip.NewWriter(outputBuf) - err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, false, testCase.args) + err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args) if errorString(testCase.err) != errorString(err) { t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err)) }