github.com/Foodji/aws-lambda-go@v1.20.2/cmd/build-lambda-zip/main.go (about)

     1  // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved
     2  
     3  package main
     4  
     5  import (
     6  	"archive/zip"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/urfave/cli/v2"
    15  )
    16  
    17  func main() {
    18  	app := &cli.App{
    19  		Name:  "build-lambda-zip",
    20  		Usage: "Put an executable and supplemental files into a zip file that works with AWS Lambda.",
    21  		Flags: []cli.Flag{
    22  			&cli.StringFlag{
    23  				Name:    "output",
    24  				Aliases: []string{"o"},
    25  				Value:   "",
    26  				Usage:   "output file path for the zip. Defaults to the first input file name.",
    27  			},
    28  		},
    29  		Action: func(c *cli.Context) error {
    30  			if !c.Args().Present() {
    31  				return errors.New("no input provided")
    32  			}
    33  
    34  			inputExe := c.Args().First()
    35  			outputZip := c.String("output")
    36  			if outputZip == "" {
    37  				outputZip = fmt.Sprintf("%s.zip", filepath.Base(inputExe))
    38  			}
    39  
    40  			if err := compressExeAndArgs(outputZip, inputExe, c.Args().Tail()); err != nil {
    41  				return fmt.Errorf("failed to compress file: %v", err)
    42  			}
    43  			log.Print("wrote " + outputZip)
    44  			return nil
    45  		},
    46  	}
    47  
    48  	if err := app.Run(os.Args); err != nil {
    49  		fmt.Fprintf(os.Stderr, "%v\n", err)
    50  		os.Exit(1)
    51  	}
    52  }
    53  
    54  func writeExe(writer *zip.Writer, pathInZip string, data []byte) error {
    55  	if pathInZip != "bootstrap" {
    56  		header := &zip.FileHeader{Name: "bootstrap", Method: zip.Deflate}
    57  		header.SetMode(0755 | os.ModeSymlink)
    58  		link, err := writer.CreateHeader(header)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		if _, err := link.Write([]byte(pathInZip)); err != nil {
    63  			return err
    64  		}
    65  	}
    66  
    67  	exe, err := writer.CreateHeader(&zip.FileHeader{
    68  		CreatorVersion: 3 << 8,     // indicates Unix
    69  		ExternalAttrs:  0777 << 16, // -rwxrwxrwx file permissions
    70  		Name:           pathInZip,
    71  		Method:         zip.Deflate,
    72  	})
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	_, err = exe.Write(data)
    78  	return err
    79  }
    80  
    81  func compressExeAndArgs(outZipPath string, exePath string, args []string) error {
    82  	zipFile, err := os.Create(outZipPath)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	defer func() {
    87  		closeErr := zipFile.Close()
    88  		if closeErr != nil {
    89  			fmt.Fprintf(os.Stderr, "Failed to close zip file: %v\n", closeErr)
    90  		}
    91  	}()
    92  
    93  	zipWriter := zip.NewWriter(zipFile)
    94  	defer zipWriter.Close()
    95  	data, err := ioutil.ReadFile(exePath)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	err = writeExe(zipWriter, filepath.Base(exePath), data)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	for _, arg := range args {
   106  		writer, err := zipWriter.Create(arg)
   107  		if err != nil {
   108  			return err
   109  		}
   110  		data, err := ioutil.ReadFile(arg)
   111  		if err != nil {
   112  			return err
   113  		}
   114  		_, err = writer.Write(data)
   115  		if err != nil {
   116  			return err
   117  		}
   118  	}
   119  	return err
   120  }