History

docs: sphinx/kernel_abi: reduce buffer usage for ABI messages

Instead of producing a big message with all ABI contents and then parse as a whole, simplify the code by handling each ABI symbol in separate. As an additional benefit, there's no need to place file/line nubers inlined at the data and use a regex to convert them.

Mauro Carvalho Chehab committed 1 year ago

Commit aea5e521 parent ee34f833 files · +51 −48Browse files

Unified · Split

3 files
  1. Documentation/sphinx/kernel_abi.py +42 −40
  2. scripts/get_abi.py +5 −2
  3. scripts/lib/abi/abi_parser.py +4 −6
Documentation/sphinx/kernel_abi.py+42−40
@@ -68,6 +68,7 @@ class KernelCmd(Directive): · 67 unmodified lines
68 has_content = False68 has_content = False
69 final_argument_whitespace = True69 final_argument_whitespace = True
70 logger = logging.getLogger('kernel_abi')70 logger = logging.getLogger('kernel_abi')
71 parser = None
71 72
72 option_spec = {73 option_spec = {
73 "debug": directives.flag,74 "debug": directives.flag,
@@ -79,59 +80,60 @@ class KernelCmd(Directive): · 5 unmodified lines
79 raise self.warning("docutils: file insertion disabled")80 raise self.warning("docutils: file insertion disabled")
80 81
81 path = os.path.join(srctree, "Documentation", self.arguments[0])82 path = os.path.join(srctree, "Documentation", self.arguments[0])
82 parser = AbiParser(path, logger=self.logger)83 self.parser = AbiParser(path, logger=self.logger)
83 parser.parse_abi()84 self.parser.parse_abi()
84 parser.check_issues()85 self.parser.check_issues()
85 86
86 msg = ""87 node = self.nested_parse(None, self.arguments[0])
87 for m in parser.doc(enable_lineno=True, show_file=True):
88 msg += m
89
90 node = self.nested_parse(msg, self.arguments[0])
91 return node88 return node
92 89
93 def nested_parse(self, lines, fname):90 def nested_parse(self, data, fname):
94 env = self.state.document.settings.env91 env = self.state.document.settings.env
95 content = ViewList()92 content = ViewList()
96 node = nodes.section()93 node = nodes.section()
97 94
98 if "debug" in self.options:95 if data is not None:
99 code_block = "\n\n.. code-block:: rst\n :linenos:\n"96 # Handles the .rst file
100 for line in lines.split("\n"):97 for line in data.split("\n"):
101 code_block += "\n " + line98 content.append(line, fname, 0)
102 lines = code_block + "\n\n"99
103 100 self.do_parse(content, node)
104 line_regex = re.compile(r"^\.\. LINENO (\S+)\#([0-9]+)$")
105 ln = 0
106 n = 0
107 f = fname
108
109 for line in lines.split("\n"):
110 n = n + 1
111 match = line_regex.search(line)
112 if match:
113 new_f = match.group(1)
114
115 # Sphinx parser is lazy: it stops parsing contents in the
116 # middle, if it is too big. So, handle it per input file
117 if new_f != f and content:
118 self.do_parse(content, node)
119 content = ViewList()
120 101
102 else:
103 # Handles the ABI parser content, symbol by symbol
104
105 old_f = fname
106 n = 0
107 for msg, f, ln in self.parser.doc():
108 msg_list = msg.split("\n")
109 if "debug" in self.options:
110 lines = [
111 "", "", ".. code-block:: rst",
112 " :linenos:", ""
113 ]
114 for m in msg_list:
115 lines.append(" " + m)
116 else:
117 lines = msg_list
118
119 for line in lines:
120 # sphinx counts lines from 0
121 content.append(line, f, ln - 1)
122 n += 1
123
124 if f != old_f:
121 # Add the file to Sphinx build dependencies125 # Add the file to Sphinx build dependencies
122 env.note_dependency(os.path.abspath(f))126 env.note_dependency(os.path.abspath(f))
123 127
124 f = new_f128 old_f = f
125 129
126 # sphinx counts lines from 0130 # Sphinx doesn't like to parse big messages. So, let's
127 ln = int(match.group(2)) - 1131 # add content symbol by symbol
128 else:132 if content:
129 content.append(line, f, ln)133 self.do_parse(content, node)
130 134 content = ViewList()
131 self.logger.info("%s: parsed %i lines" % (fname, n))
132 135
133 if content:136 self.logger.info("%s: parsed %i lines" % (fname, n))
134 self.do_parse(content, node)
135 137
136 return node.children138 return node.children
137 139
scripts/get_abi.py+5−2
@@ -63,8 +63,11 @@ class AbiRest: · 62 unmodified lines
63 parser.parse_abi()63 parser.parse_abi()
64 parser.check_issues()64 parser.check_issues()
65 65
66 for msg in parser.doc(args.enable_lineno, args.raw, not args.no_file):66 for t in parser.doc(args.raw, not args.no_file):
67 print(msg)67 if args.enable_lineno:
68 print (f".. LINENO {t[1]}#{t[2]}\n\n")
69
70 print(t[0])
68 71
69class AbiValidate:72class AbiValidate:
70 """Initialize an argparse subparser for ABI validation"""73 """Initialize an argparse subparser for ABI validation"""
scripts/lib/abi/abi_parser.py+4−6
@@ -427,7 +427,7 @@ class AbiParser: · 426 unmodified lines
427 427
428 return new_desc + "\n\n"428 return new_desc + "\n\n"
429 429
430 def doc(self, enable_lineno, output_in_txt=False, show_file=False):430 def doc(self, output_in_txt=False, show_file=True):
431 """Print ABI at stdout"""431 """Print ABI at stdout"""
432 432
433 part = None433 part = None
@@ -444,10 +444,6 @@ class AbiParser: · 10 unmodified lines
444 444
445 msg = ""445 msg = ""
446 446
447 if enable_lineno:
448 ln = v.get("line_no", 1)
449 msg += f".. LINENO {file_ref[0][0]}#{ln}\n\n"
450
451 if wtype != "File":447 if wtype != "File":
452 cur_part = names[0]448 cur_part = names[0]
453 if cur_part.find("/") >= 0:449 if cur_part.find("/") >= 0:
@@ -508,7 +504,9 @@ class AbiParser: · 54 unmodified lines
508 if users and users.strip(" \t\n"):504 if users and users.strip(" \t\n"):
509 msg += f"Users:\n\t{users.strip("\n").replace('\n', '\n\t')}\n\n"505 msg += f"Users:\n\t{users.strip("\n").replace('\n', '\n\t')}\n\n"
510 506
511 yield msg507 ln = v.get("line_no", 1)
508
509 yield (msg, file_ref[0][0], ln)
512 510
513 def check_issues(self):511 def check_issues(self):
514 """Warn about duplicated ABI entries"""512 """Warn about duplicated ABI entries"""