github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/fn/commands/init.go (about) 1 package commands 2 3 /* 4 usage: fn init <name> 5 6 If there's a Dockerfile found, this will generate the basic file with just the image name. exit 7 It will then try to decipher the runtime based on the files in the current directory, if it can't figure it out, it will ask. 8 It will then take a best guess for what the entrypoint will be based on the language, it it can't guess, it will ask. 9 10 */ 11 12 import ( 13 "errors" 14 "fmt" 15 "os" 16 "path/filepath" 17 "strings" 18 19 "github.com/iron-io/functions/fn/common" 20 "github.com/iron-io/functions/fn/langs" 21 "github.com/urfave/cli" 22 ) 23 24 var ( 25 fileExtToRuntime = map[string]string{ 26 ".go": "go", 27 ".js": "node", 28 ".rb": "ruby", 29 ".py": "python", 30 ".rs": "rust", 31 ".cs": "dotnet", 32 ".fs": "dotnet", 33 ".java": "java", 34 } 35 36 filenames = []string{ 37 "func", 38 "Func", 39 } 40 41 fnInitRuntimes []string 42 ) 43 44 func init() { 45 for rt := range fileExtToRuntime { 46 fnInitRuntimes = append(fnInitRuntimes, rt) 47 } 48 } 49 50 type initFnCmd struct { 51 name string 52 force bool 53 runtime string 54 entrypoint string 55 cmd string 56 format string 57 maxConcurrency int 58 } 59 60 func InitFn() cli.Command { 61 a := initFnCmd{} 62 63 return cli.Command{ 64 Name: "init", 65 Usage: "create a local func.yaml file", 66 Description: "Creates a func.yaml file in the current directory. ", 67 ArgsUsage: "<DOCKERHUB_USERNAME/FUNCTION_NAME>", 68 Action: a.init, 69 Flags: []cli.Flag{ 70 cli.BoolFlag{ 71 Name: "force, f", 72 Usage: "overwrite existing func.yaml", 73 Destination: &a.force, 74 }, 75 cli.StringFlag{ 76 Name: "runtime", 77 Usage: "choose an existing runtime - " + strings.Join(fnInitRuntimes, ", "), 78 Destination: &a.runtime, 79 }, 80 cli.StringFlag{ 81 Name: "entrypoint", 82 Usage: "entrypoint is the command to run to start this function - equivalent to Dockerfile ENTRYPOINT.", 83 Destination: &a.entrypoint, 84 }, 85 cli.StringFlag{ 86 Name: "format", 87 Usage: "hot function IO format - json or http", 88 Destination: &a.format, 89 Value: "", 90 }, 91 cli.IntFlag{ 92 Name: "max-concurrency", 93 Usage: "maximum concurrency for hot function", 94 Destination: &a.maxConcurrency, 95 Value: 1, 96 }, 97 cli.StringFlag{ 98 Name: "cmd", 99 Usage: "command", 100 Destination: &a.cmd, 101 Value: "", 102 }, 103 }, 104 } 105 } 106 107 func (a *initFnCmd) init(c *cli.Context) error { 108 if !a.force { 109 ff, err := common.LoadFuncfile() 110 if _, ok := err.(*common.NotFoundError); !ok && err != nil { 111 return err 112 } 113 if ff != nil { 114 return errors.New("function file already exists") 115 } 116 } 117 118 err := a.buildFuncFile(c) 119 if err != nil { 120 return err 121 } 122 123 var ffmt *string 124 if a.format != "" { 125 ffmt = &a.format 126 } 127 128 ff := &common.Funcfile{ 129 Name: a.name, 130 Runtime: &a.runtime, 131 Version: common.INITIAL_VERSION, 132 Entrypoint: a.entrypoint, 133 Cmd: a.cmd, 134 Format: ffmt, 135 MaxConcurrency: &a.maxConcurrency, 136 } 137 138 _, path := common.AppNamePath(ff.FullName()) 139 ff.Path = &path 140 141 if err := common.EncodeFuncfileYAML("func.yaml", ff); err != nil { 142 return err 143 } 144 145 fmt.Println("func.yaml created.") 146 return nil 147 } 148 149 func (a *initFnCmd) buildFuncFile(c *cli.Context) error { 150 pwd, err := os.Getwd() 151 if err != nil { 152 return fmt.Errorf("error detecting current working directory: %s", err) 153 } 154 155 a.name = c.Args().First() 156 if a.name == "" || strings.Contains(a.name, ":") { 157 return errors.New("Please specify a name for your function in the following format <DOCKERHUB_USERNAME>/<FUNCTION_NAME>.\nTry: fn init <DOCKERHUB_USERNAME>/<FUNCTION_NAME>") 158 } 159 160 if common.Exists("Dockerfile") { 161 fmt.Println("Dockerfile found, will use that to build.") 162 return nil 163 } 164 165 var rt string 166 if a.runtime == "" { 167 rt, err = detectRuntime(pwd) 168 if err != nil { 169 return err 170 } 171 a.runtime = rt 172 fmt.Printf("assuming %v runtime\n", rt) 173 } 174 fmt.Println("runtime:", a.runtime) 175 if _, ok := common.AcceptableFnRuntimes[a.runtime]; !ok { 176 return fmt.Errorf("init does not support the %s runtime, you'll have to create your own Dockerfile for this function", a.runtime) 177 } 178 179 helper := langs.GetLangHelper(a.runtime) 180 if helper == nil { 181 fmt.Printf("No helper found for %s runtime, you'll have to pass in the appropriate flags or use a Dockerfile.", a.runtime) 182 } 183 184 if a.entrypoint == "" { 185 if helper != nil { 186 a.entrypoint = helper.Entrypoint() 187 } 188 } 189 if a.cmd == "" { 190 if helper != nil { 191 a.cmd = helper.Cmd() 192 } 193 } 194 if a.entrypoint == "" && a.cmd == "" { 195 return fmt.Errorf("could not detect entrypoint or cmd for %v, use --entrypoint and/or --cmd to set them explicitly", a.runtime) 196 } 197 198 return nil 199 } 200 201 func detectRuntime(path string) (runtime string, err error) { 202 for ext, runtime := range fileExtToRuntime { 203 for _, filename := range filenames { 204 fn := filepath.Join(path, fmt.Sprintf("%s%s", filename, ext)) 205 if common.Exists(fn) { 206 return runtime, nil 207 } 208 } 209 } 210 return "", fmt.Errorf("no supported files found to guess runtime, please set runtime explicitly with --runtime flag") 211 }