#!/usr/bin/python # # Does the copyright statement include the year of the latest git commit? # # Copyright (C) 2012, 2014 Codethink Limited # # This program 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; version 2 of the License. # # 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from __future__ import print_function import datetime import re import sys import cliapp class CheckCopyrightYear(cliapp.Application): pat = re.compile(r'^[ #/*]*Copyright\s+(\(C\)\s*)' r'(?P[0-9, -]+)') def add_settings(self): self.settings.boolean(['verbose', 'v'], 'be more verbose') def setup(self): self.all_ok = True self.uncommitted = self.get_uncommitted_files() self.this_year = datetime.datetime.now().year def cleanup(self): if not self.all_ok: print('ERROR: Some copyright years need fixing', file=sys.stderr) sys.exit(1) def get_uncommitted_files(self): filenames = set() status = self.runcmd(['git', 'status', '--porcelain', '-z']) tokens = status.rstrip('\0').split('\0') while tokens: tok = tokens.pop(0) filenames.add(tok[3:]) if 'R' in tok[0:2]: filenames.add(tokens.pop(0)) return filenames def process_input_line(self, filename, line): m = self.pat.match(line) if not m: return year = None if filename not in self.uncommitted: year = self.get_git_commit_year(filename) if year is None: # git does not have a commit date for the file, which might # happen if the file isn't committed yet. This happens during # development, and it's OK. It's not quite a lumberjack, but # let's not get into gender stereotypes here. year = self.this_year ok = False for start, end in self.get_copyright_years(m): if start <= year <= end: ok = True if ok: if self.settings['verbose']: self.output.write('OK %s\n' % filename) else: self.output.write('BAD %s:%s:%s\n' % (filename, self.lineno, line.strip())) self.all_ok = self.all_ok and ok def get_git_commit_year(self, filename): out = self.runcmd(['git', 'log', '-1', '--format=format:%cd', filename]) if not out: return None words = out.split() return int(words[4]) def get_copyright_years(self, match): years = match.group('years') groups = [s.strip() for s in years.split(',')] for group in groups: if '-' in group: start, end = group.split('-') else: start = end = group start = int(start) end = int(end) yield start, end CheckCopyrightYear().run()