Last active
March 7, 2019 12:50
-
-
Save eruffaldi/51513cb4d656c797b129 to your computer and use it in GitHub Desktop.
A simple tool for managing the license header of C/C++ files. Allows for removal, regeneration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Edit Header for C/C++ | |
# Scan Files and Verify license for C/C++ | |
# | |
# Emanuele Ruffaldi 2015-2016 | |
# | |
# Usage: | |
# - select files using a combination of find/grep e.g. | |
# find . | grep -v buildosx | grep -v buildwin | grep -E ".*\.(cpp|hpp|h)$" | |
# - verify used headers or per-file | |
# python editheader.py --filelist FILELIST --all --listlicenses | |
# python editheader.py --filelist FILELIST --all --list | |
# - regenerate all | |
# python editheader.py --filelist FILELIST --all --replace MYLICENSE | |
# - replace license | |
import argparse | |
import os,re | |
import sys | |
from collections import defaultdict | |
class bcolors: | |
HEADER = '\033[95m' | |
OKBLUE = '\033[94m' | |
OKGREEN = '\033[92m' | |
WARNING = '\033[93m' | |
FAIL = '\033[91m' | |
ENDC = '\033[0m' | |
BOLD = '\033[1m' | |
UNDERLINE = '\033[4m' | |
def findfiles(args): | |
rem = re.compile(".*\.(cpp|hpp|c|h)$") | |
files = [] | |
#build expression for the exclusion of paths and files | |
for x in args.paths: | |
if os.path.isfile(x): | |
files.append(x) | |
else: | |
matches = [] | |
for root, dirnames, filenames in os.walk(x): | |
# TODO check path exclusion | |
for filename in filenames: | |
if rem.match(filename): | |
# TODO check file exclusion | |
files.append(os.path.join(root, filename)) | |
return files | |
def extractlicense(filename,args): | |
lines = [] | |
doublemode = False | |
hasmarker = False | |
if args.assume_empty: | |
return (False,False,0,list(open(filename,"r"))) | |
for e,l in enumerate(open(filename,"r")): | |
l = l.strip() | |
if e == 0: | |
# first line | |
if not l.startswith("/*"): | |
if l.startswith("//"): | |
doublemode = True | |
elif l.startswith("#"): | |
return (False,False,e,[]) | |
else: | |
return (False,False,e,"OTHER") | |
l = l[2:].strip() | |
if l != "" and l != "*": | |
lines.append(l) | |
else: | |
# stop on preprocessor | |
if l.startswith("#"): | |
break | |
elif doublemode: | |
if l.startswith("//"): | |
l = l[2:].strip() | |
if l == args.marker: | |
break | |
else: | |
lines.append(l) | |
else: | |
if l.startswith("*/"): | |
if not args.special: | |
break | |
else: | |
if l.startswith("*"): | |
l = l[1:].strip() | |
if l == args.marker: | |
hasmarker = True | |
if not args.special: | |
break | |
else: | |
lines.append(l) | |
return (doublemode,hasmarker,e,lines) | |
def main(): | |
parser = argparse.ArgumentParser(description='List and modify licenses') | |
parser.add_argument('paths', metavar='paths', type=str, nargs='*', | |
help='list of files') | |
parser.add_argument('--filelist', help="takes files from this list instead from path") | |
parser.add_argument('--list', action='store_true',help="list file found with details") | |
parser.add_argument('--listlicenses', action='store_true',help="list licenses with related files") | |
parser.add_argument('--listnames', action='store_true',help="list filenames only") | |
parser.add_argument('--assume-empty', action='store_true') | |
#parser.add_argument('--exclude',type=str,nargs='*',help="relative paths to be excluded") | |
parser.add_argument('--marker', help="marker used at the end of the first block comment",default="--") | |
parser.add_argument('--all', help="select all files, otherwise only ones with marker present or empty license",action="store_true") | |
#parser.add_argument('--selecttopragma', help="removes license froms elected files",action="store_true") | |
parser.add_argument('--remove', help="Removes All licenses",action="store_true") | |
parser.add_argument('--test', help="Test Mode, does nothing",action="store_true") | |
parser.add_argument('--replace', help="Replace all licenses with new file") | |
parser.add_argument('--special', help="eat everything",action="store_true") | |
parser.add_argument('--new', help="Instead of replacing files produce a file with appended .new",action="store_true") | |
parser.add_argument('--regen', help="Extract and Regenerate the Licence",action="store_true") | |
args = parser.parse_args() | |
newlicense = None | |
if args.remove: | |
newlicense = [] | |
elif args.replace: | |
newlicense = open(args.replace,"r").read().split("\n") | |
elif args.regen: | |
newlicense = [] | |
files = [] | |
if args.filelist: | |
files = [x.strip() for x in open(args.filelist,"r") if x.strip() != ""] | |
else: | |
files = findfiles(args) | |
wfiles = [(x,extractlicense(x,args)) for x in files] | |
if not args.all: | |
# pick only marker or empty | |
wfiles = [x for x in wfiles if x[1][1] or len(x[1][3]) == 0] | |
if args.listnames: | |
for f,l in wfiles: | |
print(f) | |
elif args.list: | |
for f,l in wfiles: | |
(doublemode,hasmarker,e,lines) = l | |
print(bcolors.OKGREEN,f,bcolors.ENDC) | |
print("\tdoublemode",doublemode) | |
print("\thasmarker",hasmarker) | |
print("\tendline",e) | |
print("\tlines",lines) | |
elif args.listlicenses: | |
ll = defaultdict(list) | |
for f,l in wfiles: | |
(doublemode,hasmarker,e,lines) = l | |
ll[tuple(lines)].append(f) | |
for k,v in ll.items(): | |
print(k) | |
for y in v: | |
print("\t",y) | |
elif newlicense is not None: | |
if len(newlicense) != 0: | |
a = ["/**"] | |
for x in newlicense: | |
a.append(" * " + x) | |
a.append(" * " +args.marker) | |
a.append(" */") | |
newlicenseblock = a | |
else: | |
newlicenseblock = [] | |
for f,l in wfiles: | |
doublemode,hasmarker,e,existing = l | |
ff = open(f,"r") | |
w = ff.read().split("\n") | |
ff.close() | |
pre = w[0:e] | |
post = w[e:] | |
if not args.regen and newlicense == existing: | |
print("same",f) | |
else: | |
if args.regen: | |
newlicenseblock = existing | |
tf = (args.new and f+".new" or f) | |
if not args.test: | |
print("updating",f,len(newlicenseblock),"post",len(post)) | |
open(tf,"w").write("\n".join(newlicenseblock + post)) | |
else: | |
print("test updating",tf,"newlicenselines",len(newlicenseblock),"from",e,"bodylines",len(post)) | |
else: | |
print("no action") | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment