-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextract.go
133 lines (129 loc) · 3.21 KB
/
extract.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package testingfiles
import (
"errors"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"slices"
"strings"
)
// ExtractCommon creates a file commonf containing all lines found in all files selected by globf filter.
// It returns an error if the intersection is empty.
func ExtractCommon(contextFilesPath, globf, commonf string) error {
fl, err := filepath.Glob(filepath.Join(contextFilesPath, globf))
if err != nil {
return err
}
if len(fl) == 0 {
return fs.ErrNotExist
}
intersec, err := requiredFeatures(fl[0])
if err != nil {
return err
}
fl = fl[1:]
i := 0
for _, f := range fl {
flines, err1 := requiredFeatures(f)
if err1 != nil {
return err1
}
for {
if intersec[i] == flines[0] {
i++
flines = flines[1:]
} else if intersec[i] < flines[0] {
// feature is unknown in checked file and must be removed from intersection
intersec = slices.Delete(intersec, i, i+1)
} else {
// skip feature unknown to intersection
flines = flines[1:]
}
if i == len(intersec) {
break
} else if len(flines) == 0 {
intersec = intersec[:i]
break
}
}
if len(intersec) == 0 {
log.Printf("intersection is empty as %s has nothing in common with other files", filepath.Base(f))
return os.ErrNotExist
}
i = 0
}
if err = os.WriteFile(filepath.Join(contextFilesPath, commonf),
[]byte(strings.Join(intersec, "\n")), os.ModePerm); err != nil {
return err
}
log.Printf("intersection has %v line(s) written to %s", len(intersec), commonf)
return nil
}
// CreateSupplements removes all lines of a baselinef file from all files in globf
func CreateSupplements(contextFilesPath, globf, baselinef string) error {
fl, err := filepath.Glob(filepath.Join(contextFilesPath, globf))
if err != nil {
return err
}
if len(fl) == 0 {
return fs.ErrNotExist
}
baseline, err := requiredFeatures(filepath.Join(contextFilesPath, baselinef))
if err != nil {
return err
}
base := baseline
for _, f := range fl {
flines, err1 := requiredFeatures(f)
if err1 != nil {
return err1
}
var supplement []string
for {
if base[0] == flines[0] {
base = base[1:]
flines = flines[1:]
} else if base[0] > flines[0] {
supplement = append(supplement, flines[0])
flines = flines[1:]
if len(flines) == 0 {
return errors.New(fmt.Sprintf("common feature is missing: %s", base[0]))
}
} else {
return errors.New(fmt.Sprintf("common feature is missing: %s", base[0]))
}
if len(base) == 0 {
break
}
}
err = os.WriteFile(f, []byte(strings.Join(supplement, "\n")), os.ModePerm)
if err != nil {
return err
}
log.Printf("%s has %v line(s)", f, len(supplement))
base = baseline
}
return nil
}
func requiredFeatures(filename string) ([]string, error) {
bs, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
bss := string(bs)
// TODO CRLF line ending is not handled
lines := strings.Split(bss, "\n")
// A last empty line is removed as it is usually an artifact
if strings.TrimSpace(lines[len(lines)-1]) == "" {
lines = lines[:len(lines)-1]
}
if len(lines) == 0 {
log.Printf("%s is empty", filename)
return nil, fs.ErrNotExist
}
slices.Sort(lines)
log.Printf("%s has %v lines", filename, len(lines))
return lines, nil
}