Skip to content

Commit ad2c0bd

Browse files
committed
1 parent 4830e76 commit ad2c0bd

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010

1111
# Output of the go coverage tool, specifically when used with LiteIDE
1212
*.out
13+
14+
# Generated binary
15+
bscdiff

bscdiff.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// bscdiff compares bsc, issue and CVE numbers from a source changelog, to a
2+
// target changelog. Missing numbers are then printed with their occurrence
3+
// in the source changelog.
4+
//
5+
// Usage: bscdiff <source_file> <target_file>
6+
7+
package main
8+
9+
import (
10+
"bufio"
11+
"fmt"
12+
"os"
13+
"regexp"
14+
"sort"
15+
)
16+
17+
type searchResult struct {
18+
line int
19+
match []string
20+
text string
21+
}
22+
23+
var regexStrings []string
24+
25+
func main() {
26+
// These are the regex-strings that will be used later on.
27+
regexStrings = []string{
28+
`bsc#\d*`,
29+
`U#\d*`,
30+
`(CVE-(1999|2\d{3})-(0\d{2}[1-9]|[1-9]\d{3,}))`}
31+
32+
args := os.Args
33+
34+
if len(args) > 1 && (args[1] == "-h" || args[1] == "--help") {
35+
fmt.Println("bscdiff compares bsc, issue and CVE numbers from a source changelog, ")
36+
fmt.Println("to a target changelog. Missing numbers are then printed with their ")
37+
fmt.Println("occurrence in the source changelog")
38+
fmt.Println()
39+
fmt.Println(fmt.Sprintf("usage: %s <source_file> <target_file>\n", args[0]))
40+
os.Exit(0)
41+
}
42+
43+
if len(args) < 3 {
44+
fmt.Fprintf(os.Stderr, "usage: %s <source_file> <target_file>", args[0])
45+
os.Exit(1)
46+
}
47+
48+
// Check if files are actually there… and files.
49+
for _, file := range os.Args[1:3] {
50+
if !fileExists(file) {
51+
fmt.Fprintf(os.Stderr, "%s does not exist!", file)
52+
os.Exit(1)
53+
}
54+
}
55+
56+
searchResults1 := scanFile(args[1])
57+
searchResults2 := scanFile(args[2])
58+
missingBscs := findMissingBsc(searchResults1, searchResults2)
59+
prettyPrintMissingBscs(searchResults1, missingBscs)
60+
}
61+
62+
// Outputs the missing BSC numbers in a useful format.
63+
func prettyPrintMissingBscs(searchResults1 []searchResult, missingBscs []string) {
64+
sort.Strings(missingBscs)
65+
for _, bsc := range missingBscs {
66+
for _, searchResult := range searchResults1 {
67+
searchPos := sort.SearchStrings(searchResult.match, bsc)
68+
if searchPos < len(searchResult.match) && searchResult.match[searchPos] == bsc {
69+
fmt.Println(fmt.Sprintf("%d: %s -> %s",
70+
searchResult.line,
71+
bsc,
72+
searchResult.text))
73+
}
74+
}
75+
}
76+
}
77+
78+
// Returns a list of BSC numbers, that are missing from the second changelog file.
79+
func findMissingBsc(changelog1 []searchResult, changelog2 []searchResult) []string {
80+
bscList1 := getBscs(changelog1)
81+
bscList2 := getBscs(changelog2)
82+
sort.Strings(bscList1)
83+
sort.Strings(bscList2)
84+
85+
var missingBscs []string
86+
for _, bsc := range bscList1 {
87+
searchPos := sort.SearchStrings(bscList2, bsc)
88+
if searchPos < len(bscList2) && bscList2[searchPos] == bsc {
89+
// found it
90+
} else {
91+
missingBscs = append(missingBscs, bsc)
92+
}
93+
}
94+
return removeDuplicates(missingBscs)
95+
}
96+
97+
// Extracts the BSC numbers from the search results and returns them as an array.
98+
func getBscs(res []searchResult) []string {
99+
var bsc []string
100+
for _, v := range res {
101+
for _, value := range v.match {
102+
bsc = append(bsc, value)
103+
}
104+
}
105+
return bsc
106+
}
107+
108+
// Scans the file for bsc, CVE and issue numbers and returns the search results.
109+
func scanFile(pathToFile string) []searchResult {
110+
var regexes []*regexp.Regexp
111+
// creating the regexes with the regex-strings from main().
112+
for _, regexString := range regexStrings {
113+
var re, _ = regexp.Compile(regexString)
114+
regexes = append(regexes, re)
115+
}
116+
lines, err := scanLines(pathToFile)
117+
if err != nil {
118+
panic(err)
119+
}
120+
var searchResults []searchResult
121+
for i, line := range lines {
122+
for _, re := range regexes {
123+
results := re.FindAllString(line, -1)
124+
if len(results) > 0 {
125+
res := searchResult{
126+
line: i + 1,
127+
match: results,
128+
text: line}
129+
searchResults = append(searchResults, res)
130+
}
131+
}
132+
}
133+
return searchResults
134+
}
135+
136+
// Returns the given file as an array of lines.
137+
func scanLines(path string) ([]string, error) {
138+
file, err := os.Open(path)
139+
if err != nil {
140+
return nil, err
141+
}
142+
defer file.Close()
143+
scanner := bufio.NewScanner(file)
144+
scanner.Split(bufio.ScanLines)
145+
var lines []string
146+
for scanner.Scan() {
147+
lines = append(lines, scanner.Text())
148+
}
149+
return lines, nil
150+
}
151+
152+
// Removes duplicates form an array.
153+
func removeDuplicates(s []string) []string {
154+
m := make(map[string]bool)
155+
for _, item := range s {
156+
if _, ok := m[item]; ok {
157+
// duplicate item
158+
} else {
159+
m[item] = true
160+
}
161+
}
162+
var result []string
163+
for item := range m {
164+
result = append(result, item)
165+
}
166+
return result
167+
}
168+
169+
// fileExists checks if a file exists and is not a directory before we
170+
// try using it to prevent further errors.
171+
func fileExists(filename string) bool {
172+
info, err := os.Stat(filename)
173+
if os.IsNotExist(err) {
174+
return false
175+
}
176+
return !info.IsDir()
177+
}

0 commit comments

Comments
 (0)