plantuml duplication behavior
This commit is contained in:
+121
-23
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking/planner"
|
||||
"cloud.o-forge.io/core/oc-lib/models/collaborative_area/shallow_collaborative_area"
|
||||
@@ -108,9 +109,9 @@ func (d *Workflow) GetResources(dt tools.DataType) []resources.ResourceInterface
|
||||
return itf
|
||||
}
|
||||
|
||||
func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.APIRequest) (*Workflow, error) {
|
||||
func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.APIRequest) (*Workflow, []string, error) {
|
||||
if plantUML == nil {
|
||||
return d, errors.New("no file available to export")
|
||||
return d, nil, errors.New("no file available to export")
|
||||
}
|
||||
|
||||
defer plantUML.Close()
|
||||
@@ -189,9 +190,11 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return d, err
|
||||
return d, nil, err
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
for i, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
|
||||
@@ -237,14 +240,15 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A
|
||||
continue
|
||||
}
|
||||
|
||||
for n, new := range resourceCatalog {
|
||||
for n, newFn := range resourceCatalog {
|
||||
if strings.Contains(line, n+"(") && !strings.Contains(line, "!procedure") && !strings.Contains(line, "!define") {
|
||||
newRes := new()
|
||||
newRes := newFn()
|
||||
newRes.SetID(uuid.New().String())
|
||||
varName, graphItem, err := d.extractResourcePlantUML(parseLine, newRes, n, request.PeerID)
|
||||
varName, graphItem, warns, err := d.extractResourcePlantUML(parseLine, newRes, n, request.PeerID, request)
|
||||
if err != nil {
|
||||
return d, err
|
||||
return d, warnings, err
|
||||
}
|
||||
warnings = append(warnings, warns...)
|
||||
if graphItem != nil {
|
||||
graphVarName[varName] = *graphItem
|
||||
}
|
||||
@@ -258,10 +262,9 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A
|
||||
d.generateResource(d.GetResources(tools.STORAGE_RESOURCE), request)
|
||||
d.generateResource(d.GetResources(tools.COMPUTE_RESOURCE), request)
|
||||
d.generateResource(d.GetResources(tools.WORKFLOW_RESOURCE), request)
|
||||
d.generateResource(d.GetResources(tools.SERVICE_RESOURCE), request)
|
||||
d.generateResource(d.GetResources(tools.DYNAMIC_RESOURCE), request)
|
||||
d.Graph.Items = graphVarName
|
||||
return d, nil
|
||||
return d, warnings, nil
|
||||
}
|
||||
|
||||
func (d *Workflow) generateResource(datas []resources.ResourceInterface, request *tools.APIRequest) error {
|
||||
@@ -402,35 +405,46 @@ func (d *Workflow) extractLink(line string, graphVarName map[string]graph.GraphI
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Workflow) extractResourcePlantUML(line string, resource resources.ResourceInterface, dataName string, peerID string) (string, *graph.GraphItem, error) {
|
||||
func (d *Workflow) extractResourcePlantUML(line string, resource resources.ResourceInterface, dataName string, peerID string, request *tools.APIRequest) (string, *graph.GraphItem, []string, error) {
|
||||
splittedFunc := strings.Split(line, "(")
|
||||
if len(splittedFunc) <= 1 {
|
||||
return "", nil, errors.New("Can't deserialize Object, there's no func")
|
||||
return "", nil, nil, errors.New("Can't deserialize Object, there's no func")
|
||||
}
|
||||
splittedParams := strings.Split(splittedFunc[1], ",")
|
||||
if len(splittedParams) <= 1 {
|
||||
return "", nil, errors.New("Can't deserialize Object, there's no params")
|
||||
return "", nil, nil, errors.New("Can't deserialize Object, there's no params")
|
||||
}
|
||||
|
||||
varName := splittedParams[0]
|
||||
splitted := strings.Split(splittedParams[1], "\"")
|
||||
|
||||
if len(splitted) <= 1 {
|
||||
return "", nil, errors.New("Can't deserialize Object, there's no name")
|
||||
return "", nil, nil, errors.New("Can't deserialize Object, there's no name")
|
||||
}
|
||||
resource.SetName(strings.ReplaceAll(splitted[1], "\\n", " "))
|
||||
name := strings.ReplaceAll(splitted[1], "\\n", " ")
|
||||
|
||||
// Resources with instances get a default one seeded from the parent resource,
|
||||
// then overridden by any explicit comment attributes.
|
||||
// Event (NativeTool) has no instance: getNewInstance returns nil and is skipped.
|
||||
instance := d.getNewInstance(dataName, splitted[1], peerID)
|
||||
// Extract comment text (if present) for metadata parsing.
|
||||
comment := ""
|
||||
if parts := strings.Split(line, "'"); len(parts) > 1 {
|
||||
comment = strings.ReplaceAll(parts[1], "'", "")
|
||||
}
|
||||
|
||||
var warns []string
|
||||
|
||||
// Try to resolve an existing catalog resource (by id, then by name).
|
||||
if existing, warn := d.resolveExistingResource(resource, dataName, name, comment, request); existing != nil {
|
||||
warns = append(warns, warn)
|
||||
item := d.addExistingGraphItem(dataName, existing)
|
||||
return varName, item, warns, nil
|
||||
}
|
||||
|
||||
// No existing resource — create new.
|
||||
resource.SetName(name)
|
||||
instance := d.getNewInstance(dataName, name, peerID)
|
||||
if instance != nil {
|
||||
if b, err := json.Marshal(resource); err == nil {
|
||||
json.Unmarshal(b, instance)
|
||||
}
|
||||
splittedComments := strings.Split(line, "'")
|
||||
if len(splittedComments) > 1 {
|
||||
comment := strings.ReplaceAll(splittedComments[1], "'", "")
|
||||
if comment != "" {
|
||||
json.Unmarshal(parseHumanFriendlyAttrs(comment), instance)
|
||||
}
|
||||
resource.AddInstances(instance)
|
||||
@@ -441,7 +455,91 @@ func (d *Workflow) extractResourcePlantUML(line string, resource resources.Resou
|
||||
d.Graph.Items[item.ID] = *item
|
||||
}
|
||||
|
||||
return varName, item, nil
|
||||
return varName, item, warns, nil
|
||||
}
|
||||
|
||||
// resolveExistingResource tries to find an existing catalog resource matching
|
||||
// the given name or the id embedded in the PlantUML comment.
|
||||
// Returns (resource, warning message) or (nil, "") if none found.
|
||||
func (d *Workflow) resolveExistingResource(
|
||||
proto resources.ResourceInterface,
|
||||
dataName, name, comment string,
|
||||
request *tools.APIRequest,
|
||||
) (resources.ResourceInterface, string) {
|
||||
accessor := proto.GetAccessor(request)
|
||||
|
||||
// 1. Try lookup by id from comment ("id: <uuid>").
|
||||
if comment != "" {
|
||||
attrs := map[string]any{}
|
||||
json.Unmarshal(parseHumanFriendlyAttrs(comment), &attrs)
|
||||
if id, ok := attrs["id"].(string); ok && id != "" {
|
||||
if dbObj, _, err := accessor.LoadOne(id); err == nil && dbObj != nil {
|
||||
if ri, ok := dbObj.(resources.ResourceInterface); ok {
|
||||
return ri, fmt.Sprintf(`[import warning] %s "%s": existing resource retrieved by id %s`, dataName, name, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try search by exact name.
|
||||
filter := &dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"abstractobject.name": {{Operator: dbs.EQUAL.String(), Value: name}},
|
||||
},
|
||||
}
|
||||
if results, _, err := accessor.Search(filter, "", false, 0, 10); err == nil {
|
||||
for _, r := range results {
|
||||
if r.GetName() == name {
|
||||
if dbObj, _, err2 := accessor.LoadOne(r.GetID()); err2 == nil && dbObj != nil {
|
||||
if ri, ok := dbObj.(resources.ResourceInterface); ok {
|
||||
return ri, fmt.Sprintf(`[import warning] %s "%s": existing resource found by name and retrieved instead of creating a new one`, dataName, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// addExistingGraphItem registers an already-existing resource in the workflow's
|
||||
// ID lists and graph, without adding it to the resource lists (so generateResource
|
||||
// won't try to store it again).
|
||||
func (d *Workflow) addExistingGraphItem(dataName string, resource resources.ResourceInterface) *graph.GraphItem {
|
||||
graphItem := &graph.GraphItem{
|
||||
ID: uuid.New().String(),
|
||||
ItemResource: &resources.ItemResource{},
|
||||
}
|
||||
switch dataName {
|
||||
case "Data":
|
||||
d.Datas = append(d.Datas, resource.GetID())
|
||||
if r, ok := resource.(*resources.DataResource); ok {
|
||||
graphItem.Data = r
|
||||
}
|
||||
case "Processing":
|
||||
d.Processings = append(d.Processings, resource.GetID())
|
||||
if r, ok := resource.(*resources.ProcessingResource); ok {
|
||||
graphItem.Processing = r
|
||||
}
|
||||
case "Service":
|
||||
d.Services = append(d.Services, resource.GetID())
|
||||
if r, ok := resource.(*resources.ServiceResource); ok {
|
||||
graphItem.Service = r
|
||||
}
|
||||
case "Storage":
|
||||
d.Storages = append(d.Storages, resource.GetID())
|
||||
if r, ok := resource.(*resources.StorageResource); ok {
|
||||
graphItem.Storage = r
|
||||
}
|
||||
case "ComputeUnit":
|
||||
d.Computes = append(d.Computes, resource.GetID())
|
||||
if r, ok := resource.(*resources.ComputeResource); ok {
|
||||
graphItem.Compute = r
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return graphItem
|
||||
}
|
||||
|
||||
func (d *Workflow) getNewGraphItem(dataName string, resource resources.ResourceInterface) *graph.GraphItem {
|
||||
|
||||
Reference in New Issue
Block a user