in packages/zypper.go [281:422]
func parseZypperPatchInfo(out []byte) (map[string][]string, error) {
/*
Loading repository data...
Reading installed packages...
Information for patch SUSE-SLE-SERVER-12-SP4-2019-2974:
-------------------------------------------------------
Repository : SLES12-SP4-Updates
Name : SUSE-SLE-SERVER-12-SP4-2019-2974
Version : 1
Arch : noarch
Vendor : maint-coord@suse.de
Status : needed
Category : recommended
Severity : important
Created On : Thu Nov 14 13:17:48 2019
Interactive : ---
Summary : Recommended update for irqbalance
Description :
This update for irqbalance fixes the following issues:
- Irqbalanced spreads the IRQs between the available virtual machines. (bsc#1119465, bsc#1154905)
Provides : patch:SUSE-SLE-SERVER-12-SP4-2019-2974 = 1
Conflicts : [2]
irqbalance.src < 1.1.0-9.3.1
irqbalance.x86_64 < 1.1.0-9.3.1
*/
patchInfo := make(map[string][]string)
var validConflictLine = regexp.MustCompile(`\s*Conflicts\s*:\s*\[\d*\]\s*`)
var conflictLineExtract = regexp.MustCompile(`\[[0-9]+\]`)
var nameLine = regexp.MustCompile(`\s*Name\s*:\s*`)
lines := bytes.Split(bytes.TrimSpace(out), []byte("\n"))
i := 0
for {
// find the name line
for ; i < len(lines); i++ {
b := nameLine.Find([]byte(lines[i]))
if b != nil {
break
}
}
if i >= len(lines) {
// we do not have any more patch info blobs
break
}
parts := strings.Split(string(lines[i]), ":")
i++
if len(parts) != 2 {
return nil, fmt.Errorf("invalid name output")
}
patchName := strings.Trim(parts[1], " ")
for ; i < len(lines); i++ {
b := validConflictLine.Find([]byte(lines[i]))
if b != nil {
// Conflicts : [2]
break
}
}
if i >= len(lines) {
// did not find conflicting packages
// this should not happen
return nil, nil
}
matches := conflictLineExtract.FindAllString(string(lines[i]), -1)
if len(matches) != 1 {
return nil, fmt.Errorf("invalid patch info")
}
// get the number of package lines to parse
conflicts := strings.Trim(matches[0], "[")
conflicts = strings.Trim(conflicts, "]")
conflictLines, err := strconv.Atoi(conflicts)
if err != nil {
return nil, fmt.Errorf("invalid patch info: invalid conflict info")
}
ctr := i + 1
ctrEnd := ctr + conflictLines
for ; ctr < ctrEnd; ctr++ {
//libsolv.src < 0.6.36-2.27.19.8
//libsolv-tools.x86_64 < 0.6.36-2.27.19.8
//libzypp.src < 16.20.2-27.60.4
//libzypp.x86_64 < 16.20.2-27.60.4
//perl-solv.x86_64 < 0.6.36-2.27.19.8
//python-solv.x86_64 < 0.6.36-2.27.19.8
//zypper.src < 1.13.54-18.40.2
//zypper.x86_64 < 1.13.54-18.40.2
//zypper-log < 1.13.54-18.40.2
//srcpackage:ruby2.5 < 2.5.9-150000.4.29.1
//ruby2.5.noarch < 2.5.9-150000.4.29.1
//ruby2.5.x86_64 < 2.5.9-150000.4.29.1
//srcpackage:zypper
//zypper-log < 1.14.64-150400.3.32.1
//zypper-needs-restarting < 1.14.64-150400.3.32.1
parts := strings.Split(string(lines[ctr]), "<")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid package info, can't parse line: %v", string(lines[ctr]))
}
nameArch := parts[0]
pkgName := ""
if strings.Contains(nameArch, "srcpackage:") {
colonIdx := strings.Index(nameArch, ":")
pkgName = strings.Trim(nameArch[colonIdx+1:], " ")
if len(pkgName) == 0 {
return nil, fmt.Errorf("invalid package info, can't parse line: %v", string(lines[ctr]))
}
} else {
// Get the last index to handle the case if pkg has float version
// (e.g. `ruby2.5.noarch < 2.5.9-150000.4.29.1`)
lastDotIdx := strings.LastIndex(nameArch, ".")
// In case if there's NO dot exist, then the package name doen't contain
// the architecture details (`e.g. zypper-log < 1.14.64-150400.3.32.1`)
if lastDotIdx == -1 {
pkgName = strings.Trim(nameArch, " ")
} else {
pkgName = strings.Trim(nameArch[:lastDotIdx], " ")
}
}
patches, ok := patchInfo[pkgName]
if !ok {
patches = make([]string, 0)
}
patches = append(patches, patchName)
patchInfo[pkgName] = patches
}
// set i for next patch information blob
i = ctrEnd
}
// TODO: instead of returning a map of <string, []string>
// make it more concrete type returns with more information
// about the package and patch
if len(patchInfo) == 0 {
return nil, fmt.Errorf("invalid patch information, did not find patch blobs")
}
return patchInfo, nil
}