github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/fn/common/funcfile.go (about)

     1  package common
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  
    13  	bumper "github.com/giantswarm/semver-bump/bump"
    14  	"github.com/giantswarm/semver-bump/storage"
    15  	yaml "gopkg.in/yaml.v2"
    16  )
    17  
    18  var (
    19  	Validfn = [...]string{
    20  		"func.yaml",
    21  		"func.yml",
    22  		"func.json",
    23  	}
    24  
    25  	errUnexpectedFileFormat = errors.New("unexpected file format for function file")
    26  )
    27  
    28  type fftest struct {
    29  	Name string            `yaml:"name,omitempty" json:"name,omitempty"`
    30  	In   *string           `yaml:"in,omitempty" json:"in,omitempty"`
    31  	Out  *string           `yaml:"out,omitempty" json:"out,omitempty"`
    32  	Err  *string           `yaml:"err,omitempty" json:"err,omitempty"`
    33  	Env  map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
    34  }
    35  
    36  type Funcfile struct {
    37  	Name           string            `yaml:"name,omitempty" json:"name,omitempty"`
    38  	Version        string            `yaml:"version,omitempty" json:"version,omitempty"`
    39  	Runtime        *string           `yaml:"runtime,omitempty" json:"runtime,omitempty"`
    40  	Entrypoint     string            `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
    41  	Cmd            string            `yaml:"cmd,omitempty" json:"cmd,omitempty"`
    42  	Type           *string           `yaml:"type,omitempty" json:"type,omitempty"`
    43  	Memory         *int64            `yaml:"memory,omitempty" json:"memory,omitempty"`
    44  	Format         *string           `yaml:"format,omitempty" json:"format,omitempty"`
    45  	Timeout        *time.Duration    `yaml:"timeout,omitempty" json:"timeout,omitempty"`
    46  	IDLETimeout    *time.Duration    `yaml:"idle_timeout,omitempty" json:"idle_timeout,omitempty"`
    47  	Headers        map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
    48  	Config         map[string]string `yaml:"config,omitempty" json:"config,omitempty"`
    49  	Build          []string          `yaml:"build,omitempty" json:"build,omitempty"`
    50  	Tests          []fftest          `yaml:"tests,omitempty" json:"tests,omitempty"`
    51  	Path           *string           `yaml:"path,omitempty" json:"path,omitempty"`
    52  	MaxConcurrency *int              `yaml:"max_concurrency,omitempty" json:"max_concurrency,omitempty"`
    53  	JwtKey         *string           `yaml:"jwt_key,omitempty" json:"jwt_key,omitempty"`
    54  }
    55  
    56  func (ff *Funcfile) FullName() string {
    57  	fname := ff.Name
    58  	if ff.Version != "" {
    59  		fname = fmt.Sprintf("%s:%s", fname, ff.Version)
    60  	}
    61  	return fname
    62  }
    63  
    64  func (ff *Funcfile) RuntimeTag() (runtime, tag string) {
    65  	if ff.Runtime == nil {
    66  		return "", ""
    67  	}
    68  
    69  	rt := *ff.Runtime
    70  	tagpos := strings.Index(rt, ":")
    71  	if tagpos == -1 {
    72  		return rt, ""
    73  	}
    74  
    75  	return rt[:tagpos], rt[tagpos+1:]
    76  }
    77  
    78  func cleanImageName(name string) string {
    79  	if i := strings.Index(name, ":"); i != -1 {
    80  		name = name[:i]
    81  	}
    82  
    83  	return name
    84  }
    85  
    86  func (ff *Funcfile) Bumpversion() error {
    87  	ff.Name = cleanImageName(ff.Name)
    88  	if ff.Version == "" {
    89  		ff.Version = INITIAL_VERSION
    90  		return nil
    91  	}
    92  
    93  	s, err := storage.NewVersionStorage("local", ff.Version)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	version := bumper.NewSemverBumper(s, "")
    99  	newver, err := version.BumpPatchVersion("", "")
   100  	if err != nil {
   101  		return err
   102  	}
   103  
   104  	ff.Version = newver.String()
   105  	return nil
   106  }
   107  
   108  func FindFuncfile(path string) (string, error) {
   109  	for _, fn := range Validfn {
   110  		fullfn := filepath.Join(path, fn)
   111  		if Exists(fullfn) {
   112  			return fullfn, nil
   113  		}
   114  	}
   115  	return "", newNotFoundError("could not find function file")
   116  }
   117  
   118  func LoadFuncfile() (*Funcfile, error) {
   119  	fn, err := FindFuncfile(".")
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	return ParseFuncfile(fn)
   124  }
   125  
   126  func ParseFuncfile(path string) (*Funcfile, error) {
   127  	ext := filepath.Ext(path)
   128  	switch ext {
   129  	case ".json":
   130  		return decodeFuncfileJSON(path)
   131  	case ".yaml", ".yml":
   132  		return decodeFuncfileYAML(path)
   133  	}
   134  	return nil, errUnexpectedFileFormat
   135  }
   136  
   137  func StoreFuncfile(path string, ff *Funcfile) error {
   138  	ext := filepath.Ext(path)
   139  	switch ext {
   140  	case ".json":
   141  		return encodeFuncfileJSON(path, ff)
   142  	case ".yaml", ".yml":
   143  		return EncodeFuncfileYAML(path, ff)
   144  	}
   145  	return errUnexpectedFileFormat
   146  }
   147  
   148  func decodeFuncfileJSON(path string) (*Funcfile, error) {
   149  	f, err := os.Open(path)
   150  	if err != nil {
   151  		return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
   152  	}
   153  	ff := new(Funcfile)
   154  	err = json.NewDecoder(f).Decode(ff)
   155  	return ff, err
   156  }
   157  
   158  func decodeFuncfileYAML(path string) (*Funcfile, error) {
   159  	b, err := ioutil.ReadFile(path)
   160  	if err != nil {
   161  		return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
   162  	}
   163  	ff := new(Funcfile)
   164  	err = yaml.Unmarshal(b, ff)
   165  	return ff, err
   166  }
   167  
   168  func encodeFuncfileJSON(path string, ff *Funcfile) error {
   169  	f, err := os.Open(path)
   170  	if err != nil {
   171  		return fmt.Errorf("could not open %s for encoding. Error: %v", path, err)
   172  	}
   173  	return json.NewEncoder(f).Encode(ff)
   174  }
   175  
   176  func EncodeFuncfileYAML(path string, ff *Funcfile) error {
   177  	b, err := yaml.Marshal(ff)
   178  	if err != nil {
   179  		return fmt.Errorf("could not encode function file. Error: %v", err)
   180  	}
   181  	return ioutil.WriteFile(path, b, os.FileMode(0644))
   182  }