Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ lambda-builder
lambda.zip

response.json
Procfile
13 changes: 9 additions & 4 deletions builders/dotnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ func NewDotnetBuilder(config Config) (DotnetBuilder, error) {
}, nil
}

func (b DotnetBuilder) BuildImage() string {
return b.Config.BuilderBuildImage
}

func (b DotnetBuilder) Detect() bool {
if io.FileExistsInDirectory(b.Config.WorkingDirectory, "Function.cs") {
return true
Expand All @@ -36,13 +32,22 @@ func (b DotnetBuilder) Detect() bool {
}

func (b DotnetBuilder) Execute() error {
b.Config.HandlerMap = b.GetHandlerMap()
return executeBuilder(b.script(), b.GetTaskBuildDir(), b.Config)
}

func (b DotnetBuilder) GetBuildImage() string {
return b.Config.BuilderBuildImage
}

func (b DotnetBuilder) GetConfig() Config {
return b.Config
}

func (b DotnetBuilder) GetHandlerMap() map[string]string {
return map[string]string{}
}

func (b DotnetBuilder) GetTaskBuildDir() string {
return "/var/task"
}
Expand Down
15 changes: 11 additions & 4 deletions builders/go.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ func NewGoBuilder(config Config) (GoBuilder, error) {
}, nil
}

func (b GoBuilder) BuildImage() string {
return b.Config.BuilderBuildImage
}

func (b GoBuilder) Detect() bool {
if io.FileExistsInDirectory(b.Config.WorkingDirectory, "go.sum") {
return true
Expand All @@ -36,13 +32,24 @@ func (b GoBuilder) Detect() bool {
}

func (b GoBuilder) Execute() error {
b.Config.HandlerMap = b.GetHandlerMap()
return executeBuilder(b.script(), b.GetTaskBuildDir(), b.Config)
}

func (b GoBuilder) GetBuildImage() string {
return b.Config.BuilderBuildImage
}

func (b GoBuilder) GetConfig() Config {
return b.Config
}

func (b GoBuilder) GetHandlerMap() map[string]string {
return map[string]string{
"bootstrap": "bootstrap",
}
}

func (b GoBuilder) GetTaskBuildDir() string {
return "/go/src/handler"
}
Expand Down
27 changes: 27 additions & 0 deletions builders/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package builders

import (
"fmt"
"lambda-builder/io"
"os"
"path/filepath"
)

func getFunctionHandler(directory string, config Config) string {
if config.Handler != "" {
return config.Handler
}

for file, handler := range config.HandlerMap {
if io.FileExistsInDirectory(directory, file) {
return handler
}
}

return ""
}

func writeProcfile(handler string, directory string) error {
b := []byte(fmt.Sprintf("web: %s\n", handler))
return os.WriteFile(filepath.Join(directory, "Procfile"), b, 0644)
}
45 changes: 36 additions & 9 deletions builders/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@ import (
)

type Builder interface {
GetConfig() Config
GetTaskBuildDir() string
Detect() bool
Execute() error
BuildImage() string
GetBuildImage() string
GetConfig() Config
GetHandlerMap() map[string]string
GetTaskBuildDir() string
Name() string
}

type Config struct {
BuildImage bool
BuilderBuildImage string
BuilderRunImage string
Handler string
HandlerMap map[string]string
Identifier string
ImageLabels []string
ImageTag string
RunQuiet bool
WriteProcfile bool
WorkingDirectory string
}

Expand Down Expand Up @@ -62,10 +66,29 @@ func executeBuilder(script string, taskBuildDir string, config Config) error {
return err
}

handler := getFunctionHandler(tmp, config)
if config.WriteProcfile && !io.FileExistsInDirectory(tmp, "Procfile") {
if handler == "" {
fmt.Printf(" ! Unable to detect handler in build directory\n")
} else {
fmt.Printf("=====> Writing Procfile from handler: %s\n", handler)

fmt.Printf(" Writing to working directory\n")
if err := writeProcfile(handler, config.WorkingDirectory); err != nil {
return fmt.Errorf("error writing Procfile to working directory: %s", err.Error())
}

fmt.Printf(" Writing to build directory\n")
if err := writeProcfile(handler, tmp); err != nil {
return fmt.Errorf("error writing Procfile to temporary build directory: %s", err.Error())
}
}
}

if config.BuildImage {
fmt.Printf("=====> Building image\n")
fmt.Printf(" Generating temporary Dockerfile\n")
if err := generateDockerfile(tmp, config); err != nil {
if err := generateDockerfile(handler, tmp, config); err != nil {
return err
}

Expand Down Expand Up @@ -111,22 +134,26 @@ func executeBuildContainer(tmp string, script string, taskBuildDir string, confi
return nil
}

func generateDockerfile(tmp string, config Config) error {
dockerfileName := filepath.Join(tmp, fmt.Sprintf("%s.Dockerfile", config.Identifier))
func generateDockerfile(cmd string, directory string, config Config) error {
dockerfileName := filepath.Join(directory, fmt.Sprintf("%s.Dockerfile", config.Identifier))
f, err := os.Create(dockerfileName)
if err != nil {
return fmt.Errorf("error creating Dockerfile: %s", err)
}

tpl, err := template.New("t1").Parse(`
FROM {{ .run_image }}
{{ if ne .command "" }}
CMD ["{{ .cmd }}"]
{{ end }}
COPY . /var/task
`)
if err != nil {
return fmt.Errorf("error generating template: %s", err)
}

data := map[string]string{
"cmd": cmd,
"run_image": config.BuilderRunImage,
}

Expand All @@ -137,11 +164,11 @@ COPY . /var/task
return nil
}

func buildDockerImage(tmp string, config Config) error {
func buildDockerImage(directory string, config Config) error {
args := []string{
"image",
"build",
"--file", filepath.Join(tmp, fmt.Sprintf("%s.Dockerfile", config.Identifier)),
"--file", filepath.Join(directory, fmt.Sprintf("%s.Dockerfile", config.Identifier)),
"--progress", "plain",
"--tag", config.GetImageTag(),
}
Expand All @@ -150,7 +177,7 @@ func buildDockerImage(tmp string, config Config) error {
args = append(args, "--label", label)
}

args = append(args, tmp)
args = append(args, directory)

cmd := execute.ExecTask{
Args: args,
Expand Down
16 changes: 12 additions & 4 deletions builders/nodejs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ func NewNodejsBuilder(config Config) (NodejsBuilder, error) {
}, nil
}

func (b NodejsBuilder) BuildImage() string {
return b.Config.BuilderBuildImage
}

func (b NodejsBuilder) Detect() bool {
if io.FileExistsInDirectory(b.Config.WorkingDirectory, "package-lock.json") {
return true
Expand All @@ -36,13 +32,25 @@ func (b NodejsBuilder) Detect() bool {
}

func (b NodejsBuilder) Execute() error {
b.Config.HandlerMap = b.GetHandlerMap()
return executeBuilder(b.script(), b.GetTaskBuildDir(), b.Config)
}

func (b NodejsBuilder) GetBuildImage() string {
return b.Config.BuilderBuildImage
}

func (b NodejsBuilder) GetConfig() Config {
return b.Config
}

func (b NodejsBuilder) GetHandlerMap() map[string]string {
return map[string]string{
"function.js": "function.handler",
"lambda_function.js": "lambda_function.handler",
}
}

func (b NodejsBuilder) GetTaskBuildDir() string {
return "/var/task"
}
Expand Down
18 changes: 14 additions & 4 deletions builders/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ func NewPythonBuilder(config Config) (PythonBuilder, error) {
}, nil
}

func (b PythonBuilder) BuildImage() string {
return b.Config.BuilderBuildImage
}

func (b PythonBuilder) Detect() bool {
if io.FileExistsInDirectory(b.Config.WorkingDirectory, "requirements.txt") {
return true
Expand All @@ -64,13 +60,27 @@ func (b PythonBuilder) Detect() bool {
}

func (b PythonBuilder) Execute() error {
b.Config.HandlerMap = b.GetHandlerMap()
return executeBuilder(b.script(), b.GetTaskBuildDir(), b.Config)
}

func (b PythonBuilder) GetBuildImage() string {
return b.Config.BuilderBuildImage
}

func (b PythonBuilder) GetConfig() Config {
return b.Config
}

func (b PythonBuilder) GetHandlerMap() map[string]string {
return map[string]string{
"app.py": "app.handler",
"function.py": "function.handler",
"lambda_function.py": "lambda_function.handler",
"main.py": "main.handler",
}
}

func (b PythonBuilder) GetTaskBuildDir() string {
return "/var/task"
}
Expand Down
16 changes: 12 additions & 4 deletions builders/ruby.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ func NewRubyBuilder(config Config) (RubyBuilder, error) {
}, nil
}

func (b RubyBuilder) BuildImage() string {
return b.Config.BuilderBuildImage
}

func (b RubyBuilder) Detect() bool {
if io.FileExistsInDirectory(b.Config.WorkingDirectory, "Gemfile.lock") {
return true
Expand All @@ -35,15 +31,27 @@ func (b RubyBuilder) Detect() bool {
return false
}

func (b RubyBuilder) GetBuildImage() string {
return b.Config.BuilderBuildImage
}

func (b RubyBuilder) GetConfig() Config {
return b.Config
}

func (b RubyBuilder) GetHandlerMap() map[string]string {
return map[string]string{
"function.rb": "function.handler",
"lambda_function.rb": "lambda_function.handler",
}
}

func (b RubyBuilder) GetTaskBuildDir() string {
return "/var/task"
}

func (b RubyBuilder) Execute() error {
b.Config.HandlerMap = b.GetHandlerMap()
return executeBuilder(b.script(), b.GetTaskBuildDir(), b.Config)
}

Expand Down
14 changes: 10 additions & 4 deletions commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ type BuildCommand struct {
command.Meta

buildImage bool
handler string
imageTag string
labels []string
quiet bool
workingDirectory string
writeProcfile bool
}

func (c *BuildCommand) Name() string {
Expand Down Expand Up @@ -65,8 +67,10 @@ func (c *BuildCommand) FlagSet() *flag.FlagSet {
}

f := c.Meta.FlagSet(c.Name(), command.FlagSetClient)
f.BoolVar(&c.quiet, "quiet", false, "run builder in quiet mode")
f.BoolVar(&c.buildImage, "build-image", false, "build a docker image")
f.BoolVar(&c.quiet, "quiet", false, "run builder in quiet mode")
f.BoolVar(&c.writeProcfile, "write-procfile", false, "writes a Procfile if a handler is specified or detected")
f.StringVar(&c.handler, "handler", "", "handler override to specify as the default command to run in a built image")
f.StringVarP(&c.imageTag, "tag", "t", "", "name and optionally a tag in the 'name:tag' format")
f.StringVar(&c.workingDirectory, "working-directory", workingDirectory, "working directory")
f.StringArrayVar(&c.labels, "label", []string{}, " set metadata for an image")
Expand All @@ -77,8 +81,9 @@ func (c *BuildCommand) AutocompleteFlags() complete.Flags {
return command.MergeAutocompleteFlags(
c.Meta.AutocompleteFlags(command.FlagSetClient),
complete.Flags{
"--build-image": complete.PredictNothing,
"--quiet": complete.PredictNothing,
"--build-image": complete.PredictNothing,
"--quiet": complete.PredictNothing,
"--write-procfile": complete.PredictNothing,
},
)
}
Expand Down Expand Up @@ -122,6 +127,7 @@ func (c *BuildCommand) Run(args []string) int {
ImageLabels: c.labels,
ImageTag: c.imageTag,
RunQuiet: c.quiet,
WriteProcfile: c.writeProcfile,
WorkingDirectory: c.workingDirectory,
}

Expand All @@ -134,7 +140,7 @@ func (c *BuildCommand) Run(args []string) int {

c.Ui.Info(fmt.Sprintf("Detected %s builder", builder.Name()))

logger.LogHeader1(fmt.Sprintf("Building app with image %s", builder.BuildImage()))
logger.LogHeader1(fmt.Sprintf("Building app with image %s", builder.GetBuildImage()))
if err := builder.Execute(); err != nil {
c.Ui.Error(err.Error())
return 1
Expand Down
Loading