internal/deps/gomod.go

7effe3feb4612cffb5ed38c02300299559aa8971
gitbay/internal/deps/gomod.go history · blame · raw

60 lines · 1536 bytes

 1package deps
 2
 3import "strings"
 4
 5// parseGoMod reads the direct requirements from go.mod. Indirect
 6// requirements are the module graph's business rather than the maintainer's,
 7// and a replaced module does not come from the proxy at all, so both are
 8// skipped.
 9func parseGoMod(read ReadFile) []Dep {
10	raw, err := read("go.mod")
11	if err != nil {
12		return nil
13	}
14	replaced := map[string]bool{}
15	var reqs [][2]string
16	block := "" // the directive whose ( ... ) block we are inside
17	for _, line := range strings.Split(string(raw), "\n") {
18		line = strings.TrimSpace(line)
19		indirect := false
20		if i := strings.Index(line, "//"); i >= 0 {
21			indirect = strings.Contains(line[i:], "indirect")
22			line = strings.TrimSpace(line[:i])
23		}
24		if line == "" {
25			continue
26		}
27		directive := block
28		if block == "" {
29			d, rest, ok := strings.Cut(line, " ")
30			if !ok || (d != "require" && d != "replace") {
31				continue
32			}
33			if rest = strings.TrimSpace(rest); rest == "(" {
34				block = d
35				continue
36			}
37			directive, line = d, rest
38		} else if line == ")" {
39			block = ""
40			continue
41		}
42		fields := strings.Fields(line)
43		switch {
44		case directive == "require" && !indirect && len(fields) >= 2:
45			reqs = append(reqs, [2]string{fields[0], fields[1]})
46		case directive == "replace" && len(fields) >= 1:
47			replaced[fields[0]] = true
48		}
49	}
50	var out []Dep
51	for _, r := range reqs {
52		if replaced[r[0]] {
53			continue
54		}
55		if v := pin(r[1]); v != "" {
56			out = append(out, Dep{Ecosystem: EcoGo, Name: r[0], Current: r[1]})
57		}
58	}
59	return out
60}