process-text-files.py: Add command indent-makefiles

The command is intended to reformat makefiles in a general fashion.
It currently only vertically aligns equal signs in makefiles.

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2019-03-03 17:11:57 +01:00
commit a4b447375a

View file

@ -23,11 +23,61 @@ class Cmd(jwutils.Cmd):
super(Cmd, self).__init__(name, help=help)
@staticmethod
def _replace_pattern(line, src, target):
def _replace_pattern(line, src, target, context=None):
return line.replace(src, target)
@staticmethod
def _replace_cpp_symbol(data, src, target):
def _indent_pattern(data, src, target, context=None):
indent = 30
pattern = '='
right_align_match = 0
skip_lhs_pattern = None
require_lhs_pattern = None
skip_short = None
min_assignments = None
if context is not None:
if 'indent' in context:
indent = context['indent']
if 'pattern' in context:
pattern = context['pattern']
if 'right-align-match' in context:
right_align_match = context['right-align-match']
if 'skip-lhs-pattern' in context:
skip_lhs_pattern = context['skip-lhs-pattern']
if 'require-lhs-pattern' in context:
require_lhs_pattern = context['require-lhs-pattern']
if 'skip-short' in context:
skip_short = context['skip-short']
if 'min-assignments' in context:
min_assignments = context['min-assignments']
r = ''
assignments=0
lines = data.splitlines()
if skip_short is not None and len(lines) < skip_short:
return data
for line in iter(lines):
#slog(NOTICE, "indenting pattern", pattern, "of", line)
parts = re.split(pattern, line)
if (
len(parts) < 2
or (skip_lhs_pattern is not None and re.match(skip_lhs_pattern, parts[0]))
or (require_lhs_pattern is not None and not re.match(require_lhs_pattern, parts[0]))
):
r += line + '\n'
continue
#slog(NOTICE, "split into", parts)
if right_align_match > 0:
parts[1] = parts[1].rjust(right_align_match)
if len(parts) > 2:
parts[2] = ' ' + parts[2].strip()
r += parts[0].rstrip().ljust(indent) + ''.join(parts[1:]) + '\n'
assignments += 1
if min_assignments is not None and assignments < min_assignments:
return data
return r
@staticmethod
def _replace_cpp_symbol(data, src, target, context=None):
stopc = "^a-zA-Z0-9_"
stopa = "(^|[" + stopc + "])"
stope = "([" + stopc + "]|$)"
@ -49,22 +99,27 @@ class Cmd(jwutils.Cmd):
# slog(NOTICE, " resulted in ", data, "->", r)
return r
def _replace_in_file(self, path, replacements, func=None, backup='rep'):
def _replace_in_file(self, path, replacements, func=None, backup='rep', context=None):
if func is None:
func = self._replace_pattern
tmp = path + '.' + backup
tmp_ext = backup
if tmp_ext is None:
tmp_ext = tmp
tmp = path + '.' + tmp_ext
changed = False
with open(path) as infile, open(tmp, 'w') as outfile:
data = infile.read()
#slog(NOTICE, "-- opened", path)
for src, target in replacements.iteritems():
#slog(NOTICE, "replacing", src, "to", target)
odata = data
#data = data.replace(src, target)
data = func(data, src, target)
data = func(data, src, target, context)
if data != odata:
#slog(NOTICE, "changed", odata, "to", data, "in", path)
changed = True
outfile.write(data)
if not changed:
os.unlink(tmp)
return False
if backup is None:
@ -163,12 +218,11 @@ class Cmd(jwutils.Cmd):
# overriding
def run(self, args):
self._init(args)
slog(NOTICE, "running")
files = []
if args.name_regex is not None:
for root, dirs, names in os.walk(args.root):
for name in names:
if re.match(args.name_regex, name):
if re.search(args.name_regex, name):
files.append((root, name))
self.process(args, files)
@ -204,7 +258,6 @@ class CmdReplaceCppSymbols(Cmd):
if args.name_regex is not None:
return super(CmdReplaceCppSymbols, self).run(args)
self._init(args)
slog(NOTICE, "running")
files = []
exts = _exts_h_cpp | set([ '.sh', '.py' ])
for root, dirs, names in os.walk(args.root):
@ -247,6 +300,35 @@ class CmdReplaceCppSymbols(Cmd):
os.rename(path, new_path)
self._fix_multiple_inclusion_preventer(args.mip_prefix, new_path)
class CmdIndentMakefileEquals(Cmd):
def __init__(self):
super(CmdIndentMakefileEquals, self).__init__("indent-makefiles", "Indent and beautify makefiles")
def add_parser(self, parsers):
p = super(CmdIndentMakefileEquals, self).add_parser(parsers)
p.add_argument('-e', "--equal-pos", help="Columns number of equal sign", type=int, default=40)
p.add_argument("--skip-short", help="Don't change makefiles with less lines of code", type=int, default=6)
p.add_argument("--min-assignments", help="Don't change makefiles with less assignment statements", type=int, default=4)
return p
def process(self, args, files):
context = dict()
right_align_match = 2
context["indent"] = args.equal_pos - right_align_match
context["pattern"] = "([?+:]*=|::=)"
context["right-align-match"] = right_align_match
context["skip-lhs-pattern"] = "[^A-Za-z0-9_# ]"
context["require-lhs-pattern"] = "^[ #]*[A-Za-z0-9_]"
context["skip-short"] = args.skip_short
context["min-assignments"] = args.min_assignments
replacements = {"blah": "blub"} # just a dummy to use _replace_in_file, TODO: obviate the need
slog(NOTICE, "indenting equal signs in", len(files), "makefiles:")
for dir, name in files:
path = dir + '/' + name
if self._replace_in_file(path, replacements, func=self._indent_pattern, context=context):
slog(NOTICE, "+ changed", path)
class CmdAddCppNamespace(Cmd):
def __init__(self):
@ -263,7 +345,6 @@ class CmdAddCppNamespace(Cmd):
if args.name_regex is not None:
return super(CmdAddCppNamespace, self).run(args)
self._init(args)
slog(NOTICE, "running")
files = []
exts = _exts_h_cpp | set([ '.sh', '.py' ])
for root, dirs, names in os.walk(args.root):