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