cloudstack/tools/build/addcopyright.py
Gavin Lee 39a676c496 Correct license header mainly for patches folder
Signed-off-by: Chip Childers <chip.childers@gmail.com>
I've assumed that Gavin's commit is appropriate, based
on an assumption that we will keep these files in the source
tree.  If https://issues.apache.org/jira/browse/LEGAL-146
results in a different opionion from the members, then we
will end up having to do something more drastic anyway.
2012-08-31 10:50:46 -04:00

301 lines
12 KiB
Python
Executable File

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from optparse import OptionParser
import sys
import os, os.path
import fnmatch
import time
class CopyRightDetecter(object):
def isCopyRightLine(self, txt):
return False
class KeyWordCopyRightDetecter(CopyRightDetecter):
keywords = ['Cloud.com', 'Copyright', '(C)', '2011', 'Citrix', 'Systems', 'Inc', 'All', 'rights', 'reserved', 'This', 'software', 'is', 'licensed', 'under', 'the',
'GNU', 'General', 'Public', 'License', 'v3', 'or', 'later', 'It', 'is', 'free', 'software:', 'you', 'can', 'redistribute', 'it', 'and/or', 'modify', 'it',
'under', 'the', 'terms', 'of', 'the', 'GNU', 'General', 'Public', 'License', 'as', 'published', 'by', 'the', 'Free', 'Software', 'Foundation', 'either',
'version', '3', 'of', 'the', 'License', 'or', 'any', 'later', 'version', 'This', 'program', 'is', 'distributed', 'in', 'the', 'hope', 'that', 'it', 'will',
'be', 'useful', 'but', 'WITHOUT', 'ANY', 'WARRANTY;', 'without', 'even', 'the', 'implied', 'warranty', 'of', 'MERCHANTABILITY', 'or', 'FITNESS', 'FOR', 'A',
'PARTICULAR', 'PURPOSE', 'See', 'the', 'GNU', 'General', 'Public', 'License', 'for', 'more', 'details', 'You', 'should', 'have', 'received', 'a', 'copy', 'of',
'the', 'GNU', 'General', 'Public', 'License', 'along', 'with', 'this', 'program', 'If', 'not', 'see', '<http://www.gnu.org/licenses/>', 'Version', '2', 'only',
'("GPL")', 'Common', 'Development', 'and', 'Distribution', 'License("CDDL")', '(collectively', 'License").', 'language', 'governing', 'permissions', 'limitations',
'License.', '-', 'When', 'distributing', 'include', 'Header', 'Notice', 'each', 'file', 'at', 'glassfish/bootstrap/legal/LICENSE.txt.', 'Sun', 'designates',
'particular', 'subject', 'to', 'Classpath', 'exception', 'provided', 'GPL', 'section', 'accompanied', 'code.', 'applicable', 'add', 'following', 'below',
'fields', 'enclosed', 'brackets', 'replaced', 'your', 'own', 'identifying', 'information', 'Portions', 'Copyrighted', 'year', 'name', 'copyright', 'owner]',
'Contributor(s)', 'indicate', 'decision', 'adding', '[Contributor', 'elects', 'distribution', 'CDDL', 'license.', "don't", 'single', 'choice', 'license',
'recipient', 'has', 'option', 'distribute', 'extend', 'its', 'licensees', 'above.', 'However', 'if', 'code', 'therefore', 'elected', 'then', 'applies', 'new',
'made', 'such', 'holder.']
def isCopyRightLine(self, txt):
words = [ c.strip().strip('.').strip('\n').strip(',').strip() for c in txt.split(" ") ]
total = len(words)
if total == 0: return False
numKeyWord = 0
for w in words:
if w == "": continue
if w in self.keywords: numKeyWord+=1
if float(numKeyWord)/float(total) >= float(1)/float(2): return True
return False
copyRightDetectingFactory = {"KeyWord":KeyWordCopyRightDetecter.__name__}
logfd = open("/tmp/addcopyright.log", 'w')
class Logger(object):
@staticmethod
def info(msg):
sys.stdout.write("INFO: %s"%msg)
sys.stdout.write("\n")
sys.stdout.flush()
@staticmethod
def debug(msg):
logfd.write("DEBUG: %s"%msg)
logfd.write("\n")
@staticmethod
def warn(msg):
sys.stdout.write("WARNNING: %s"%msg)
sys.stdout.write("\n")
sys.stdout.flush()
@staticmethod
def error(msg):
sys.stderr.write("ERROR: %s"%msg)
sys.stderr.write("\n")
sys.stderr.flush()
class Adder(object):
defaultTxt = '''Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
'''
copyRightTxt = None
targetFile = None
fileBody = None
decter = None
signature = 'Automatically generated by addcopyright.py at %s' % time.strftime("%m/%d/%Y", time.localtime())
COMMENT_NOTATION = ""
def __init__(self):
self.decter = eval(copyRightDetectingFactory["KeyWord"])()
def setTargetFile(self, fpath):
self.targetFile = fpath
if not os.path.exists(self.targetFile):
raise Exception("Cannot find %s"%self.targetFile)
def setCopyRightTxt(self, txt):
self.copyRightTxt = txt.split("\n")
def checkParams(self):
assert self.targetFile != None, "Target file not set"
if self.copyRightTxt == None:
self.copyRightTxt = self.defaultTxt.split("\n")
def pasteCopyRight(self):
self.fileBody = self.copyRightTxt + self.fileBody
file(self.targetFile, 'w').write("".join(self.fileBody))
Logger.info("Added copyright header to %s"%self.targetFile)
def composeCopyRight(self):
l = self.copyRightTxt
l.append(self.signature)
l = [ self.COMMENT_NOTATION + " " + line + "\n" for line in l ]
self.copyRightTxt = l
def getFileBody(self):
self.fileBody = file(self.targetFile).readlines()
def isCommentLine(self, line):
if line.strip().startswith(self.COMMENT_NOTATION):
return True
return False
def removeOldCopyRight(self):
newBody = []
removed = False
for line in self.fileBody[0:50]:
if self.isCommentLine(line) and self.decter.isCopyRightLine(line):
removed = True
Logger.debug("remove old copyright: %s" % line)
continue
newBody.append(line)
self.fileBody = newBody + self.fileBody[50:]
if removed:
Logger.info("Removed old copyright header of %s"%self.targetFile)
def cleanBlankComment(self):
newBody = []
for l in self.fileBody[0:50]:
if self.isCommentLine(l) and l.strip().strip(self.COMMENT_NOTATION).strip().strip('\n') == "":
Logger.debug("Blank Comment: %s" % l)
continue
newBody.append(l)
self.fileBody = newBody + self.fileBody[50:]
def doWork(self):
self.checkParams()
self.getFileBody()
self.removeOldCopyRight()
self.composeCopyRight()
self.cleanBlankComment()
self.pasteCopyRight()
class SqlAdder(Adder):
def __init__(self):
super(SqlAdder, self).__init__()
self.COMMENT_NOTATION = "#"
class InterpreterAdder(Adder):
def __init__(self):
super(InterpreterAdder, self).__init__()
self.COMMENT_NOTATION = "#"
def pasteCopyRight(self):
if len(self.fileBody) > 0 and self.isCommentLine(self.fileBody[0]):
# Don't cover the first line of interpreter comment
self.fileBody = [self.fileBody[0]] + self.copyRightTxt + self.fileBody[1:]
else:
self.fileBody = self.copyRightTxt + self.fileBody
file(self.targetFile, 'w').write("".join(self.fileBody))
Logger.info("Added copyright header to %s"%self.targetFile)
class JavaAdder(Adder):
commentOn = False
def __init__(self):
super(JavaAdder, self).__init__()
self.COMMENT_NOTATION = '//'
def isCommentLine(self, line):
if line.strip().startswith('//'):
return True
elif line.strip().startswith('/*'):
self.commentOn = True
return True
elif self.commentOn == True and line.find('*/') != -1:
self.commentOn = False
return True
elif self.commentOn:
return True
else:
return False
def cleanBlankComment(self):
#TODO
pass
copyRightAdderFactory = {".sql":SqlAdder.__name__, ".sh":InterpreterAdder.__name__, ".py":InterpreterAdder.__name__}
class CopyRightAdder(object):
parser = None
options = None
args = None
targetFiles = None
excludeFiles = None
copyRightFileTxt = None
rootDir = None
def errAndExit(self, msg):
Logger.error(msg)
Logger.info("addcopyright -h for help")
sys.exit(1)
def __init__(self):
usage = '''Usage: addcopyright [file_name_pattern] [--exculdes=file_name_pattern] [--file=copyright_file] [--root=root_dir_of_files_to_add_header] [--replace]
Examples:
addcopyright
addcopyright *.sql
addcopyright *.sql --excludes="*.sql~"
addcopyright *.sql --file=/root/Citrix.copyright
addcopyright *.sql --file=/root/Citrix.copyright --root=~/cloudstack-oss
'''
self.parser = OptionParser(usage=usage)
self.parser.add_option("", "--excludes", action="store", type="string", dest="excludes", default="",
help="Exclude these files when adding copyright header")
self.parser.add_option("", "--file", action="store", type="string", dest="copyRightFile", default="",
help="Path to copyright header file. Default to Citrix copyright header")
self.parser.add_option("", "--root", action="store", type="string", dest="rootDir", default="",
help="Root folder where files being added copyright header locate. Default to current directory")
(self.options, self.args) = self.parser.parse_args()
if len(self.args) > 1:
self.errAndExit("Invalid arguments:%s" % self.args)
if len(self.args) == 1:
self.targetFiles = self.args[0]
if self.options.excludes != "":
self.excludeFiles = self.options.excludes
if self.options.copyRightFile != "":
self.copyRightFileTxt = file(self.options.copyRightFile).read()
if self.options.rootDir != "":
self.rootDir = os.path.expanduser(self.options.rootDir)
if not os.path.isdir(self.rootDir): raise Exception("Cannot find directory %s"%self.rootDir)
else:
self.rootDir = os.getcwd()
def createConcreteAdder(self, filename):
(x, ext) = os.path.splitext(filename)
if not copyRightAdderFactory.has_key(ext): return None
return eval(copyRightAdderFactory[ext])()
def run(self):
for root, dirs, files in os.walk(self.rootDir):
for f in files:
fpath = os.path.join(root, f)
if self.excludeFiles != None and fnmatch.fnmatch(f, self.excludeFiles):
Logger.info("Skipping excluded file %s" % fpath)
continue
if self.targetFiles != None and not fnmatch.fnmatch(f, self.targetFiles):
Logger.info("Skipping %s not matching our file name pattern" % fpath)
continue
adder = self.createConcreteAdder(f)
if adder == None:
Logger.warn("Cannot find a proper copyright Adder for %s, skip it" % fpath)
continue
adder.setTargetFile(fpath)
if self.copyRightFileTxt != None:
adder.setCopyRightTxt(self.copyRightFileTxt)
adder.doWork()
if __name__ == '__main__':
task = CopyRightAdder()
task.run()