github.com/AiRISTAFlowInc/fs-cli@v0.2.6/api/build.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "go/parser" 6 "go/printer" 7 "go/token" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/AiRISTAFlowInc/fs-cli/common" 14 "github.com/AiRISTAFlowInc/fs-cli/util" 15 ) 16 17 const ( 18 fileEmbeddedAppGo string = "embeddedapp.go" 19 ) 20 21 func BuildProject(project common.AppProject, options common.BuildOptions) error { 22 err := project.DepManager().AddReplacedContribForBuild() 23 if err != nil { 24 return err 25 } 26 27 buildPreProcessors := common.BuildPreProcessors() 28 29 if len(buildPreProcessors) > 0 { 30 for _, processor := range buildPreProcessors { 31 err = processor.DoPreProcessing(project, options) 32 if err != nil { 33 return err 34 } 35 } 36 } 37 38 var builder common.Builder 39 embedConfig := options.EmbedConfig 40 41 if options.Shim != "" { 42 builder = &ShimBuilder{shim: options.Shim} 43 embedConfig = true 44 } else { 45 builder = &AppBuilder{} 46 } 47 48 if embedConfig { 49 err = createEmbeddedAppGoFile(project) 50 if err != nil { 51 return err 52 } 53 } else { 54 err = cleanupEmbeddedAppGoFile(project) 55 if err != nil { 56 return err 57 } 58 } 59 60 if options.OptimizeImports { 61 if Verbose() { 62 fmt.Println("Optimizing imports...") 63 } 64 err := optimizeImports(project) 65 defer restoreImports(project) 66 67 if err != nil { 68 return err 69 } 70 } 71 72 err = builder.Build(project) 73 if err != nil { 74 return err 75 } 76 77 buildPostProcessors := common.BuildPostProcessors() 78 79 if len(buildPostProcessors) > 0 { 80 for _, processor := range buildPostProcessors { 81 err = processor.DoPostProcessing(project) 82 if err != nil { 83 return err 84 } 85 } 86 } 87 88 return nil 89 } 90 91 func cleanupEmbeddedAppGoFile(project common.AppProject) error { 92 embedSrcPath := filepath.Join(project.SrcDir(), fileEmbeddedAppGo) 93 94 if _, err := os.Stat(embedSrcPath); err == nil { 95 if Verbose() { 96 fmt.Println("Removing embed configuration") 97 } 98 err = os.Remove(embedSrcPath) 99 if err != nil { 100 return err 101 } 102 } 103 return nil 104 } 105 106 func createEmbeddedAppGoFile(project common.AppProject) error { 107 embedSrcPath := filepath.Join(project.SrcDir(), fileEmbeddedAppGo) 108 109 if Verbose() { 110 fmt.Println("Embedding configuration in application...") 111 } 112 113 buf, err := ioutil.ReadFile(filepath.Join(project.Dir(), fileFlogoJson)) 114 if err != nil { 115 return err 116 } 117 flogoJSON := string(buf) 118 119 tplFile := tplEmbeddedAppGoFile 120 if !isNewMain(project) { 121 tplFile = tplEmbeddedAppOldGoFile 122 } 123 124 engineJSON := "" 125 126 if util.FileExists(filepath.Join(project.Dir(), fileEngineJson)) { 127 buf, err = ioutil.ReadFile(filepath.Join(project.Dir(), fileEngineJson)) 128 if err != nil { 129 return err 130 } 131 132 engineJSON = string(buf) 133 } 134 135 data := struct { 136 FlogoJSON string 137 EngineJSON string 138 }{ 139 flogoJSON, 140 engineJSON, 141 } 142 143 f, err := os.Create(embedSrcPath) 144 if err != nil { 145 return err 146 } 147 RenderTemplate(f, tplFile, &data) 148 _ = f.Close() 149 150 return nil 151 } 152 153 func isNewMain(project common.AppProject) bool { 154 mainGo := filepath.Join(project.SrcDir(), fileMainGo) 155 buf, err := ioutil.ReadFile(mainGo) 156 if err == nil { 157 mainCode := string(buf) 158 return strings.Contains(mainCode, "cfgEngine") 159 160 } 161 162 return false 163 } 164 165 var tplEmbeddedAppGoFile = `// Do not change this file, it has been generated using flogo-cli 166 // If you change it and rebuild the application your changes might get lost 167 package main 168 169 // embedded flogo app descriptor file 170 const flogoJSON string = ` + "`{{.FlogoJSON}}`" + ` 171 const engineJSON string = ` + "`{{.EngineJSON}}`" + ` 172 173 func init () { 174 cfgJson = flogoJSON 175 cfgEngine = engineJSON 176 } 177 ` 178 179 var tplEmbeddedAppOldGoFile = `// Do not change this file, it has been generated using flogo-cli 180 // If you change it and rebuild the application your changes might get lost 181 package main 182 183 // embedded flogo app descriptor file 184 const flogoJSON string = ` + "`{{.FlogoJSON}}`" + ` 185 186 func init () { 187 cfgJson = flogoJSON 188 } 189 ` 190 191 func initMain(project common.AppProject, backupMain bool) error { 192 //backup main if it exists 193 mainGo := filepath.Join(project.SrcDir(), fileMainGo) 194 mainGoBak := filepath.Join(project.SrcDir(), fileMainGo+".bak") 195 196 if backupMain { 197 if _, err := os.Stat(mainGo); err == nil { 198 err = os.Rename(mainGo, mainGoBak) 199 if err != nil { 200 return err 201 } 202 } else if _, err := os.Stat(mainGoBak); err != nil { 203 return fmt.Errorf("project corrupt, main missing") 204 } 205 } else { 206 if _, err := os.Stat(mainGoBak); err == nil { 207 err = os.Rename(mainGoBak, mainGo) 208 if err != nil { 209 return err 210 } 211 } else if _, err := os.Stat(mainGo); err != nil { 212 return fmt.Errorf("project corrupt, main missing") 213 } 214 } 215 216 return nil 217 } 218 219 func optimizeImports(project common.AppProject) error { 220 221 appImports, err := util.GetAppImports(filepath.Join(project.Dir(), fileFlogoJson), project.DepManager(), true) 222 if err != nil { 223 return err 224 } 225 226 var unused []util.Import 227 appImports.GetAllImports() 228 for _, impDetails := range appImports.GetAllImportDetails() { 229 if !impDetails.Referenced() && impDetails.IsCoreContrib() { 230 unused = append(unused, impDetails.Imp) 231 } 232 } 233 234 importsFile := filepath.Join(project.SrcDir(), fileImportsGo) 235 importsFileOrig := filepath.Join(project.SrcDir(), fileImportsGo+".orig") 236 237 err = util.CopyFile(importsFile, importsFileOrig) 238 if err != nil { 239 return err 240 } 241 242 fset := token.NewFileSet() 243 file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly) 244 if err != nil { 245 return err 246 } 247 248 for _, i := range unused { 249 if Verbose() { 250 fmt.Printf(" Removing Import: %s\n", i.GoImportPath()) 251 } 252 util.DeleteImport(fset, file, i.GoImportPath()) 253 } 254 255 f, err := os.Create(importsFile) 256 defer f.Close() 257 if err := printer.Fprint(f, fset, file); err != nil { 258 return err 259 } 260 261 return nil 262 } 263 264 func restoreImports(project common.AppProject) { 265 importsFile := filepath.Join(project.SrcDir(), fileImportsGo) 266 importsFileOrig := filepath.Join(project.SrcDir(), fileImportsGo+".orig") 267 268 if _, err := os.Stat(importsFileOrig); err == nil { 269 err = util.CopyFile(importsFileOrig, importsFile) 270 if err != nil { 271 fmt.Fprintf(os.Stderr, "Error restoring imports file '%s': %v\n", importsFile, err) 272 return 273 } 274 275 var err = os.Remove(importsFileOrig) 276 if err != nil { 277 fmt.Fprintf(os.Stderr, "Error removing backup imports file '%s': %v\n", importsFileOrig, err) 278 fmt.Fprintf(os.Stderr, "Manually remove backup imports file '%s'\n", importsFileOrig) 279 } 280 } 281 }