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