Skip to content

Instantly share code, notes, and snippets.

@chromakode
Created February 20, 2010 22:52
Show Gist options
  • Save chromakode/309970 to your computer and use it in GitHub Desktop.
Save chromakode/309970 to your computer and use it in GitHub Desktop.
A somewhat scary header munger. You'd better have good version control!
#!/usr/bin/env python
from __future__ import print_function
import sys
import os, os.path
import shutil
import optparse
import re
comment_ignore_re = re.compile(r"#!.+")
comment_re = re.compile(r"""^\#.*$ # Python style
|^//.*$ # C line style
|^/\*.*\*/$ # C block style""", re.VERBOSE)
def split_header(sourcefile):
pre_lines = list()
header_lines = list()
rest_lines = list()
PRE, IN, POST = range(3)
state = PRE
for line in sourcefile:
# Retain ignored lines preceding the header, such as shebangs.
if state is PRE:
if comment_ignore_re.match(line):
pre_lines.append(line)
else:
state = IN
# Add all comment lines until the initial comment block ends.
if state is IN:
if comment_re.match(line):
if not comment_ignore_re.match(line):
header_lines.append(line)
else:
state = POST
# Add any whitespace separating the header from other contents.
if state is POST:
if line.strip() == "":
header_lines.append(line)
else:
rest_lines.append(line)
break
rest_lines.extend(sourcefile)
return "".join(pre_lines), "".join(header_lines), "".join(rest_lines)
def get_template(exemplar):
pre, header, rest = split_header(exemplar)
header_template = header.replace(os.path.normpath(exemplar.name), "{path}")
header_template = header_template.replace(os.path.basename(exemplar.name), "{basename}")
return header_template
def substitute_template(template, sourcefile):
return template.format(basename=os.path.basename(sourcefile.name),
path=os.path.normpath(sourcefile.name))
def apply_template(template, sourcefile):
pre, header, rest = split_header(sourcefile)
return pre + substitute_template(template, sourcefile) + rest
def nanny(root_path, exemplar_path, extensions=None, file_ignore_regex=None):
if not extensions:
# By default, only affect files with the same extension as the exemplar.
extensions = [os.path.splitext(exemplar_path)[1]]
file_ignore_re = re.compile(file_ignore_regex)
header_template = get_template(open(exemplar_path))
print("Using header format:")
print("---")
print(header_template, end="")
print("---")
if not raw_input("Continue? [yN] ").lower() == "y":
return 0
for root, dirs, files in os.walk(root_path):
for name in files:
filename, extension = os.path.splitext(name)
if extension in extensions and file_ignore_re.match(name) is None:
path = os.path.join(root, name)
with open(path, "r") as sourcefile:
newdata = apply_template(header_template, sourcefile)
#shutil.copy(path, path+"~")
with open(path, "w") as sourcefile:
sourcefile.write(newdata)
print("Processed: {0}".format(path))
return 0
def main():
if len(sys.argv) != 3:
print("Usage: {0} ROOT EXEMPLAR".format(os.path.basename(sys.argv[0])))
sys.exit(1)
else:
sys.exit(nanny(*sys.argv[1:], file_ignore_regex="__init__.py"))
if __name__=="__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment