// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved package main import ( "archive/zip" "flag" "fmt" "io/ioutil" //nolint: staticcheck "log" "os" "path/filepath" ) const usage = `build-lambda-zip - Puts an executable and supplemental files into a zip file that works with AWS Lambda. usage: build-lambda-zip [options] handler-exe [paths...] options: -o, --output output file path for the zip. (default: ${handler-exe}.zip) -h, --help prints usage ` func main() { var outputZip string flag.StringVar(&outputZip, "o", "", "") flag.StringVar(&outputZip, "output", "", "") flag.Usage = func() { fmt.Fprint(os.Stderr, usage) } flag.Parse() if len(flag.Args()) == 0 { log.Fatal("no input provided") } inputExe := flag.Arg(0) if outputZip == "" { outputZip = fmt.Sprintf("%s.zip", filepath.Base(inputExe)) } if err := compressExeAndArgs(outputZip, inputExe, flag.Args()[1:]); err != nil { log.Fatalf("failed to compress file: %v", err) } log.Printf("wrote %s", outputZip) } func writeExe(writer *zip.Writer, pathInZip string, data []byte) error { if pathInZip != "bootstrap" { header := &zip.FileHeader{Name: "bootstrap", Method: zip.Deflate} header.SetMode(0755 | os.ModeSymlink) link, err := writer.CreateHeader(header) if err != nil { return err } if _, err := link.Write([]byte(pathInZip)); err != nil { return err } } exe, err := writer.CreateHeader(&zip.FileHeader{ CreatorVersion: 3 << 8, // indicates Unix ExternalAttrs: 0777 << 16, // -rwxrwxrwx file permissions Name: pathInZip, Method: zip.Deflate, }) if err != nil { return err } _, err = exe.Write(data) return err } func compressExeAndArgs(outZipPath string, exePath string, args []string) error { zipFile, err := os.Create(outZipPath) if err != nil { return err } defer func() { closeErr := zipFile.Close() if closeErr != nil { fmt.Fprintf(os.Stderr, "Failed to close zip file: %v\n", closeErr) } }() zipWriter := zip.NewWriter(zipFile) defer zipWriter.Close() data, err := ioutil.ReadFile(exePath) if err != nil { return err } err = writeExe(zipWriter, filepath.Base(exePath), data) if err != nil { return err } for _, arg := range args { writer, err := zipWriter.Create(arg) if err != nil { return err } data, err := ioutil.ReadFile(arg) if err != nil { return err } _, err = writer.Write(data) if err != nil { return err } } return err }