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