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 }