diff options
author | Luke Granger-Brown <git@lukegb.com> | 2020-06-14T11·22+0100 |
---|---|---|
committer | lukegb <lukegb@tvl.fyi> | 2020-06-14T15·34+0000 |
commit | af167ff8d43786f285dc953195af332a970b1a2b (patch) | |
tree | 131c9f05cd9038c38a78907366271690ea86396c | |
parent | f3d9d5ef4919c377d0cab6a2f9effdef3907310c (diff) |
feat(gerrit): Create detzip, a small helper utility for packing zips determinstically. r/946
detzip will be used in a patch for the Gerrit bower repository helper, which allows us to get consistent hashes for the output of fetching the dependencies for the Bazel build. Change-Id: I6c87b19815b9d747064108aecbb57ed875d2623b Reviewed-on: https://cl.tvl.fyi/c/depot/+/251 Reviewed-by: lukegb <lukegb@tvl.fyi>
-rw-r--r-- | third_party/gerrit/detzip.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/third_party/gerrit/detzip.go b/third_party/gerrit/detzip.go new file mode 100644 index 000000000000..511c18ecfe17 --- /dev/null +++ b/third_party/gerrit/detzip.go @@ -0,0 +1,97 @@ +package main + +import ( + "archive/zip" + "flag" + "fmt" + "io" + "log" + "os" + "path/filepath" + "sort" + "strings" +) + +var ( + exclude = flag.String("exclude", "", "comma-separated list of filenames to exclude (in any directory)") +) + +func init() { + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s [zip file] [directory]:\n", os.Args[0]) + flag.PrintDefaults() + } +} + +func listToMap(ss []string) map[string]bool { + m := make(map[string]bool) + for _, s := range ss { + m[s] = true + } + return m +} + +func main() { + flag.Parse() + if flag.NArg() != 2 { + flag.Usage() + os.Exit(1) + } + + outPath := flag.Arg(0) + dirPath := flag.Arg(1) + + excludeFiles := listToMap(strings.Split(*exclude, ",")) + + // Aggregate all files first. + var files []string + filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + if excludeFiles[info.Name()] { + return nil + } + files = append(files, path) + return nil + }) + + // Create zip + outW, err := os.Create(outPath) + if err != nil { + log.Fatalf("Create(%q): %v", outPath, err) + } + + zipW := zip.NewWriter(outW) + + // Output files in alphabetical order + sort.Strings(files) + for _, f := range files { + fw, err := zipW.CreateHeader(&zip.FileHeader{ + Name: f, + Method: zip.Store, + }) + if err != nil { + log.Fatalf("creating %q in zip: %v", f, err) + } + + ff, err := os.Open(f) + if err != nil { + log.Fatalf("opening %q: %v", f, err) + } + if _, err := io.Copy(fw, ff); err != nil { + log.Fatalf("copying %q to zip: %v", f, err) + } + ff.Close() + } + + if err := zipW.Close(); err != nil { + log.Fatalf("writing ZIP central directory: %v", err) + } + if err := outW.Close(); err != nil { + log.Fatalf("closing ZIP file: %v", err) + } +} |