summaryrefslogtreecommitdiff
path: root/util/scripts/maintainers.go
diff options
context:
space:
mode:
Diffstat (limited to 'util/scripts/maintainers.go')
-rw-r--r--util/scripts/maintainers.go177
1 files changed, 108 insertions, 69 deletions
diff --git a/util/scripts/maintainers.go b/util/scripts/maintainers.go
index 0474b77f90..623562bd64 100644
--- a/util/scripts/maintainers.go
+++ b/util/scripts/maintainers.go
@@ -19,13 +19,14 @@ import (
"log"
"os"
"os/exec"
- "path/filepath"
+ "regexp"
)
type subsystem struct {
name string
maintainer []string
- file []string
+ paths []string
+ globs []*regexp.Regexp
}
var subsystems []subsystem
@@ -84,6 +85,19 @@ func get_maintainers() ([]string, error) {
return maintainers, nil
}
+func path_to_regexstr(path string) string {
+ // if prefix, allow all subdirectories
+ if path[len(path)-1] == '/' {
+ path += "*"
+ }
+ return glob_to_regex(path)
+}
+
+func path_to_regex(path string) *regexp.Regexp {
+ regexstr := path_to_regexstr(path)
+ return regexp.MustCompile(regexstr)
+}
+
func build_maintainers(maintainers []string) {
var current *subsystem
for _, line := range maintainers {
@@ -100,7 +114,9 @@ func build_maintainers(maintainers []string) {
current.maintainer = append(current.maintainer, line[3:len(line)])
case 'F':
// add files
- current.file = append(current.file, line[3:len(line)])
+ current.paths = append(current.paths, line[3:len(line)])
+ current.globs = append(current.globs, path_to_regex(line[3:len(line)]))
+ break
case 'L', 'S', 'T', 'W': // ignore
default:
fmt.Println("No such specifier: ", line)
@@ -113,78 +129,24 @@ func print_maintainers() {
for _, subsystem := range subsystems {
fmt.Println(subsystem.name)
fmt.Println(" ", subsystem.maintainer)
- fmt.Println(" ", subsystem.file)
+ fmt.Println(" ", subsystem.paths)
}
}
-func match_file(fname string, files []string) (bool, error) {
- var matched bool
- var err error
-
- for _, file := range files {
- /* Direct match */
- matched, err = filepath.Match(file, fname)
- if err != nil {
- return false, err
- }
- if matched {
- return true, nil
- }
-
- /* There are three cases that match_file can handle:
- *
- * dirname/filename
- * dirname/*
- * dirname/
- *
- * The first case is an exact match, the second case is a
- * direct match of everything in that directory, and the third
- * is a direct match of everything in that directory and its
- * subdirectories.
- *
- * The first two cases are handled above, the code below is
- * only for that latter case, so if file doesn't end in /,
- * skip to the next file.
- */
- if file[len(file)-1] != '/' {
- continue
- }
-
- /* Remove / because we add it again below */
- file = file[:len(file)-1]
-
- /* Maximum tree depth, as calculated by
- * $(( `git ls-files | tr -d "[a-z][A-Z][0-9]\-\_\." | \
- * sort -u | tail -1 | wc -c` - 1 ))
- * 11
- */
- max_depth := 11
-
- for i := 0; i < max_depth; i++ {
- /* Subdirectory match */
- file += "/*"
-
- if matched, err = filepath.Match(file, fname); err != nil {
- return false, err
- }
- if matched {
- return true, nil
- }
-
+func match_file(fname string, component subsystem) bool {
+ for _, glob := range component.globs {
+ if glob.Match([]byte(fname)) {
+ return true
}
}
- return false, nil
+ return false
}
func find_maintainer(fname string) {
var success bool
for _, subsystem := range subsystems {
- matched, err := match_file(fname, subsystem.file)
- if err != nil {
- log.Fatalf("match_file failed: %v", err)
- return
- }
+ matched := match_file(fname, subsystem)
if matched && subsystem.name != "THE REST" {
success = true
fmt.Println(fname, "is in subsystem",
@@ -201,11 +163,7 @@ func find_unmaintained(fname string) {
var success bool
for _, subsystem := range subsystems {
- matched, err := match_file(fname, subsystem.file)
- if err != nil {
- log.Fatalf("match_file failed: %v", err)
- return
- }
+ matched := match_file(fname, subsystem)
if matched && subsystem.name != "THE REST" {
success = true
fmt.Println(fname, "is in subsystem",
@@ -217,6 +175,87 @@ func find_unmaintained(fname string) {
}
}
+// taken from https://github.com/zyedidia/glob/blob/master/glob.go which is
+// Copyright (c) 2016: Zachary Yedidia.
+// and was published under the MIT "Expat" license.
+//
+// only change: return the string, instead of a compiled golang regex
+func glob_to_regex(glob string) string {
+ regex := ""
+ inGroup := 0
+ inClass := 0
+ firstIndexInClass := -1
+ arr := []byte(glob)
+
+ for i := 0; i < len(arr); i++ {
+ ch := arr[i]
+
+ switch ch {
+ case '\\':
+ i++
+ if i >= len(arr) {
+ regex += "\\"
+ } else {
+ next := arr[i]
+ switch next {
+ case ',':
+ // Nothing
+ case 'Q', 'E':
+ regex += "\\\\"
+ default:
+ regex += "\\"
+ }
+ regex += string(next)
+ }
+ case '*':
+ if inClass == 0 {
+ regex += ".*"
+ } else {
+ regex += "*"
+ }
+ case '?':
+ if inClass == 0 {
+ regex += "."
+ } else {
+ regex += "?"
+ }
+ case '[':
+ inClass++
+ firstIndexInClass = i + 1
+ regex += "["
+ case ']':
+ inClass--
+ regex += "]"
+ case '.', '(', ')', '+', '|', '^', '$', '@', '%':
+ if inClass == 0 || (firstIndexInClass == i && ch == '^') {
+ regex += "\\"
+ }
+ regex += string(ch)
+ case '!':
+ if firstIndexInClass == i {
+ regex += "^"
+ } else {
+ regex += "!"
+ }
+ case '{':
+ inGroup++
+ regex += "("
+ case '}':
+ inGroup--
+ regex += ")"
+ case ',':
+ if inGroup > 0 {
+ regex += "|"
+ } else {
+ regex += ","
+ }
+ default:
+ regex += string(ch)
+ }
+ }
+ return "^" + regex + "$"
+}
+
func main() {
var files []string
var maint bool