1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
import logging
import operator
import os
import re
from repoman.modules.linechecks.base import InheritEclass
from repoman.modules.linechecks.config import LineChecksConfig
from repoman._portage import portage
# Avoid a circular import issue in py2.7
portage.proxy.lazyimport.lazyimport(globals(),
'portage.module:Modules',
)
MODULES_PATH = os.path.dirname(__file__)
# initial development debug info
logging.debug("LineChecks module path: %s", MODULES_PATH)
class LineCheckController(object):
'''Initializes and runs the LineCheck checks'''
def __init__(self, repo_settings, linechecks):
'''Class init
@param repo_settings: RepoSettings instance
'''
self.repo_settings = repo_settings
self.linechecks = linechecks
self.config = LineChecksConfig(repo_settings)
self.controller = Modules(path=MODULES_PATH, namepath="repoman.modules.linechecks")
logging.debug("LineCheckController; module_names: %s", self.controller.module_names)
self._constant_checks = None
self._here_doc_re = re.compile(r'.*<<[-]?(\w+)\s*(>\s*\S+\s*)?$')
self._ignore_comment_re = re.compile(r'^\s*#')
self._continuation_re = re.compile(r'(\\)*$')
def checks_init(self, experimental_inherit=False):
'''Initialize the main variables
@param experimental_inherit boolean
'''
if not experimental_inherit:
# Emulate the old eprefixify.defined and inherit.autotools checks.
self._eclass_info = self.config.eclass_info
else:
self._eclass_info = self.config.eclass_info_experimental_inherit
self._constant_checks = []
logging.debug("LineCheckController; modules: %s", self.linechecks)
# Add in the pluggable modules
for mod in self.linechecks:
mod_class = self.controller.get_class(mod)
logging.debug("LineCheckController; module_name: %s, class: %s", mod, mod_class.__name__)
self._constant_checks.append(mod_class(self.config.errors))
# Add in the InheritEclass checks
logging.debug("LineCheckController; eclass_info.items(): %s", list(self.config.eclass_info))
for k, kwargs in self.config.eclass_info.items():
logging.debug("LineCheckController; k: %s, kwargs: %s", k, kwargs)
self._constant_checks.append(
InheritEclass(
k,
self.config.eclass_eapi_functions,
self.config.errors,
**kwargs
)
)
def run_checks(self, contents, pkg):
'''Run the configured linechecks
@param contents: the ebjuild contents to check
@param pkg: the package being checked
'''
if self._constant_checks is None:
self.checks_init()
checks = self._constant_checks
here_doc_delim = None
multiline = None
for lc in checks:
lc.new(pkg)
multinum = 0
for num, line in enumerate(contents):
# Check if we're inside a here-document.
if here_doc_delim is not None:
if here_doc_delim.match(line):
here_doc_delim = None
if here_doc_delim is None:
here_doc = self._here_doc_re.match(line)
if here_doc is not None:
here_doc_delim = re.compile(r'^\s*%s$' % here_doc.group(1))
if here_doc_delim is not None:
continue
# Unroll multiline escaped strings so that we can check things:
# inherit foo bar \
# moo \
# cow
# This will merge these lines like so:
# inherit foo bar moo cow
# A line ending with an even number of backslashes does not count,
# because the last backslash is escaped. Therefore, search for an
# odd number of backslashes.
line_escaped = operator.sub(*self._continuation_re.search(line).span()) % 2 == 1
if multiline:
# Chop off the \ and \n bytes from the previous line.
multiline = multiline[:-2] + line
if not line_escaped:
line = multiline
num = multinum
multiline = None
else:
continue
else:
if line_escaped:
multinum = num
multiline = line
continue
if not line.endswith("#nowarn\n"):
# Finally we have a full line to parse.
is_comment = self._ignore_comment_re.match(line) is not None
for lc in checks:
if is_comment and lc.ignore_comment:
continue
if lc.check_eapi(pkg.eapi):
ignore = lc.ignore_line
if not ignore or not ignore.match(line):
e = lc.check(num, line)
if e:
yield lc.repoman_check_name, e % (num + 1)
for lc in checks:
i = lc.end()
if i is not None:
for e in i:
yield lc.repoman_check_name, e
|