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