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 }