Skip to content

Instantly share code, notes, and snippets.

@jlsherrill
Created October 22, 2024 17:55
Show Gist options
  • Save jlsherrill/182d330896194a6df20e7ae8f881cb96 to your computer and use it in GitHub Desktop.
Save jlsherrill/182d330896194a6df20e7ae8f881cb96 to your computer and use it in GitHub Desktop.
Generate csvs with list of packages and number of errata from updateinfo.xml files
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"slices"
"time"
)
type Updates struct {
XMLName xml.Name `xml:"updates"`
Updates []Update `xml:"update"`
}
type Update struct {
XMLName xml.Name `xml:"update"`
Type string `xml:"type,attr"`
Issued Issued `xml:"issued"`
PkgList PkgList `xml:"pkglist"`
}
type Issued struct {
XMLName xml.Name `xml:"issued"`
Date customTime `xml:"date,attr"`
}
type customTime struct {
time.Time
}
func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
parse, _ := time.Parse("2006-01-02 15:04:05 UTC", attr.Value)
*c = customTime{parse}
return nil
}
type PkgList struct {
XMLName xml.Name `xml:"pkglist"`
PkgCollections []PkgCollection `xml:"collection"`
}
type PkgCollection struct {
XMLName xml.Name `xml:"collection"`
Packages []Package `xml:"package"`
}
type Package struct {
XMLName xml.Name `xml:"package"`
Name string `xml:"name,attr"`
Arch string `xml:"arch,attr"`
}
func LoadXml(file string) (*Updates, error) {
var updates Updates
xmlFile, err := os.Open(fmt.Sprintf("xml/%s", file))
if err != nil {
return nil, err
}
byteValue, _ := ioutil.ReadAll(xmlFile)
err = xml.Unmarshal(byteValue, &updates)
if err != nil {
return nil, err
}
return &updates, nil
}
func processOS(appstream string, baseos string, outputFilename string, includeAfter time.Time) error {
m := make(map[string]int)
updates, err := LoadXml(appstream)
if err != nil {
return fmt.Errorf("Error loading XML: %v", err)
}
err = processUpdates(m, updates.Updates, includeAfter)
if err != nil {
return fmt.Errorf("Error processing updates for appstream: %v", err)
}
updates, err = LoadXml(baseos)
if err != nil {
return fmt.Errorf("Error loading XML for baseos: %v", err)
}
err = processUpdates(m, updates.Updates, includeAfter)
if err != nil {
return fmt.Errorf("Error processing updates for baseos: %v", err)
}
file, err := os.Create(outputFilename)
if err != nil {
return fmt.Errorf("Error creating output file: %v", err)
}
for k, v := range m {
_, err = file.WriteString(fmt.Sprintf("%s,%d\n", k, v))
if err != nil {
return fmt.Errorf("Error writing to output file: %v", err)
}
}
return nil
}
func processUpdates(tracker map[string]int, updates []Update, includeAfter time.Time) error {
for _, update := range updates {
pkgsForUpdate := []string{}
if update.Issued.Date.Before(includeAfter) {
continue
}
if update.Type != "security" {
continue
}
for _, pkgList := range update.PkgList.PkgCollections {
for _, pkg := range pkgList.Packages {
if !slices.Contains(pkgsForUpdate, pkg.Name) {
pkgsForUpdate = append(pkgsForUpdate, pkg.Name)
}
}
}
// For each update add each package to the map, or increment it by 1 if its there
for _, name := range pkgsForUpdate {
tracker[name] = tracker[name] + 1
}
}
return nil
}
func main() {
thisYear := time.Date(2024, 01, 01, 0, 0, 0, 0, time.UTC)
err := processOS("9_appstream.xml", "9_baseos.xml", "9Count_2024.csv", thisYear)
if err != nil {
fmt.Println(err)
}
err = processOS("8_appstream.xml", "8_baseos.xml", "8Count_2024.csv", thisYear)
if err != nil {
fmt.Println(err)
}
start := time.Date(1990, 01, 01, 0, 0, 0, 0, time.UTC)
err = processOS("9_appstream.xml", "9_baseos.xml", "9Count_all.csv", start)
if err != nil {
fmt.Println(err)
}
err = processOS("8_appstream.xml", "8_baseos.xml", "8Count_all.csv", start)
if err != nil {
fmt.Println(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment