github.com/AiRISTAFlowInc/fs-cli@v0.2.6/api/create.go (about) 1 package api 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strings" 11 12 "github.com/AiRISTAFlowInc/fs-cli/common" 13 "github.com/AiRISTAFlowInc/fs-cli/util" 14 ) 15 16 var fileSampleEngineMain = filepath.Join("examples", "engine", "main.go") 17 18 func CreateProject(basePath, appName, appCfgPath, coreVersion string) (common.AppProject, error) { 19 var err error 20 var appJson string 21 22 if appCfgPath != "" { 23 24 if util.IsRemote(appCfgPath) { 25 26 appJson, err = util.LoadRemoteFile(appCfgPath) 27 if err != nil { 28 return nil, fmt.Errorf("unable to load remote app file '%s' - %s", appCfgPath, err.Error()) 29 } 30 } else { 31 appJson, err = util.LoadLocalFile(appCfgPath) 32 if err != nil { 33 return nil, fmt.Errorf("unable to load app file '%s' - %s", appCfgPath, err.Error()) 34 } 35 } 36 } else { 37 if len(appName) == 0 { 38 return nil, fmt.Errorf("app name not specified") 39 } 40 } 41 42 appName, err = getAppName(appName, appJson) 43 if err != nil { 44 return nil, err 45 } 46 47 fmt.Printf("Creating Flogo App: %s\n", appName) 48 49 appDir, err := createAppDirectory(basePath, appName) 50 if err != nil { 51 return nil, err 52 } 53 54 srcDir := filepath.Join(appDir, "src") 55 dm := util.NewDepManager(srcDir) 56 57 if Verbose() { 58 fmt.Printf("Setting up app directory: %s\n", appDir) 59 } 60 61 err = setupAppDirectory(dm, appDir, coreVersion) 62 if err != nil { 63 return nil, err 64 } 65 66 if Verbose() { 67 if appJson == "" { 68 fmt.Println("Adding sample flogo.json") 69 } 70 } 71 err = createAppJson(dm, appDir, appName, appJson) 72 if err != nil { 73 return nil, err 74 } 75 76 err = createMain(dm, appDir) 77 if err != nil { 78 return nil, err 79 } 80 81 project := NewAppProject(appDir) 82 83 if Verbose() { 84 fmt.Println("Importing Dependencies...") 85 } 86 87 err = importDependencies(project) 88 if err != nil { 89 return nil, err 90 } 91 92 if Verbose() { 93 fmt.Printf("Created App: %s\n", appName) 94 } 95 96 err = util.ExecCmd(exec.Command("go", "mod", "tidy"), srcDir) 97 if err != nil { 98 fmt.Println("[err]", err) 99 } 100 101 return project, nil 102 } 103 104 // createAppDirectory creates the flogo app directory 105 func createAppDirectory(basePath, appName string) (string, error) { 106 var err error 107 108 if basePath == "." { 109 basePath, err = os.Getwd() 110 if err != nil { 111 return "", err 112 } 113 } 114 115 appPath := filepath.Join(basePath, appName) 116 err = os.Mkdir(appPath, os.ModePerm) 117 if err != nil { 118 return "", err 119 } 120 121 return appPath, nil 122 } 123 124 // setupAppDirectory sets up the flogo app directory 125 func setupAppDirectory(dm util.DepManager, appPath, coreVersion string) error { 126 err := os.Mkdir(filepath.Join(appPath, dirBin), os.ModePerm) 127 if err != nil { 128 return err 129 } 130 131 srcDir := filepath.Join(appPath, dirSrc) 132 err = os.Mkdir(srcDir, os.ModePerm) 133 if err != nil { 134 return err 135 } 136 137 _, err = os.Create(filepath.Join(srcDir, fileImportsGo)) 138 if err != nil { 139 return err 140 } 141 err = ioutil.WriteFile(filepath.Join(srcDir, fileImportsGo), []byte("package main\n"), 0644) 142 if err != nil { 143 return err 144 } 145 146 err = dm.Init() 147 if err != nil { 148 return err 149 } 150 151 flogoCoreImport := util.NewFlogoImport(flogoCoreRepo, "", coreVersion, "") 152 153 //todo get the actual version installed from the go.mod file 154 if coreVersion == "" { 155 fmt.Printf("Installing: %s@latest\n", flogoCoreImport.CanonicalImport()) 156 } else { 157 fmt.Printf("Installing: %s\n", flogoCoreImport.CanonicalImport()) 158 } 159 160 // add & fetch the core library 161 err = dm.AddDependency(flogoCoreImport) 162 if err != nil { 163 return err 164 } 165 166 return nil 167 } 168 169 // createAppJson create the flogo app json 170 func createAppJson(dm util.DepManager, appDir, appName, appJson string) error { 171 updatedJson, err := getAndUpdateAppJson(dm, appName, appJson) 172 if err != nil { 173 return err 174 } 175 176 err = ioutil.WriteFile(filepath.Join(appDir, fileFlogoJson), []byte(updatedJson), 0644) 177 if err != nil { 178 return err 179 } 180 181 return nil 182 } 183 184 // importDependencies import all dependencies 185 func importDependencies(project common.AppProject) error { 186 ai, err := util.GetAppImports(filepath.Join(project.Dir(), fileFlogoJson), project.DepManager(), true) 187 if err != nil { 188 return err 189 } 190 191 imports := ai.GetAllImports() 192 193 if len(imports) == 0 { 194 return nil 195 } 196 197 err = project.AddImports(true, false, imports...) 198 if err != nil { 199 return err 200 } 201 202 legacySupportRequired := false 203 204 for _, details := range ai.GetAllImportDetails() { 205 206 path, err := project.GetPath(details.Imp) 207 if err != nil { 208 return err 209 } 210 211 desc, err := util.GetContribDescriptor(path) 212 213 if err != nil { 214 return err 215 } 216 217 if desc != nil { 218 219 cType := desc.GetContribType() 220 if desc.IsLegacy { 221 legacySupportRequired = true 222 cType = "legacy " + desc.GetContribType() 223 err := CreateLegacyMetadata(path, desc.GetContribType(), details.Imp.GoImportPath()) 224 if err != nil { 225 return err 226 } 227 } 228 229 fmt.Printf("Installed %s: %s\n", cType, details.Imp) 230 //instStr := fmt.Sprintf("Installed %s:", cType) 231 //fmt.Printf("%-20s %s\n", instStr, imp) 232 } 233 } 234 235 if legacySupportRequired { 236 err := InstallLegacySupport(project) 237 return err 238 } 239 240 return nil 241 } 242 243 func createMain(dm util.DepManager, appDir string) error { 244 flogoCoreImport, err := util.NewFlogoImportFromPath(flogoCoreRepo) 245 if err != nil { 246 return err 247 } 248 249 corePath, err := dm.GetPath(flogoCoreImport) 250 if err != nil { 251 return err 252 } 253 254 bytes, err := ioutil.ReadFile(filepath.Join(corePath, fileSampleEngineMain)) 255 if err != nil { 256 return err 257 } 258 259 err = ioutil.WriteFile(filepath.Join(appDir, dirSrc, fileMainGo), bytes, 0644) 260 if err != nil { 261 return err 262 } 263 264 return nil 265 } 266 267 func getAndUpdateAppJson(dm util.DepManager, appName, appJson string) (string, error) { 268 if len(appJson) == 0 { 269 appJson = emptyFlogoJson 270 } 271 272 descriptor, err := util.ParseAppDescriptor(appJson) 273 if err != nil { 274 return "", err 275 } 276 277 if appName != "" { 278 // override the application name 279 280 altJson := strings.Replace(appJson, `"`+descriptor.Name+`"`, `"`+appName+`"`, 1) 281 altDescriptor, err := util.ParseAppDescriptor(altJson) 282 283 //see if we can get away with simple replace so we don't reorder the existing json 284 if err == nil && altDescriptor.Name == appName { 285 appJson = altJson 286 } else { 287 //simple replace didn't work so we have to unmarshal & re-marshal the supplied json 288 var appObj map[string]interface{} 289 err := json.Unmarshal([]byte(appJson), &appObj) 290 if err != nil { 291 return "", err 292 } 293 294 appObj["name"] = appName 295 296 updApp, err := json.MarshalIndent(appObj, "", " ") 297 if err != nil { 298 return "", err 299 } 300 appJson = string(updApp) 301 } 302 303 descriptor.Name = appName 304 } else { 305 appName = descriptor.Name 306 _ = appName 307 } 308 309 return appJson, nil 310 } 311 312 func getAppName(appName, appJson string) (string, error) { 313 if appJson != "" && appName == "" { 314 descriptor, err := util.ParseAppDescriptor(appJson) 315 if err != nil { 316 return "", err 317 } 318 319 return descriptor.Name, nil 320 } 321 322 return appName, nil 323 } 324 func GetTempDir() (string, error) { 325 326 tempDir, err := ioutil.TempDir("", "flogo") 327 if err != nil { 328 return "", err 329 } 330 return tempDir, nil 331 } 332 333 var emptyFlogoJson = ` 334 { 335 "name": "{{.AppName}}", 336 "type": "flogo:app", 337 "version": "0.0.1", 338 "description": "My Flogo Application Description", 339 "appModel": "1.1.0", 340 "imports": [], 341 "triggers": [], 342 "resources":[] 343 } 344 `