github.com/fnproject/cli@v0.0.0-20240508150455-e5d88bd86117/langs/go.go (about)

     1  /*
     2   * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package langs
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"path/filepath"
    25  )
    26  
    27  type GoLangHelper struct {
    28  	BaseHelper
    29  	Version string
    30  }
    31  
    32  func (h *GoLangHelper) Handles(lang string) bool {
    33  	return defaultHandles(h, lang)
    34  }
    35  func (h *GoLangHelper) Runtime() string {
    36  	return h.LangStrings()[0]
    37  }
    38  
    39  func (h *GoLangHelper) CustomMemory() uint64 {
    40  	return 0
    41  }
    42  
    43  func (lh *GoLangHelper) LangStrings() []string {
    44  	return []string{"go", fmt.Sprintf("go%s", lh.Version)}
    45  }
    46  func (lh *GoLangHelper) Extensions() []string {
    47  	return []string{".go"}
    48  }
    49  
    50  func (lh *GoLangHelper) BuildFromImage() (string, error) {
    51  	return fmt.Sprintf("fnproject/go:%s-dev", lh.Version), nil
    52  }
    53  
    54  func (lh *GoLangHelper) RunFromImage() (string, error) {
    55  	return fmt.Sprintf("fnproject/go:%s", lh.Version), nil
    56  }
    57  
    58  func (h *GoLangHelper) DockerfileBuildCmds() []string {
    59  	r := []string{}
    60  	// more info on Go multi-stage builds: https://medium.com/travis-on-docker/multi-stage-docker-builds-for-creating-tiny-go-images-e0e1867efe5a
    61  	// TODO: if we keep the go.sum on user's drive, we can put this after the dep commands and then the dep layers will be cached.
    62  	vendor := exists("vendor/")
    63  	// skip dep tool install if vendor is there
    64  	if !vendor && exists("Gopkg.toml") {
    65  		r = append(r, "RUN go get -u github.com/golang/dep/cmd/dep")
    66  		if exists("Gopkg.lock") {
    67  			r = append(r, "ADD Gopkg.* /go/src/func/")
    68  			r = append(r, "RUN cd /go/src/func/ && dep ensure --vendor-only")
    69  			r = append(r, "ADD . /go/src/func/")
    70  		} else {
    71  			r = append(r, "ADD . /go/src/func/")
    72  			r = append(r, "RUN cd /go/src/func/ && dep ensure")
    73  		}
    74  	} else if exists("go.mod") {
    75  		r = append(r, "WORKDIR /go/src/func/")
    76  		r = append(r, "ENV GO111MODULE=on")
    77  		if vendor {
    78  			r = append(r, "ENV GOFLAGS=\"-mod=vendor\"")
    79  		}
    80  		r = append(r, "COPY . .")
    81  		r = append(r, "RUN go mod tidy")
    82  	} else {
    83  		r = append(r, "ADD . /go/src/func/")
    84  	}
    85  
    86  	r = append(r, "RUN go build -o func -v")
    87  
    88  	return r
    89  }
    90  
    91  func (h *GoLangHelper) DockerfileCopyCmds() []string {
    92  	return []string{
    93  		"COPY --from=build-stage /go/src/func/func /function/",
    94  	}
    95  }
    96  
    97  func (lh *GoLangHelper) Entrypoint() (string, error) {
    98  	return "./func", nil
    99  }
   100  
   101  func (lh *GoLangHelper) HasBoilerplate() bool { return true }
   102  
   103  func (lh *GoLangHelper) GenerateBoilerplate(path string) error {
   104  	codeFile := filepath.Join(path, "func.go")
   105  	if exists(codeFile) {
   106  		return errors.New("func.go already exists, canceling init")
   107  	}
   108  	if err := ioutil.WriteFile(codeFile, []byte(helloGoSrcBoilerplate), os.FileMode(0644)); err != nil {
   109  		return err
   110  	}
   111  	modFile := "go.mod"
   112  	fdkVersion, _ := lh.GetLatestFDKVersion()
   113  	if err := ioutil.WriteFile(modFile, []byte(fmt.Sprintf(modBoilerplate, fdkVersion)), os.FileMode(0644)); err != nil {
   114  		return err
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  func (h *GoLangHelper) GetLatestFDKVersion() (string, error) {
   121  	return getLatestFDKVersionFromGithub("fnproject/fdk-go")
   122  }
   123  
   124  const (
   125  	helloGoSrcBoilerplate = `package main
   126  
   127  import (
   128  	"context"
   129  	"encoding/json"
   130  	"fmt"
   131  	"io"
   132  	"log"
   133  
   134  	fdk "github.com/fnproject/fdk-go"
   135  )
   136  
   137  func main() {
   138  	fdk.Handle(fdk.HandlerFunc(myHandler))
   139  }
   140  
   141  type Person struct {
   142  	Name string ` + "`json:\"name\"`" + `
   143  }
   144  
   145  func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
   146  	p := &Person{Name: "World"}
   147  	json.NewDecoder(in).Decode(p)
   148  	msg := struct {
   149  		Msg string ` + "`json:\"message\"`" + `
   150  	}{
   151  		Msg: fmt.Sprintf("Hello %s", p.Name),
   152  	}
   153  	log.Print("Inside Go Hello World function")
   154  	json.NewEncoder(out).Encode(&msg)
   155  }
   156  `
   157  
   158  	modBoilerplate = `
   159  module func
   160  
   161  require github.com/fnproject/fdk-go %s
   162  `
   163  )
   164  
   165  func (h *GoLangHelper) FixImagesOnInit() bool {
   166  	return true
   167  }