| 1 | #!/usr/bin/env python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | # |
|---|
| 4 | # Copyright (c) 2008 the NxOS developers |
|---|
| 5 | # |
|---|
| 6 | # See AUTHORS for a full list of the developers. |
|---|
| 7 | # |
|---|
| 8 | # Redistribution of this file is permitted under |
|---|
| 9 | # the terms of the GNU Public License (GPL) version 2. |
|---|
| 10 | # |
|---|
| 11 | # Receives a unified diff on standard input. Scans all altered files |
|---|
| 12 | # for copyright notices, and warns about missing notices in relevant |
|---|
| 13 | # files, as well as copyrights that should be tweaked. |
|---|
| 14 | |
|---|
| 15 | import time |
|---|
| 16 | import os |
|---|
| 17 | import sys |
|---|
| 18 | import re |
|---|
| 19 | |
|---|
| 20 | COPYRIGHT_RE = re.compile(r'Copyright \(([cC])\) ([0-9\-,]+) the NxOS developers') |
|---|
| 21 | |
|---|
| 22 | current_year = time.gmtime()[0] |
|---|
| 23 | |
|---|
| 24 | def years_in_group(group): |
|---|
| 25 | if '-' in group: |
|---|
| 26 | min, max = (int(x) for x in group.split('-')) |
|---|
| 27 | for year in xrange(min, max+1): |
|---|
| 28 | yield year |
|---|
| 29 | else: |
|---|
| 30 | yield int(group) |
|---|
| 31 | |
|---|
| 32 | def parse_years(years_str): |
|---|
| 33 | years = set() |
|---|
| 34 | for group in years_str.split(','): |
|---|
| 35 | try: |
|---|
| 36 | for year in years_in_group(group): |
|---|
| 37 | if year in years: |
|---|
| 38 | print 'Year %d mentionned twice in %s' % (year, years) |
|---|
| 39 | return False |
|---|
| 40 | years.add(year) |
|---|
| 41 | except: |
|---|
| 42 | print 'Could not parse copyright years %s' % years |
|---|
| 43 | return False |
|---|
| 44 | return years |
|---|
| 45 | |
|---|
| 46 | def check_file(filepath): |
|---|
| 47 | requires_copyright = False |
|---|
| 48 | |
|---|
| 49 | basename = os.path.basename(filepath) |
|---|
| 50 | if '.' in basename: |
|---|
| 51 | extension = basename.rsplit('.', 1)[1] |
|---|
| 52 | if extension in ('h', 'c', 'S', 'py', 'sh'): |
|---|
| 53 | requires_copyright = True |
|---|
| 54 | |
|---|
| 55 | contents = file(filepath).read() |
|---|
| 56 | if requires_copyright and 'Copyright' not in contents: |
|---|
| 57 | print 'No copyright notice found in %s' % filepath |
|---|
| 58 | return False |
|---|
| 59 | |
|---|
| 60 | m = COPYRIGHT_RE.search(contents) |
|---|
| 61 | if not m: |
|---|
| 62 | return True |
|---|
| 63 | |
|---|
| 64 | if m.group(1) == 'C': |
|---|
| 65 | print 'Copyright notice in %s uses "(C)"' % filepath |
|---|
| 66 | print 'Correct notation is "(c)"' |
|---|
| 67 | print m.group(0) |
|---|
| 68 | return False |
|---|
| 69 | |
|---|
| 70 | years = parse_years(m.group(2)) |
|---|
| 71 | if not years: |
|---|
| 72 | return False |
|---|
| 73 | if current_year not in years: |
|---|
| 74 | print '%d not present in copyright notice of %s:' % \ |
|---|
| 75 | (current_year, filepath) |
|---|
| 76 | print m.group(0) |
|---|
| 77 | return False |
|---|
| 78 | return True |
|---|
| 79 | |
|---|
| 80 | ok = True |
|---|
| 81 | |
|---|
| 82 | for line in sys.stdin: |
|---|
| 83 | if line.startswith('+++ '): |
|---|
| 84 | filepath = line.split()[1] |
|---|
| 85 | |
|---|
| 86 | # Skip deletions |
|---|
| 87 | if filepath == '/dev/null': |
|---|
| 88 | continue |
|---|
| 89 | |
|---|
| 90 | if filepath[:2] in ('a/', 'b/'): |
|---|
| 91 | filepath = filepath[2:] |
|---|
| 92 | |
|---|
| 93 | if not check_file(filepath): |
|---|
| 94 | ok = False |
|---|
| 95 | |
|---|
| 96 | if ok: |
|---|
| 97 | sys.exit(0) |
|---|
| 98 | else: |
|---|
| 99 | os.system('hg tip --template {desc} >commit.msg') |
|---|
| 100 | print 'Commit message saved in commit.msg' |
|---|
| 101 | sys.exit(1) |
|---|