in internal/system/appsdiscovery/apps_discovery.go [882:970]
func parseR3transOutput(ctx context.Context, s string) (wlProps *spb.SapDiscovery_WorkloadProperties) {
log.CtxLogger(ctx).Debugw("R3trans exported data", "fileString", s)
lines := strings.Split(s, "\n")
cversLines := false
prdversLines := false
cversEntries := []*spb.SapDiscovery_WorkloadProperties_SoftwareComponentProperties{}
prdversEntries := []*spb.SapDiscovery_WorkloadProperties_ProductVersion{}
for _, l := range lines {
if strings.Contains(l, "CVERS") && strings.Contains(l, "REP") {
cversLines, prdversLines = true, false
} else if strings.Contains(l, "PRDVERS") && strings.Contains(l, "REP") {
prdversLines, cversLines = true, false
} else if !strings.Contains(l, "**") {
cversLines, prdversLines = false, false
} else {
if cversLines {
// Example line : "4 ETW000 ** 102 ** SAP_ABA 750 0025 S"
cversSplit := strings.Split(l, "**")
re := regexp.MustCompile("\\s+")
if len(cversSplit) < 1 {
log.CtxLogger(ctx).Infow("cvers entry does not have enough fields", "fields", cversSplit, "len(fields)", len(cversSplit))
continue
}
// Taking everything after the "**" which is "SAP_ABA 750 0025 S"
// And splitting that on any number of spaces.
fields := re.Split(strings.TrimSpace(cversSplit[len(cversSplit)-1]), -1)
cversEntry := map[string]string{}
if len(fields) > 0 {
cversEntry["name"] = fields[0]
}
if len(fields) > 1 {
cversEntry["version"] = fields[1]
}
if len(fields) > 2 {
cversEntry["ext_version"] = fields[2]
}
if len(fields) == 3 {
// The last two fields are combined.
if len(fields[2]) < 1 {
log.CtxLogger(ctx).Infow("Parsing component encountered ext_version that is too short.", "fields[2]", fields[2], "len(fields[2])", len(fields[2]))
continue
}
// This looks like "0000000000S" where "0000000000" is the ext_version and "S" is the type.
cversEntry["ext_version"] = string(fields[2][0 : len(fields[2])-1])
cversEntry["type"] = string(fields[2][len(fields[2])-1])
}
if len(fields) > 3 {
cversEntry["type"] = fields[3]
}
cversObj := &spb.SapDiscovery_WorkloadProperties_SoftwareComponentProperties{
Name: cversEntry["name"],
Version: cversEntry["version"],
ExtVersion: cversEntry["ext_version"],
Type: cversEntry["type"],
}
cversEntries = append(cversEntries, cversObj)
}
if prdversLines {
re := regexp.MustCompile("\\s\\s+")
// Example of what this looks like:
// 4 ETW000 ** 394 ** 73554900100900000414SAP NETWEAVER 7.5 sap.com SAP NETWEAVER 7.5 +20220927121631
// We split on multiple consecutive spaces so that we don't split in the middle of a given field.
prdversSplit := re.Split(l, -1)
if len(prdversSplit) < 2 {
log.CtxLogger(ctx).Infow("prdvers entry does not have enough fields", "fields", prdversSplit, "len(fields)", len(prdversSplit))
continue
}
// Extracting the second to last element here gives us "SAP NETWEAVER 7.5"
fields := prdversSplit[len(prdversSplit)-2]
// Find the last space in the product description. This separates the name from the version.
lastIndex := strings.LastIndex(fields, " ")
if lastIndex < 0 {
log.CtxLogger(ctx).Infow("Failed to distinguish name from version for prdvers entry", "fields", fields, "len(fields)", len(fields))
prdversEntries = append(prdversEntries, &spb.SapDiscovery_WorkloadProperties_ProductVersion{Name: fields})
continue
}
prvdersObj := &spb.SapDiscovery_WorkloadProperties_ProductVersion{
Name: fields[:lastIndex],
Version: fields[lastIndex+1:],
}
prdversEntries = append(prdversEntries, prvdersObj)
}
}
}
return &spb.SapDiscovery_WorkloadProperties{
ProductVersions: prdversEntries,
SoftwareComponentVersions: cversEntries,
}
}