ballistica/tools/efrotools/makefile.py
2019-10-05 12:51:58 -07:00

100 lines
3.2 KiB
Python

"""Tools for parsing/filtering makefiles."""
from __future__ import annotations
import copy
from dataclasses import dataclass
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Optional, List
@dataclass
class Section:
"""Represents a section of a Makefile."""
name: Optional[str]
paragraphs: List[Paragraph]
@dataclass
class Paragraph:
"""Represents a continuous set of non-blank lines in a Makefile."""
contents: str
class Makefile:
"""Represents an entire Makefile."""
header_line_full = '#' * 80
header_line_empty = '#' + ' ' * 78 + '#'
def __init__(self, contents: str):
self.sections: List[Section] = []
self._original = copy.copy(contents)
lines = contents.splitlines()
paragraphs: List[Paragraph] = []
# First off, break into paragraphs (continuous sets of lines)
plines: List[str] = []
for line in lines:
if line.strip() == '':
if plines:
paragraphs.append(Paragraph(contents='\n'.join(plines)))
plines = []
continue
plines.append(line)
if plines:
paragraphs.append(Paragraph(contents='\n'.join(plines)))
plines = []
# Now break all paragraphs into sections.
section = Section(name=None, paragraphs=[])
self.sections.append(section)
for paragraph in paragraphs:
# Look for our very particular section headers and start
# a new section whenever we come across one.
plines = paragraph.contents.splitlines()
# pylint: disable=too-many-boolean-expressions
if (len(plines) == 5 and plines[0] == self.header_line_full
and plines[1] == self.header_line_empty
and len(plines[2]) == 80 and plines[2][0] == '#'
and plines[2][-1] == '#'
and plines[3] == self.header_line_empty
and plines[4] == self.header_line_full):
section = Section(name=plines[2][1:-1].strip(), paragraphs=[])
self.sections.append(section)
else:
section.paragraphs.append(paragraph)
def get_output(self) -> str:
"""Generate a Makefile from the current state."""
output = ''
for section in self.sections:
did_first_entry = False
if section.name is not None:
output += '\n\n' + self.header_line_full + '\n'
output += self.header_line_empty + '\n'
spacelen = 78 - len(section.name)
output += '#' + ' ' * (spacelen // 2) + section.name
spacelen -= spacelen // 2
output += ' ' * spacelen + '#\n'
output += self.header_line_empty + '\n'
output += self.header_line_full + '\n'
did_first_entry = True
for paragraph in section.paragraphs:
if did_first_entry:
output += '\n'
output += paragraph.contents + '\n'
did_first_entry = True
# print(output)
return output