github.com/r2d2-ai/cli@v1.20.0/util/engine.go (about)

     1  package util
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  )
    10  
    11  // PartialEngineDescriptor is the descriptor for a Flogo application
    12  type PartialEngineDescriptor struct {
    13  	Imports  []string               `json:"imports"`
    14  	Services []*EngineServiceDetails `json:"services"`
    15  }
    16  
    17  type EngineServiceDetails struct {
    18  	Ref string
    19  }
    20  
    21  type EngineImportDetails struct {
    22  	Imp          Import
    23  	TopLevel     bool // a toplevel import i.e. from imports section
    24  	ServiceRef  bool // imports is used by a service
    25  
    26  	HasAliasRef  bool // imports alias is used by a contrib reference
    27  	HasDirectRef bool // a direct reference exists for this import
    28  }
    29  
    30  type EngineImports struct {
    31  	imports     map[string]*EngineImportDetails
    32  	orphanedRef map[string]void
    33  	depManager      DepManager
    34  }
    35  
    36  func (ai *EngineImports) addImports(imports []string) error {
    37  	for _, anImport := range imports {
    38  		flogoImport, err := ParseImport(anImport)
    39  		if err != nil {
    40  			return err
    41  		}
    42  
    43  		if _, exists := ai.imports[flogoImport.GoImportPath()]; exists {
    44  			//todo warn about duplicate import?
    45  			continue
    46  		}
    47  
    48  		details := &EngineImportDetails{Imp: flogoImport, TopLevel:true}
    49  		ai.imports[flogoImport.GoImportPath()] = details
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  func (ai *EngineImports) addReference(ref string, isService bool) error {
    56  	cleanedRef := strings.TrimSpace(ref)
    57  
    58  	if cleanedRef[0] == '#' {
    59  
    60  		alias := cleanedRef[1:]
    61  		found := false
    62  		for _, importDetails := range ai.imports {
    63  
    64  			if importDetails.TopLevel {
    65  				// alias refs can only be to toplevel imports
    66  				if importDetails.Imp.CanonicalAlias() == alias {
    67  					importDetails.HasAliasRef = true
    68  					importDetails.ServiceRef = isService
    69  					found = true
    70  					break
    71  				}
    72  			}
    73  		}
    74  
    75  		if !found {
    76  			ai.orphanedRef[cleanedRef] = void{}
    77  		}
    78  
    79  	} else {
    80  		flogoImport, err := ParseImport(ref)
    81  		if err != nil {
    82  			return err
    83  		}
    84  
    85  		if imp, exists := ai.imports[flogoImport.GoImportPath()]; exists {
    86  			if !imp.TopLevel {
    87  				//already accounted for
    88  				return nil
    89  			}
    90  
    91  			imp.HasDirectRef = true
    92  			imp.ServiceRef = true
    93  			return nil
    94  		}
    95  
    96  		//doesn't exists so add new import
    97  		details  := &EngineImportDetails{Imp: flogoImport, ServiceRef:isService}
    98  		ai.imports[flogoImport.GoImportPath()] = details
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  func (ai *EngineImports) GetOrphanedReferences() []string {
   105  	var refs []string
   106  	for ref := range ai.orphanedRef {
   107  		refs = append(refs, ref)
   108  	}
   109  
   110  	return refs
   111  }
   112  
   113  func (ai *EngineImports) GetAllImports() []Import {
   114  	var allImports []Import
   115  	for _, details := range ai.imports {
   116  		allImports = append(allImports, details.Imp)
   117  	}
   118  
   119  	return allImports
   120  }
   121  
   122  func (ai *EngineImports) GetAllImportDetails() []*EngineImportDetails {
   123  
   124  	var allImports []*EngineImportDetails
   125  	for _, details := range ai.imports {
   126  		allImports = append(allImports, details)
   127  	}
   128  
   129  	return allImports
   130  }
   131  
   132  func GetEngineImports(engJsonFile string, depManager DepManager) (*EngineImports, error) {
   133  	engJson, err := os.Open(engJsonFile)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	bytes, err := ioutil.ReadAll(engJson)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	engDesc := &PartialEngineDescriptor{}
   144  	err = json.Unmarshal(bytes, engDesc)
   145  	if err != nil {
   146  		fmt.Fprintf(os.Stderr, "Unable to unmarshal flogo engine json: %s", engJsonFile)
   147  		return nil, err
   148  	}
   149  
   150  	imports := make(map[string]void)
   151  
   152  	if len(engDesc.Imports) > 0 {
   153  		for _, imp := range engDesc.Imports {
   154  			imports[imp] = void{}
   155  		}
   156  	}
   157  
   158  	if len(engDesc.Services) > 0 {
   159  		for _, service := range engDesc.Services {
   160  			imports[service.Ref] = void{}
   161  		}
   162  	}
   163  
   164  
   165  	ai := &EngineImports{depManager: depManager}
   166  	ai.imports = make(map[string]*EngineImportDetails)
   167  	ai.orphanedRef = make(map[string]void)
   168  
   169  	err = ai.addImports(engDesc.Imports)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	// add service refs/imports
   175  	for _, serviceDetails := range engDesc.Services {
   176  		err := ai.addReference(serviceDetails.Ref, true)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  	}
   181  
   182  	return ai, err
   183  }