]> rtime.felk.cvut.cz Git - coffee/buildroot.git/blob - support/scripts/checkpackagelib_mk.py
package/eudev: bump version to 3.2.2
[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 TypoInPackageVariable(_CheckFunction):
135     ALLOWED = re.compile("|".join([
136         "ACLOCAL_DIR",
137         "ACLOCAL_HOST_DIR",
138         "BR_CCACHE_INITIAL_SETUP",
139         "BR_NO_CHECK_HASH_FOR",
140         "LINUX_POST_PATCH_HOOKS",
141         "LINUX_TOOLS",
142         "LUA_RUN",
143         "MKFS_JFFS2",
144         "MKIMAGE_ARCH",
145         "PKG_CONFIG_HOST_BINARY",
146         "TARGET_FINALIZE_HOOKS",
147         "XTENSA_CORE_NAME"]))
148     PACKAGE_NAME = re.compile("/([^/]+)\.mk")
149     VARIABLE = re.compile("^([A-Z0-9_]+_[A-Z0-9_]+)\s*(\+|)=")
150
151     def before(self):
152         package = self.PACKAGE_NAME.search(self.filename).group(1)
153         package = package.replace("-", "_").upper()
154         # linux tools do not use LINUX_TOOL_ prefix for variables
155         package = package.replace("LINUX_TOOL_", "")
156         self.package = package
157         self.REGEX = re.compile("^(HOST_)?({}_[A-Z0-9_]+)".format(package))
158         self.FIND_VIRTUAL = re.compile(
159             "^{}_PROVIDES\s*(\+|)=\s*(.*)".format(package))
160         self.virtual = []
161
162     def check_line(self, lineno, text):
163         m = self.VARIABLE.search(text)
164         if m is None:
165             return
166
167         variable = m.group(1)
168
169         # allow to set variables for virtual package this package provides
170         v = self.FIND_VIRTUAL.search(text)
171         if v:
172             self.virtual += v.group(2).upper().split()
173             return
174         for virtual in self.virtual:
175             if variable.startswith("{}_".format(virtual)):
176                 return
177
178         if self.ALLOWED.match(variable):
179             return
180         if self.REGEX.search(text) is None:
181             return ["{}:{}: possible typo: {} -> *{}*"
182                     .format(self.filename, lineno, variable, self.package),
183                     text]
184
185
186 class UselessFlag(_CheckFunction):
187     DEFAULT_AUTOTOOLS_FLAG = re.compile("^.*{}".format("|".join([
188         "_AUTORECONF\s*=\s*NO",
189         "_LIBTOOL_PATCH\s*=\s*YES"])))
190     DEFAULT_GENERIC_FLAG = re.compile("^.*{}".format("|".join([
191         "_INSTALL_IMAGES\s*=\s*NO",
192         "_INSTALL_REDISTRIBUTE\s*=\s*YES",
193         "_INSTALL_STAGING\s*=\s*NO",
194         "_INSTALL_TARGET\s*=\s*YES"])))
195     END_CONDITIONAL = re.compile("^\s*(endif)")
196     START_CONDITIONAL = re.compile("^\s*(ifeq|ifneq)")
197
198     def before(self):
199         self.conditional = 0
200
201     def check_line(self, lineno, text):
202         if self.START_CONDITIONAL.search(text):
203             self.conditional += 1
204             return
205         if self.END_CONDITIONAL.search(text):
206             self.conditional -= 1
207             return
208
209         # allow non-default conditionally overridden by default
210         if self.conditional > 0:
211             return
212
213         if self.DEFAULT_GENERIC_FLAG.search(text):
214             return ["{}:{}: useless default value ({}#"
215                     "_infrastructure_for_packages_with_specific_build_systems)"
216                     .format(self.filename, lineno, self.url_to_manual),
217                     text]
218
219         if self.DEFAULT_AUTOTOOLS_FLAG.search(text):
220             return ["{}:{}: useless default value "
221                     "({}#_infrastructure_for_autotools_based_packages)"
222                     .format(self.filename, lineno, self.url_to_manual),
223                     text]