180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru''' 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruCopyright 2011 Google Inc. 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruUse of this source code is governed by a BSD-style license that can be 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querufound in the LICENSE file. 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru''' 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport datetime 980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport re 1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudef CreateParser(filepath): 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Returns a Parser as appropriate for the file at this filepath. 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """ 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (filepath.endswith('.cpp') or 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filepath.endswith('.h') or 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filepath.endswith('.c')): 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return CParser() 1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru else: 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return None 2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass Parser(object): 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Base class for all language-specific parsers. 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """ 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def __init__(self): 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru self._copyright_pattern = re.compile('copyright', re.IGNORECASE) 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru self._attribute_pattern = re.compile( 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 'copyright.*\D(\d{4})\W*(\w.*[\w.])', re.IGNORECASE) 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def FindCopyrightBlock(self, comment_blocks): 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Given a list of comment block strings, return the one that seems 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru like the most likely copyright block. 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru Returns None if comment_blocks was empty, or if we couldn't find 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru a comment block that contains copyright info.""" 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if not comment_blocks: 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return None 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for block in comment_blocks: 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if self._copyright_pattern.search(block): 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return block 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def GetCopyrightBlockAttributes(self, comment_block): 4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Given a comment block, return a tuple of attributes: (year, holder). 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru If comment_block is None, or none of the attributes are found, 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru this will return (None, None).""" 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if not comment_block: 4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (None, None) 5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matches = self._attribute_pattern.findall(comment_block) 5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if not matches: 5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (None, None) 5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru first_match = matches[0] 5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (first_match[0], first_match[1]) 5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass CParser(Parser): 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Parser that knows how to parse C/C++ files. 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """ 6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DEFAULT_YEAR = datetime.date.today().year 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DEFAULT_HOLDER = 'Google Inc.' 6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru COPYRIGHT_BLOCK_FORMAT = ''' 6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright %s %s 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru''' 7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def __init__(self): 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru super(CParser, self).__init__() 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru self._comment_pattern = re.compile('/\*.*?\*/', re.DOTALL) 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def FindAllCommentBlocks(self, file_contents): 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Returns a list of all comment blocks within these file contents. 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """ 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return self._comment_pattern.findall(file_contents) 8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru def CreateCopyrightBlock(self, year, holder): 8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """Returns a copyright block suitable for this language, with the 8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru given attributes. 8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru @param year year in which to hold copyright (defaults to DEFAULT_YEAR) 8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru @param holder holder of copyright (defaults to DEFAULT_HOLDER) 8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru """ 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if not year: 8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru year = self.DEFAULT_YEAR 9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if not holder: 9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru holder = self.DEFAULT_HOLDER 9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return self.COPYRIGHT_BLOCK_FORMAT % (year, holder) 93