github.com/r2d2-ai/cli@v1.20.0/api/shim.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "path" 9 "path/filepath" 10 "regexp" 11 "strings" 12 13 "github.com/r2d2-ai/cli/common" 14 "github.com/r2d2-ai/cli/util" 15 ) 16 17 const ( 18 fileShimSupportGo string = "shim_support.go" 19 fileShimGo string = "shim.go" 20 fileBuildGo string = "build.go" 21 fileMakefile string = "Makefile" 22 dirShim string = "shim" 23 ) 24 25 var fileSampleShimSupport = filepath.Join("examples", "engine", "shim", fileShimSupportGo) 26 27 var flogoImportPattern = regexp.MustCompile(`^(([^ ]*)[ ]+)?([^@:]*)@?([^:]*)?:?(.*)?$`) 28 29 type ShimBuilder struct { 30 appBuilder common.Builder 31 shim string 32 } 33 34 func (sb *ShimBuilder) Build(project common.AppProject) error { 35 36 err := backupMain(project) 37 if err != nil { 38 return err 39 } 40 41 defer shimCleanup(project) 42 43 err = createShimSupportGoFile(project) 44 if err != nil { 45 return err 46 } 47 48 if Verbose() { 49 fmt.Println("Preparing shim...") 50 } 51 built, err := prepareShim(project, sb.shim) 52 if err != nil { 53 return err 54 } 55 56 if !built { 57 fmt.Println("Using go build to build shim...") 58 59 err := simpleGoBuild(project) 60 if err != nil { 61 return err 62 } 63 } 64 65 return nil 66 } 67 68 func prepareShim(project common.AppProject, shim string) (bool, error) { 69 70 buf, err := ioutil.ReadFile(filepath.Join(project.Dir(), fileFlogoJson)) 71 if err != nil { 72 return false, err 73 } 74 75 flogoJSON := string(buf) 76 77 descriptor, err := util.ParseAppDescriptor(flogoJSON) 78 if err != nil { 79 return false, err 80 } 81 82 err = registerImports(project, descriptor) 83 if err != nil { 84 return false, err 85 } 86 87 for _, trgCfg := range descriptor.Triggers { 88 if trgCfg.Id == shim { 89 90 ref := trgCfg.Ref 91 92 if trgCfg.Ref != "" { 93 found := false 94 ref, found = GetAliasRef("flogo:trigger", trgCfg.Ref) 95 if !found { 96 return false, fmt.Errorf("unable to determine ref for trigger: %s", trgCfg.Id) 97 } 98 } 99 100 refImport, err := util.NewFlogoImportFromPath(ref) 101 if err != nil { 102 return false, err 103 } 104 105 impPath, err := project.GetPath(refImport) 106 if err != nil { 107 return false, err 108 } 109 110 var shimFilePath string 111 112 shimFilePath = filepath.Join(impPath, dirShim, fileShimGo) 113 114 if _, err := os.Stat(shimFilePath); err == nil { 115 116 err = util.CopyFile(shimFilePath, filepath.Join(project.SrcDir(), fileShimGo)) 117 if err != nil { 118 return false, err 119 } 120 121 // Check if this shim based trigger has a gobuild file. If the trigger has a gobuild 122 // execute that file, otherwise check if there is a Makefile to execute 123 goBuildFilePath := filepath.Join(impPath, dirShim, fileBuildGo) 124 125 makefilePath := filepath.Join(shimFilePath, dirShim, fileMakefile) 126 127 if _, err := os.Stat(goBuildFilePath); err == nil { 128 fmt.Println("Using build.go to build shim......") 129 130 err = util.CopyFile(goBuildFilePath, filepath.Join(project.SrcDir(), fileBuildGo)) 131 if err != nil { 132 return false, err 133 } 134 135 // Execute go run gobuild.go 136 err = util.ExecCmd(exec.Command("go", "run", fileBuildGo), project.SrcDir()) 137 if err != nil { 138 return false, err 139 } 140 141 return true, nil 142 } else if _, err := os.Stat(makefilePath); err == nil { 143 //look for Makefile and execute it 144 fmt.Println("Using make file to build shim...") 145 146 err = util.CopyFile(makefilePath, filepath.Join(project.SrcDir(), fileMakefile)) 147 if err != nil { 148 return false, err 149 } 150 151 if Verbose() { 152 fmt.Println("Make File:", makefilePath) 153 } 154 155 // Execute make 156 cmd := exec.Command("make", "-C", project.SrcDir()) 157 cmd.Stdout = os.Stdout 158 cmd.Stderr = os.Stderr 159 cmd.Env = util.ReplaceEnvValue(os.Environ(), "GOPATH", project.Dir()) 160 161 err = cmd.Run() 162 if err != nil { 163 return false, err 164 } 165 166 return true, nil 167 } else { 168 return false, nil 169 } 170 } 171 172 break 173 } 174 } 175 176 return false, fmt.Errorf("unable to to find shim trigger: %s", shim) 177 } 178 179 func shimCleanup(project common.AppProject) { 180 181 if Verbose() { 182 fmt.Println("Cleaning up shim support files...") 183 } 184 185 err := util.DeleteFile(filepath.Join(project.SrcDir(), fileShimSupportGo)) 186 if err != nil { 187 fmt.Printf("Unable to delete: %s", fileShimSupportGo) 188 } 189 err = util.DeleteFile(filepath.Join(project.SrcDir(), fileShimGo)) 190 if err != nil { 191 fmt.Printf("Unable to delete: %s", fileShimGo) 192 } 193 err = util.DeleteFile(filepath.Join(project.SrcDir(), fileBuildGo)) 194 if err != nil { 195 fmt.Printf("Unable to delete: %s", fileBuildGo) 196 } 197 } 198 199 func createShimSupportGoFile(project common.AppProject) error { 200 201 shimSrcPath := filepath.Join(project.SrcDir(), fileShimSupportGo) 202 203 if Verbose() { 204 fmt.Println("Creating shim support files...") 205 } 206 207 flogoCoreImport, err := util.NewFlogoImportFromPath(flogoCoreRepo) 208 if err != nil { 209 return err 210 } 211 212 corePath, err := project.GetPath(flogoCoreImport) 213 if err != nil { 214 return err 215 } 216 217 bytes, err := ioutil.ReadFile(filepath.Join(corePath, fileSampleShimSupport)) 218 if err != nil { 219 return err 220 } 221 222 err = ioutil.WriteFile(shimSrcPath, bytes, 0644) 223 if err != nil { 224 return err 225 } 226 227 return nil 228 } 229 230 func registerImports(project common.AppProject, appDesc *util.FlogoAppDescriptor) error { 231 232 for _, anImport := range appDesc.Imports { 233 err := registerImport(project, anImport) 234 if err != nil { 235 return err 236 } 237 } 238 239 return nil 240 } 241 242 func registerImport(project common.AppProject, anImport string) error { 243 244 matches := flogoImportPattern.FindStringSubmatch(anImport) 245 246 parts := strings.Split(matches[3], " ") 247 248 var alias string 249 var ref string 250 numParts := len(parts) 251 if numParts == 1 { 252 ref = parts[0] 253 alias = path.Base(ref) 254 255 } else if numParts == 2 { 256 alias = parts[0] 257 ref = parts[1] 258 } else { 259 return fmt.Errorf("invalid import %s", anImport) 260 } 261 262 if alias == "" || ref == "" { 263 return fmt.Errorf("invalid import %s", anImport) 264 } 265 266 ct, err := util.GetContribType(project.DepManager(), ref) 267 if err != nil { 268 return err 269 } 270 271 if ct != "" { 272 RegisterAlias(ct, alias, ref) 273 } 274 275 return nil 276 } 277 278 var aliases = make(map[string]map[string]string) 279 280 func RegisterAlias(contribType string, alias, ref string) { 281 282 aliasToRefMap, exists := aliases[contribType] 283 if !exists { 284 aliasToRefMap = make(map[string]string) 285 aliases[contribType] = aliasToRefMap 286 } 287 288 aliasToRefMap[alias] = ref 289 } 290 291 func GetAliasRef(contribType string, alias string) (string, bool) { 292 if alias == "" { 293 return "", false 294 } 295 296 if alias[0] == '#' { 297 alias = alias[1:] 298 } 299 aliasToRefMap, exists := aliases[contribType] 300 if !exists { 301 return "", false 302 } 303 304 ref, exists := aliasToRefMap[alias] 305 if !exists { 306 return "", false 307 } 308 309 return ref, true 310 }