aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Harder <radhermit@gmail.com>2021-01-04 05:03:45 -0700
committerTim Harder <radhermit@gmail.com>2021-01-04 05:12:46 -0700
commita633697c65dcd27fa609db8a4e63b463eb0762a1 (patch)
treec031d9aef2612f846181d90e7127b9f94b2b4151
parentebuild.eclass: add support for converting eclassdocs to rst/man/html (diff)
downloadpkgcore-a633697c65dcd27fa609db8a4e63b463eb0762a1.tar.gz
pkgcore-a633697c65dcd27fa609db8a4e63b463eb0762a1.tar.bz2
pkgcore-a633697c65dcd27fa609db8a4e63b463eb0762a1.zip
ebuild.eclass: use literal blocks for all multiline text
The only way to sanely handle haphazard pseudo-formatting currently seen in eclasses.
-rw-r--r--src/pkgcore/ebuild/eclass.py76
1 files changed, 33 insertions, 43 deletions
diff --git a/src/pkgcore/ebuild/eclass.py b/src/pkgcore/ebuild/eclass.py
index 50077300..6d8f383b 100644
--- a/src/pkgcore/ebuild/eclass.py
+++ b/src/pkgcore/ebuild/eclass.py
@@ -5,8 +5,6 @@ import re
import shlex
import subprocess
from functools import partial
-from itertools import groupby
-from operator import itemgetter
from snakeoil import klass
from snakeoil.mappings import ImmutableDict, OrderedSet
@@ -33,6 +31,17 @@ class AttrDict(ImmutableDict):
return sorted(dir(self._dict) + list(self._dict))
+def _rst_header(char, text, leading=False, newline=False):
+ """Create rST header data from a given character and header text."""
+ sep = char * len(text)
+ data = [text, sep]
+ if leading:
+ data = [sep] + data
+ if newline:
+ data.append('')
+ return data
+
+
class ParseEclassDoc:
"""Generic block for eclass docs.
@@ -60,8 +69,10 @@ class ParseEclassDoc:
self.tags = tags
# regex matching all known tags for the eclass doc block
self._block_tags_re = re.compile(rf'^(?P<tag>{"|".join(self.tags)})(?P<value>.*)')
- # regex matching @CODE tags for literal blocks
- self._code_block = re.compile(r'^\s*@CODE\s*$')
+ # regex matching @CODE tags
+ self._code_tag = re.compile(r'^\s*@CODE\s*$')
+ # regex matching @SUBSECTION tags
+ self._subsection_tag = re.compile(r'^\s*@SUBSECTION (?P<title>.+)$')
def _tag_bool(self, block, tag, lineno):
"""Parse boolean tags."""
@@ -95,43 +106,33 @@ class ParseEclassDoc:
return tuple(block[1:])
def _tag_multiline_str(self, block, tag, lineno):
- """Parse tags with multiline text while handling @CODE tags."""
+ """Parse tags with multiline text while handling @CODE/@SUBSECTION tags."""
lines = self._tag_multiline_args(block, tag, lineno)
- data = []
- indented = []
- code_block = False
+ if not lines:
+ return None
+
+ # use literal blocks for all multiline text
+ data = ['::', '\n\n']
for i, line in enumerate(lines, 1):
- if self._code_block.match(line):
- # in a literal code block
- if code_block:
- code_block = False
- else:
- code_block = lineno + i
- data.extend(['\n', '.. code-block:: bash', '\n\n'])
+ if self._code_tag.match(line):
+ continue
+ elif mo := self._subsection_tag.match(line):
+ header = _rst_header('~', mo.group('title'))
+ data.extend(f'{x}\n' for x in header)
+ data.extend(['::', '\n\n'])
elif line:
- if code_block:
- # add indentation for code blocks
- line = f' {line}'
- elif re.match(r'^\s+', line):
- indented.append(lineno + i)
- data.append(f'{line}\n')
+ data.append(f' {line}\n')
else:
data.append('\n')
- if code_block:
- logger.warning(f'{repr(tag)}, line {code_block}: unterminated @CODE block')
- for k, g in groupby(enumerate(indented), lambda x: x[0] - x[1]):
- lines = list(map(itemgetter(1), g))
- if len(lines) == 1:
- context = f'line {lines[0]}'
- else:
- context = f'lines {lines[0]}-{lines[1]}'
- logger.warning(
- f'{repr(tag)}, {context}: indented code not in @CODE block')
-
return ''.join(data).rstrip('\n')
+ def _tag_multiline_rst(self, block, tag, lineno):
+ """Parse tags with multiline rST formatting."""
+ lines = self._tag_multiline_args(block, tag, lineno)
+ return ''.join(lines).rstrip('\n')
+
def _tag_deprecated(self, block, tag, lineno):
"""Parse deprecated tags."""
arg = self._tag_inline_arg(block, tag, lineno)
@@ -312,17 +313,6 @@ _eclass_blocks_re = re.compile(
rf'^(?P<prefix>\s*#) (?P<tag>{"|".join(ParseEclassDoc.blocks)})(?P<value>.*)')
-def _rst_header(char, text, leading=False, newline=False):
- """Create rST header data from a given character and header text."""
- sep = char * len(text)
- data = [text, sep]
- if leading:
- data = [sep] + data
- if newline:
- data.append('')
- return data
-
-
class EclassDoc(AttrDict):
"""Support parsing eclass docs for a given eclass path."""