]> rtime.felk.cvut.cz Git - coffee/buildroot.git/blob - support/scripts/checkpackagelib_mk.py
f66888d21ff5cd291db2d362188d46205eb041c3
[coffee/buildroot.git] / support / scripts / checkpackagelib_mk.py
1 # See support/scripts/check-package.txt before editing this file.
2 # There are already dependency checks during the build, so below check
3 # functions don't need to check for things already checked by exploring the
4 # menu options using "make menuconfig" and by running "make" with appropriate
5 # packages enabled.
6
7 import re
8
9 from checkpackagebase import _CheckFunction
10 # Notice: ignore 'imported but unused' from pyflakes for check functions.
11 from checkpackagelib import ConsecutiveEmptyLines
12 from checkpackagelib import EmptyLastLine
13 from checkpackagelib import NewlineAtEof
14 from checkpackagelib import TrailingSpace
15
16
17 class Indent(_CheckFunction):
18     COMMENT = re.compile("^\s*#")
19     CONDITIONAL = re.compile("^\s*(ifeq|ifneq|endif)\s")
20     ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
21     END_DEFINE = re.compile("^\s*endef\s")
22     MAKEFILE_TARGET = re.compile("^[^# \t]+:\s")
23     START_DEFINE = re.compile("^\s*define\s")
24
25     def before(self):
26         self.define = False
27         self.backslash = False
28         self.makefile_target = False
29
30     def check_line(self, lineno, text):
31         if self.START_DEFINE.search(text):
32             self.define = True
33             return
34         if self.END_DEFINE.search(text):
35             self.define = False
36             return
37
38         expect_tabs = False
39         if self.define or self.backslash or self.makefile_target:
40             expect_tabs = True
41         if self.CONDITIONAL.search(text):
42             expect_tabs = False
43
44         # calculate for next line
45         if self.ENDS_WITH_BACKSLASH.search(text):
46             self.backslash = True
47         else:
48             self.backslash = False
49
50         if self.MAKEFILE_TARGET.search(text):
51             self.makefile_target = True
52             return
53         if text.strip() == "":
54             self.makefile_target = False
55             return
56
57         # comment can be indented or not inside define ... endef, so ignore it
58         if self.define and self.COMMENT.search(text):
59             return
60
61         if expect_tabs:
62             if not text.startswith("\t"):
63                 return ["{}:{}: expected indent with tabs"
64                         .format(self.filename, lineno),
65                         text]
66         else:
67             if text.startswith("\t"):
68                 return ["{}:{}: unexpected indent with tabs"
69                         .format(self.filename, lineno),
70                         text]
71
72
73 class PackageHeader(_CheckFunction):
74     def before(self):
75         self.skip = False
76
77     def check_line(self, lineno, text):
78         if self.skip or lineno > 6:
79             return
80
81         if lineno in [1, 5]:
82             if lineno == 1 and text.startswith("include "):
83                 self.skip = True
84                 return
85             if text.rstrip() != "#" * 80:
86                 return ["{}:{}: should be 80 hashes ({}#writing-rules-mk)"
87                         .format(self.filename, lineno, self.url_to_manual),
88                         text,
89                         "#" * 80]
90         elif lineno in [2, 4]:
91             if text.rstrip() != "#":
92                 return ["{}:{}: should be 1 hash ({}#writing-rules-mk)"
93                         .format(self.filename, lineno, self.url_to_manual),
94                         text]
95         elif lineno == 6:
96             if text.rstrip() != "":
97                 return ["{}:{}: should be a blank line ({}#writing-rules-mk)"
98                         .format(self.filename, lineno, self.url_to_manual),
99                         text]
100
101
102 class SpaceBeforeBackslash(_CheckFunction):
103     TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH = re.compile(r"^.*(  |\t)\\$")
104
105     def check_line(self, lineno, text):
106         if self.TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH.match(text.rstrip()):
107             return ["{}:{}: use only one space before backslash"
108                     .format(self.filename, lineno),
109                     text]
110
111
112 class TrailingBackslash(_CheckFunction):
113     ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
114
115     def before(self):
116         self.backslash = False
117
118     def check_line(self, lineno, text):
119         last_line_ends_in_backslash = self.backslash
120
121         # calculate for next line
122         if self.ENDS_WITH_BACKSLASH.search(text):
123             self.backslash = True
124             self.lastline = text
125             return
126         self.backslash = False
127
128         if last_line_ends_in_backslash and text.strip() == "":
129             return ["{}:{}: remove trailing backslash"
130                     .format(self.filename, lineno - 1),
131                     self.lastline]
132
133
134 class UselessFlag(_CheckFunction):
135     DEFAULT_AUTOTOOLS_FLAG = re.compile("^.*{}".format("|".join([
136         "_AUTORECONF\s*=\s*NO",
137         "_LIBTOOL_PATCH\s*=\s*YES"])))
138     DEFAULT_GENERIC_FLAG = re.compile("^.*{}".format("|".join([
139         "_INSTALL_IMAGES\s*=\s*NO",
140         "_INSTALL_REDISTRIBUTE\s*=\s*YES",
141         "_INSTALL_STAGING\s*=\s*NO",
142         "_INSTALL_TARGET\s*=\s*YES"])))
143     END_CONDITIONAL = re.compile("^\s*(endif)")
144     START_CONDITIONAL = re.compile("^\s*(ifeq|ifneq)")
145
146     def before(self):
147         self.conditional = 0
148
149     def check_line(self, lineno, text):
150         if self.START_CONDITIONAL.search(text):
151             self.conditional += 1
152             return
153         if self.END_CONDITIONAL.search(text):
154             self.conditional -= 1
155             return
156
157         # allow non-default conditionally overridden by default
158         if self.conditional > 0:
159             return
160
161         if self.DEFAULT_GENERIC_FLAG.search(text):
162             return ["{}:{}: useless default value ({}#"
163                     "_infrastructure_for_packages_with_specific_build_systems)"
164                     .format(self.filename, lineno, self.url_to_manual),
165                     text]
166
167         if self.DEFAULT_AUTOTOOLS_FLAG.search(text):
168             return ["{}:{}: useless default value "
169                     "({}#_infrastructure_for_autotools_based_packages)"
170                     .format(self.filename, lineno, self.url_to_manual),
171                     text]