# 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', '', '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()