1935d94500d4864b352f964b643ff10785e92924eepoger@google.com''' 2935d94500d4864b352f964b643ff10785e92924eepoger@google.comCopyright 2011 Google Inc. 3935d94500d4864b352f964b643ff10785e92924eepoger@google.com 4935d94500d4864b352f964b643ff10785e92924eepoger@google.comUse of this source code is governed by a BSD-style license that can be 5935d94500d4864b352f964b643ff10785e92924eepoger@google.comfound in the LICENSE file. 6935d94500d4864b352f964b643ff10785e92924eepoger@google.com''' 7935d94500d4864b352f964b643ff10785e92924eepoger@google.com 8935d94500d4864b352f964b643ff10785e92924eepoger@google.comimport datetime 9935d94500d4864b352f964b643ff10785e92924eepoger@google.comimport re 10935d94500d4864b352f964b643ff10785e92924eepoger@google.com 11935d94500d4864b352f964b643ff10785e92924eepoger@google.comdef CreateParser(filepath): 12935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Returns a Parser as appropriate for the file at this filepath. 13935d94500d4864b352f964b643ff10785e92924eepoger@google.com """ 14935d94500d4864b352f964b643ff10785e92924eepoger@google.com if (filepath.endswith('.cpp') or 15935d94500d4864b352f964b643ff10785e92924eepoger@google.com filepath.endswith('.h') or 16935d94500d4864b352f964b643ff10785e92924eepoger@google.com filepath.endswith('.c')): 17935d94500d4864b352f964b643ff10785e92924eepoger@google.com return CParser() 18935d94500d4864b352f964b643ff10785e92924eepoger@google.com else: 19935d94500d4864b352f964b643ff10785e92924eepoger@google.com return None 20935d94500d4864b352f964b643ff10785e92924eepoger@google.com 21935d94500d4864b352f964b643ff10785e92924eepoger@google.com 22935d94500d4864b352f964b643ff10785e92924eepoger@google.comclass Parser(object): 23935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Base class for all language-specific parsers. 24935d94500d4864b352f964b643ff10785e92924eepoger@google.com """ 25935d94500d4864b352f964b643ff10785e92924eepoger@google.com 26935d94500d4864b352f964b643ff10785e92924eepoger@google.com def __init__(self): 27935d94500d4864b352f964b643ff10785e92924eepoger@google.com self._copyright_pattern = re.compile('copyright', re.IGNORECASE) 28935d94500d4864b352f964b643ff10785e92924eepoger@google.com self._attribute_pattern = re.compile( 29935d94500d4864b352f964b643ff10785e92924eepoger@google.com 'copyright.*\D(\d{4})\W*(\w.*[\w.])', re.IGNORECASE) 30935d94500d4864b352f964b643ff10785e92924eepoger@google.com 31935d94500d4864b352f964b643ff10785e92924eepoger@google.com def FindCopyrightBlock(self, comment_blocks): 32935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Given a list of comment block strings, return the one that seems 33935d94500d4864b352f964b643ff10785e92924eepoger@google.com like the most likely copyright block. 34935d94500d4864b352f964b643ff10785e92924eepoger@google.com 35935d94500d4864b352f964b643ff10785e92924eepoger@google.com Returns None if comment_blocks was empty, or if we couldn't find 36935d94500d4864b352f964b643ff10785e92924eepoger@google.com a comment block that contains copyright info.""" 37935d94500d4864b352f964b643ff10785e92924eepoger@google.com if not comment_blocks: 38935d94500d4864b352f964b643ff10785e92924eepoger@google.com return None 39935d94500d4864b352f964b643ff10785e92924eepoger@google.com for block in comment_blocks: 40935d94500d4864b352f964b643ff10785e92924eepoger@google.com if self._copyright_pattern.search(block): 41935d94500d4864b352f964b643ff10785e92924eepoger@google.com return block 42935d94500d4864b352f964b643ff10785e92924eepoger@google.com 43935d94500d4864b352f964b643ff10785e92924eepoger@google.com def GetCopyrightBlockAttributes(self, comment_block): 44935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Given a comment block, return a tuple of attributes: (year, holder). 45935d94500d4864b352f964b643ff10785e92924eepoger@google.com 46935d94500d4864b352f964b643ff10785e92924eepoger@google.com If comment_block is None, or none of the attributes are found, 47935d94500d4864b352f964b643ff10785e92924eepoger@google.com this will return (None, None).""" 48935d94500d4864b352f964b643ff10785e92924eepoger@google.com if not comment_block: 49935d94500d4864b352f964b643ff10785e92924eepoger@google.com return (None, None) 50935d94500d4864b352f964b643ff10785e92924eepoger@google.com matches = self._attribute_pattern.findall(comment_block) 51935d94500d4864b352f964b643ff10785e92924eepoger@google.com if not matches: 52935d94500d4864b352f964b643ff10785e92924eepoger@google.com return (None, None) 53935d94500d4864b352f964b643ff10785e92924eepoger@google.com first_match = matches[0] 54935d94500d4864b352f964b643ff10785e92924eepoger@google.com return (first_match[0], first_match[1]) 55935d94500d4864b352f964b643ff10785e92924eepoger@google.com 56935d94500d4864b352f964b643ff10785e92924eepoger@google.com 57935d94500d4864b352f964b643ff10785e92924eepoger@google.comclass CParser(Parser): 58935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Parser that knows how to parse C/C++ files. 59935d94500d4864b352f964b643ff10785e92924eepoger@google.com """ 60935d94500d4864b352f964b643ff10785e92924eepoger@google.com 61935d94500d4864b352f964b643ff10785e92924eepoger@google.com DEFAULT_YEAR = datetime.date.today().year 62935d94500d4864b352f964b643ff10785e92924eepoger@google.com DEFAULT_HOLDER = 'Google Inc.' 63935d94500d4864b352f964b643ff10785e92924eepoger@google.com COPYRIGHT_BLOCK_FORMAT = ''' 64935d94500d4864b352f964b643ff10785e92924eepoger@google.com/* 65935d94500d4864b352f964b643ff10785e92924eepoger@google.com * Copyright %s %s 66935d94500d4864b352f964b643ff10785e92924eepoger@google.com * 67935d94500d4864b352f964b643ff10785e92924eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 68935d94500d4864b352f964b643ff10785e92924eepoger@google.com * found in the LICENSE file. 69935d94500d4864b352f964b643ff10785e92924eepoger@google.com */ 70935d94500d4864b352f964b643ff10785e92924eepoger@google.com''' 71935d94500d4864b352f964b643ff10785e92924eepoger@google.com 72935d94500d4864b352f964b643ff10785e92924eepoger@google.com def __init__(self): 73935d94500d4864b352f964b643ff10785e92924eepoger@google.com super(CParser, self).__init__() 74935d94500d4864b352f964b643ff10785e92924eepoger@google.com self._comment_pattern = re.compile('/\*.*?\*/', re.DOTALL) 75935d94500d4864b352f964b643ff10785e92924eepoger@google.com 76935d94500d4864b352f964b643ff10785e92924eepoger@google.com def FindAllCommentBlocks(self, file_contents): 77935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Returns a list of all comment blocks within these file contents. 78935d94500d4864b352f964b643ff10785e92924eepoger@google.com """ 79935d94500d4864b352f964b643ff10785e92924eepoger@google.com return self._comment_pattern.findall(file_contents) 80935d94500d4864b352f964b643ff10785e92924eepoger@google.com 81935d94500d4864b352f964b643ff10785e92924eepoger@google.com def CreateCopyrightBlock(self, year, holder): 82935d94500d4864b352f964b643ff10785e92924eepoger@google.com """Returns a copyright block suitable for this language, with the 83935d94500d4864b352f964b643ff10785e92924eepoger@google.com given attributes. 84935d94500d4864b352f964b643ff10785e92924eepoger@google.com 85935d94500d4864b352f964b643ff10785e92924eepoger@google.com @param year year in which to hold copyright (defaults to DEFAULT_YEAR) 86935d94500d4864b352f964b643ff10785e92924eepoger@google.com @param holder holder of copyright (defaults to DEFAULT_HOLDER) 87935d94500d4864b352f964b643ff10785e92924eepoger@google.com """ 88935d94500d4864b352f964b643ff10785e92924eepoger@google.com if not year: 89935d94500d4864b352f964b643ff10785e92924eepoger@google.com year = self.DEFAULT_YEAR 90935d94500d4864b352f964b643ff10785e92924eepoger@google.com if not holder: 91935d94500d4864b352f964b643ff10785e92924eepoger@google.com holder = self.DEFAULT_HOLDER 92935d94500d4864b352f964b643ff10785e92924eepoger@google.com return self.COPYRIGHT_BLOCK_FORMAT % (year, holder) 93