github.com/TNTworks/flogo-cli@v0.9.1-0.20220522183836-60b8a963ae00/api/project.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "go/parser" 6 "go/printer" 7 "go/token" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strings" 12 13 "github.com/TNTworks/flogo-cli/common" 14 "github.com/TNTworks/flogo-cli/util" 15 ) 16 17 const ( 18 flogoCoreRepo = "github.com/project-flogo/core" 19 fileFlogoJson = "flogo.json" 20 fileEngineJson = "engine.json" 21 fileMainGo = "main.go" 22 fileImportsGo = "imports.go" 23 dirSrc = "src" 24 dirBin = "bin" 25 ) 26 27 var GOOSENV = os.Getenv("GOOS") 28 29 type appProjectImpl struct { 30 appDir string 31 appName string 32 srcDir string 33 binDir string 34 dm util.DepManager 35 } 36 37 func NewAppProject(appDir string) common.AppProject { 38 project := &appProjectImpl{appDir: appDir} 39 project.srcDir = filepath.Join(appDir, dirSrc) 40 project.binDir = filepath.Join(appDir, dirBin) 41 project.dm = util.NewDepManager(project.srcDir) 42 project.appName = filepath.Base(appDir) 43 return project 44 } 45 46 func (p *appProjectImpl) Validate() error { 47 _, err := os.Stat(filepath.Join(p.appDir, fileFlogoJson)) 48 if os.IsNotExist(err) { 49 return fmt.Errorf("not a valid flogo app project directory, missing flogo.json") 50 } 51 52 _, err = os.Stat(p.srcDir) 53 if os.IsNotExist(err) { 54 return fmt.Errorf("not a valid flogo app project directory, missing 'src' diretory") 55 } 56 57 _, err = os.Stat(filepath.Join(p.srcDir, fileImportsGo)) 58 if os.IsNotExist(err) { 59 return fmt.Errorf("flogo app directory corrupt, missing 'src/imports.go' file") 60 } 61 62 _, err = os.Stat(filepath.Join(p.srcDir, "go.mod")) 63 if os.IsNotExist(err) { 64 return fmt.Errorf("flogo app directory corrupt, missing 'src/go.mod' file") 65 } 66 67 return nil 68 } 69 70 func (p *appProjectImpl) Name() string { 71 return p.appName 72 } 73 74 func (p *appProjectImpl) Dir() string { 75 return p.appDir 76 } 77 78 func (p *appProjectImpl) BinDir() string { 79 return p.binDir 80 } 81 82 func (p *appProjectImpl) SrcDir() string { 83 return p.srcDir 84 } 85 86 func (p *appProjectImpl) DepManager() util.DepManager { 87 return p.dm 88 } 89 90 func (p *appProjectImpl) Executable() string { 91 92 var execPath string 93 94 execPath = filepath.Join(p.binDir, p.appName) 95 96 if GOOSENV == "windows" || (runtime.GOOS == "windows" && GOOSENV == "") { 97 // env or cross platform is windows 98 execPath = filepath.Join(p.binDir, p.appName+".exe") 99 } 100 101 return execPath 102 } 103 104 func (p *appProjectImpl) GetPath(flogoImport util.Import) (string, error) { 105 return p.dm.GetPath(flogoImport) 106 } 107 108 func (p *appProjectImpl) GetGoImports(withVersion bool) ([]util.Import, error) { 109 importsFile := filepath.Join(p.SrcDir(), fileImportsGo) 110 111 fset := token.NewFileSet() 112 file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly) 113 if err != nil { 114 return nil, err 115 } 116 117 //if withVersion, parse go.mod file for version information 118 //goModImports, err := p.dm.GetAllImports() 119 //if err != nil { 120 // return nil, err 121 //} 122 123 var imports []util.Import 124 for _, is := range file.Imports { 125 126 imp, err := util.ParseImport(is.Path.Value) 127 if err != nil { 128 return nil, err 129 } 130 131 imports = append(imports, imp) 132 } 133 134 return imports, nil 135 } 136 137 func (p *appProjectImpl) addImportsInGo(ignoreError bool, imports ...util.Import) error { 138 importsFile := filepath.Join(p.SrcDir(), fileImportsGo) 139 140 fset := token.NewFileSet() 141 file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly) 142 if err != nil { 143 return err 144 } 145 146 for _, i := range imports { 147 err := p.DepManager().AddDependency(i) 148 if err != nil { 149 if ignoreError { 150 fmt.Printf("Warning: unable to install '%s'\n", i) 151 continue 152 } 153 154 fmt.Fprintf(os.Stderr, "Error in installing '%s'\n", i) 155 156 return err 157 } 158 util.AddImport(fset, file, i.GoImportPath()) 159 } 160 161 f, err := os.Create(importsFile) 162 defer f.Close() 163 if err := printer.Fprint(f, fset, file); err != nil { 164 return err 165 } 166 167 //p.dm.Finalize() 168 169 return nil 170 } 171 172 func (p *appProjectImpl) addImportsInJson(ignoreError bool, imports ...util.Import) error { 173 174 appDescriptor, err := readAppDescriptor(p) 175 if err != nil { 176 return err 177 } 178 179 // list existing imports in JSON to avoid duplicates 180 existingImports := make(map[string]util.Import) 181 jsonImports, _ := util.ParseImports(appDescriptor.Imports) 182 for _, e := range jsonImports { 183 existingImports[e.GoImportPath()] = e 184 } 185 186 for _, i := range imports { 187 val, ok := existingImports[i.GoImportPath()] 188 if !ok { 189 //appDescriptor.Imports = append(appDescriptor.Imports, i.CanonicalImport()) 190 existingImports[i.GoImportPath()] = i 191 } else { 192 if i.CanonicalImport() != val.CanonicalImport() { 193 delete(existingImports, val.GoImportPath()) 194 alias := i.Alias() 195 if val.Alias() != "" && i.Alias() == "" { 196 alias = val.Alias() 197 } 198 existingImports[i.GoImportPath()] = util.NewFlogoImport(i.ModulePath(), i.RelativeImportPath(), i.Version(), alias) 199 } 200 } 201 202 } 203 var newImport []string 204 for _, val := range existingImports { 205 newImport = append(newImport, val.CanonicalImport()) 206 } 207 appDescriptor.Imports = newImport 208 209 err = writeAppDescriptor(p, appDescriptor) 210 if err != nil { 211 return err 212 } 213 214 return nil 215 } 216 217 func (p *appProjectImpl) AddImports(ignoreError bool, addToJson bool, imports ...util.Import) error { 218 err := p.addImportsInGo(ignoreError, imports...) // begin with Go imports as they are more likely to fail 219 if err != nil { 220 return err 221 } 222 223 if addToJson { 224 err = p.addImportsInJson(ignoreError, imports...) // adding imports in JSON after Go imports ensure the flogo.json is self-sufficient 225 } 226 227 return err 228 } 229 230 func (p *appProjectImpl) RemoveImports(imports ...string) error { 231 232 importsFile := filepath.Join(p.SrcDir(), fileImportsGo) 233 234 fset := token.NewFileSet() 235 file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly) 236 if err != nil { 237 return err 238 } 239 240 for _, impPath := range imports { 241 util.DeleteImport(fset, file, strings.Trim(impPath, "\"")) 242 } 243 244 f, err := os.Create(importsFile) 245 defer f.Close() 246 if err := printer.Fprint(f, fset, file); err != nil { 247 return err 248 } 249 250 return nil 251 }