github.com/TIBCOSoftware/flogo-lib@v0.5.9/flogo/gen/gen.go (about)

     1  package main
     2  
     3  import (
     4  	"path/filepath"
     5  	"io/ioutil"
     6  	"os"
     7  	"go/build"
     8  	"fmt"
     9  	"encoding/json"
    10  	"strings"
    11  	"text/template"
    12  	"io"
    13  )
    14  
    15  func main()  {
    16  	args := os.Args
    17  
    18  	fmt.Println("Generating flogo metadata in ", args[1])
    19  
    20  	generateGoMetadata(args[1])
    21  }
    22  
    23  func generateGoMetadata(dir string) error {
    24  	//todo optimize metadata recreation to minimize compile times
    25  	dependencies, err := ListDependencies(dir)
    26  
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	for _, dependency := range dependencies {
    32  
    33  		fmt.Println("Generating flogo metadata for:", dependency.Ref)
    34  
    35  		createMetadata(dependency)
    36  	}
    37  
    38  	return nil
    39  }
    40  
    41  func createMetadata(dependency *Dependency) error {
    42  
    43  	var mdFilePath string
    44  	var mdGoFilePath string
    45  	var tplMetadata string
    46  
    47  	switch dependency.ContribType {
    48  	case ACTION:
    49  		mdFilePath = filepath.Join(dependency.Dir, "action.json")
    50  		mdGoFilePath = filepath.Join(dependency.Dir, "action_metadata.go")
    51  		tplMetadata = tplMetadataGoFile
    52  	case TRIGGER:
    53  		mdFilePath = filepath.Join(dependency.Dir, "trigger.json")
    54  		mdGoFilePath = filepath.Join(dependency.Dir, "trigger_metadata.go")
    55  		tplMetadata = tplTriggerMetadataGoFile
    56  	case ACTIVITY:
    57  		mdFilePath = filepath.Join(dependency.Dir, "activity.json")
    58  		mdGoFilePath = filepath.Join(dependency.Dir, "activity_metadata.go")
    59  		tplMetadata = tplActivityMetadataGoFile
    60  	default:
    61  		return nil
    62  	}
    63  
    64  	raw, err := ioutil.ReadFile(mdFilePath)
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	info := &struct {
    70  		Package      string
    71  		MetadataJSON string
    72  	}{
    73  		Package:      filepath.Base(dependency.Dir),
    74  		MetadataJSON: string(raw),
    75  	}
    76  
    77  	f, _ := os.Create(mdGoFilePath)
    78  	RenderTemplate(f, tplMetadata, info)
    79  	f.Close()
    80  
    81  	return nil
    82  }
    83  
    84  var tplMetadataGoFile = `package {{.Package}}
    85  
    86  var jsonMetadata = ` + "`{{.MetadataJSON}}`" + `
    87  
    88  func getJsonMetadata() string {
    89  	return jsonMetadata
    90  }
    91  `
    92  
    93  var tplActivityMetadataGoFile = `package {{.Package}}
    94  
    95  import (
    96  	"github.com/TIBCOSoftware/flogo-lib/core/activity"
    97  )
    98  
    99  var jsonMetadata = ` + "`{{.MetadataJSON}}`" + `
   100  
   101  // init create & register activity
   102  func init() {
   103  	md := activity.NewMetadata(jsonMetadata)
   104  	activity.Register(NewActivity(md))
   105  }
   106  `
   107  
   108  var tplTriggerMetadataGoFile = `package {{.Package}}
   109  
   110  import (
   111  	"github.com/TIBCOSoftware/flogo-lib/core/trigger"
   112  )
   113  
   114  var jsonMetadata = ` + "`{{.MetadataJSON}}`" + `
   115  
   116  // init create & register trigger factory
   117  func init() {
   118  	md := trigger.NewMetadata(jsonMetadata)
   119  	trigger.RegisterFactory(md.ID, NewFactory(md))
   120  }
   121  `
   122  
   123  func ListDependencies(dir string) ([]*Dependency, error) {
   124  
   125  	var cType ContribType
   126  
   127  	// Get build context
   128  	bc := build.Default
   129  	currentGoPath := bc.GOPATH
   130  	bc.GOPATH = dir
   131  	//dir, _ := os.Getwd()
   132  	//fmt.Println("gopath:", dir)
   133  	ndir := "."
   134  	//fmt.Println("dir:", ndir)
   135  
   136  	defer func() { bc.GOPATH = currentGoPath }()
   137  	pkgs, err := bc.ImportDir(ndir, 0)
   138  	if err != nil {
   139  		//fmt.Println("err:", err)
   140  		return nil, err
   141  	}
   142  	//fmt.Println("pkgs:",pkgs)
   143  
   144  	var deps []*Dependency
   145  	// Get all imports
   146  	for _, imp := range pkgs.Imports {
   147  
   148  		//fmt.Println("imp:",imp)
   149  
   150  		pkg, err := bc.Import(imp, ndir, build.FindOnly)
   151  		if err != nil {
   152  			//fmt.Println("import err:",err)
   153  			// Ignore package
   154  			continue
   155  		}
   156  
   157  		//fmt.Println("pkg:",pkg.Dir)
   158  
   159  		if cType == 0 || cType == ACTION {
   160  			filePath := filepath.Join(pkg.Dir, "action.json")
   161  			// Check if it is an action
   162  			info, err := os.Stat(filePath)
   163  			if err == nil {
   164  				desc, err := readDescriptor(filePath, info)
   165  				if err == nil && desc.Type == "flogo:action" {
   166  					deps = append(deps, &Dependency{ContribType: ACTION, Ref: imp, Dir: pkg.Dir})
   167  				}
   168  			}
   169  		}
   170  		if cType == 0 || cType == TRIGGER {
   171  			filePath := filepath.Join(pkg.Dir, "trigger.json")
   172  			// Check if it is a trigger
   173  			info, err := os.Stat(filePath)
   174  			if err == nil {
   175  				desc, err := readDescriptor(filePath, info)
   176  				if err == nil && desc.Type == "flogo:trigger" {
   177  					deps = append(deps, &Dependency{ContribType: TRIGGER, Ref: imp, Dir: pkg.Dir})
   178  				}
   179  			}
   180  		}
   181  		if cType == 0 || cType == ACTIVITY {
   182  			filePath := filepath.Join(pkg.Dir, "activity.json")
   183  			// Check if it is an activity
   184  			info, err := os.Stat(filePath)
   185  			if err == nil {
   186  				desc, err := readDescriptor(filePath, info)
   187  				if err == nil && desc.Type == "flogo:activity" {
   188  					deps = append(deps, &Dependency{ContribType: ACTIVITY, Ref: imp, Dir: pkg.Dir})
   189  				}
   190  			}
   191  		}
   192  	}
   193  	return deps, nil
   194  }
   195  
   196  func readDescriptor(path string, info os.FileInfo) (*Descriptor, error) {
   197  
   198  	raw, err := ioutil.ReadFile(path)
   199  	if err != nil {
   200  		fmt.Println("error: " + err.Error())
   201  		return nil, err
   202  	}
   203  
   204  	return ParseDescriptor(string(raw))
   205  }
   206  
   207  // ParseDescriptor parse a descriptor
   208  func ParseDescriptor(descJson string) (*Descriptor, error) {
   209  	descriptor := &Descriptor{}
   210  
   211  	err := json.Unmarshal([]byte(descJson), descriptor)
   212  
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	return descriptor, nil
   218  }
   219  
   220  type Descriptor struct {
   221  	Name        string `json:"name"`
   222  	Version     string `json:"version"`
   223  	Description string `json:"description"`
   224  	Type        string `json:"type"`
   225  }
   226  
   227  type Dependency struct {
   228  	ContribType ContribType
   229  	Ref         string
   230  	Dir         string
   231  }
   232  
   233  func (d *Dependency) MarshalJSON() ([]byte, error) {
   234  	return json.Marshal(&struct {
   235  		ContribType string `json:"type"`
   236  		Ref         string `json:"ref"`
   237  	}{
   238  		ContribType: d.ContribType.String(),
   239  		Ref:         d.Ref,
   240  	})
   241  }
   242  
   243  func (d *Dependency) UnmarshalJSON(data []byte) error {
   244  	ser := &struct {
   245  		ContribType string `json:"type"`
   246  		Ref         string `json:"ref"`
   247  	}{}
   248  
   249  	if err := json.Unmarshal(data, ser); err != nil {
   250  		return err
   251  	}
   252  
   253  	d.Ref = ser.Ref
   254  	d.ContribType = ToContribType(ser.ContribType)
   255  
   256  	return nil
   257  }
   258  
   259  type ContribType int
   260  
   261  const (
   262  	ACTION ContribType = 1 + iota
   263  	TRIGGER
   264  	ACTIVITY
   265  )
   266  
   267  var ctStr = [...]string{
   268  	"all",
   269  	"action",
   270  	"trigger",
   271  	"activity",
   272  }
   273  
   274  func (m ContribType) String() string { return ctStr[m] }
   275  
   276  func ToContribType(name string) ContribType {
   277  	switch name {
   278  	case "action":
   279  		return ACTION
   280  	case "trigger":
   281  		return TRIGGER
   282  	case "activity":
   283  		return ACTIVITY
   284  	case "all":
   285  		return 0
   286  	}
   287  
   288  	return -1
   289  }
   290  
   291  //RenderTemplate renders the specified template
   292  func RenderTemplate(w io.Writer, text string, data interface{}) {
   293  	t := template.New("top")
   294  	t.Funcs(template.FuncMap{"trim": strings.TrimSpace})
   295  	template.Must(t.Parse(text))
   296  	if err := t.Execute(w, data); err != nil {
   297  		panic(err)
   298  	}
   299  }