Annotation of pkgsrc/pkgtools/pkglint/files/category.go, Revision 1.4
1.1 rillig 1: package main
2:
3: import (
4: "sort"
5: )
6:
1.4 ! rillig 7: func CheckdirCategory() {
! 8: if G.opts.DebugTrace {
! 9: defer tracecall1(G.CurrentDir)()
! 10: }
1.1 rillig 11:
1.4 ! rillig 12: lines := LoadNonemptyLines(G.CurrentDir+"/Makefile", true)
1.1 rillig 13: if lines == nil {
14: return
15: }
1.4 ! rillig 16:
! 17: mklines := NewMkLines(lines)
! 18: mklines.Check()
1.1 rillig 19:
20: exp := NewExpecter(lines)
1.4 ! rillig 21: for exp.AdvanceIfPrefix("#") {
1.1 rillig 22: }
1.4 ! rillig 23: exp.ExpectEmptyLine()
1.1 rillig 24:
1.4 ! rillig 25: if exp.AdvanceIfMatches(`^COMMENT=\t*(.*)`) {
! 26: mklines.mklines[exp.index-1].CheckValidCharactersInValue(`[- '(),/0-9A-Za-z]`)
! 27: } else {
! 28: exp.CurrentLine().Error0("COMMENT= line expected.")
1.1 rillig 29: }
1.4 ! rillig 30: exp.ExpectEmptyLine()
1.1 rillig 31:
1.4 ! rillig 32: type subdir struct {
! 33: name string
! 34: line *Line
! 35: active bool
1.1 rillig 36: }
37:
38: // And now to the most complicated part of the category Makefiles,
39: // the (hopefully) sorted list of SUBDIRs. The first step is to
40: // collect the SUBDIRs in the Makefile and in the file system.
41:
1.4 ! rillig 42: fSubdirs := getSubdirs(G.CurrentDir)
1.1 rillig 43: sort.Sort(sort.StringSlice(fSubdirs))
1.2 rillig 44: var mSubdirs []subdir
1.1 rillig 45:
46: prevSubdir := ""
1.4 ! rillig 47: for !exp.EOF() {
! 48: line := exp.CurrentLine()
! 49: text := line.Text
1.1 rillig 50:
1.2 rillig 51: if m, commentFlag, indentation, name, comment := match4(text, `^(#?)SUBDIR\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
1.1 rillig 52: commentedOut := commentFlag == "#"
53: if commentedOut && comment == "" {
1.4 ! rillig 54: line.Warn1("%q commented out without giving a reason.", name)
1.1 rillig 55: }
56:
57: if indentation != "\t" {
1.4 ! rillig 58: line.Warn0("Indentation should be a single tab character.")
1.1 rillig 59: }
60:
1.2 rillig 61: if name == prevSubdir {
1.4 ! rillig 62: line.Error1("%q must only appear once.", name)
1.2 rillig 63: } else if name < prevSubdir {
1.4 ! rillig 64: line.Warn2("%q should come before %q.", name, prevSubdir)
1.1 rillig 65: } else {
66: // correctly ordered
67: }
68:
1.2 rillig 69: mSubdirs = append(mSubdirs, subdir{name, line, !commentedOut})
70: prevSubdir = name
1.4 ! rillig 71: exp.Advance()
1.1 rillig 72:
73: } else {
1.4 ! rillig 74: if line.Text != "" {
! 75: line.Error0("SUBDIR+= line or empty line expected.")
1.1 rillig 76: }
77: break
78: }
79: }
80:
81: // To prevent unnecessary warnings about subdirectories that are
82: // in one list, but not in the other, we generate the sets of
83: // subdirs of each list.
84: fCheck := make(map[string]bool)
85: mCheck := make(map[string]bool)
86: for _, fsub := range fSubdirs {
87: fCheck[fsub] = true
88: }
89: for _, msub := range mSubdirs {
1.2 rillig 90: mCheck[msub.name] = true
1.1 rillig 91: }
92:
1.2 rillig 93: fIndex, fAtend, fNeednext, fCurrent := 0, false, true, ""
94: mIndex, mAtend, mNeednext, mCurrent := 0, false, true, ""
1.1 rillig 95:
96: var subdirs []string
97:
98: var line *Line
1.2 rillig 99: mActive := false
1.1 rillig 100:
1.2 rillig 101: for !(mAtend && fAtend) {
102: if !mAtend && mNeednext {
103: mNeednext = false
104: if mIndex >= len(mSubdirs) {
105: mAtend = true
1.4 ! rillig 106: line = exp.CurrentLine()
1.1 rillig 107: continue
108: } else {
1.2 rillig 109: mCurrent = mSubdirs[mIndex].name
110: line = mSubdirs[mIndex].line
111: mActive = mSubdirs[mIndex].active
112: mIndex++
1.1 rillig 113: }
114: }
115:
1.2 rillig 116: if !fAtend && fNeednext {
117: fNeednext = false
118: if fIndex >= len(fSubdirs) {
119: fAtend = true
1.1 rillig 120: continue
121: } else {
1.2 rillig 122: fCurrent = fSubdirs[fIndex]
123: fIndex++
1.1 rillig 124: }
125: }
126:
1.2 rillig 127: if !fAtend && (mAtend || fCurrent < mCurrent) {
128: if !mCheck[fCurrent] {
1.4 ! rillig 129: if !line.AutofixInsertBefore("SUBDIR+=\t" + fCurrent) {
! 130: line.Error1("%q exists in the file system, but not in the Makefile.", fCurrent)
! 131: }
1.2 rillig 132: }
133: fNeednext = true
134:
135: } else if !mAtend && (fAtend || mCurrent < fCurrent) {
136: if !fCheck[mCurrent] {
1.4 ! rillig 137: if !line.AutofixDelete() {
! 138: line.Error1("%q exists in the Makefile, but not in the file system.", mCurrent)
! 139: }
1.1 rillig 140: }
1.2 rillig 141: mNeednext = true
1.1 rillig 142:
143: } else { // f_current == m_current
1.2 rillig 144: fNeednext = true
145: mNeednext = true
146: if mActive {
1.4 ! rillig 147: subdirs = append(subdirs, G.CurrentDir+"/"+mCurrent)
1.1 rillig 148: }
149: }
150: }
151:
152: // the pkgsrc-wip category Makefile defines its own targets for
153: // generating indexes and READMEs. Just skip them.
1.4 ! rillig 154: if G.Wip {
1.1 rillig 155: exp.index = len(exp.lines) - 2
156: }
157:
1.4 ! rillig 158: exp.ExpectEmptyLine()
! 159: exp.ExpectText(".include \"../mk/misc/category.mk\"")
! 160: if !exp.EOF() {
! 161: exp.CurrentLine().Error0("The file should end here.")
1.1 rillig 162: }
163:
1.4 ! rillig 164: SaveAutofixChanges(lines)
1.1 rillig 165:
166: if G.opts.Recursive {
1.4 ! rillig 167: G.Todo = append(append([]string(nil), subdirs...), G.Todo...)
1.1 rillig 168: }
169: }
CVSweb <webmaster@jp.NetBSD.org>