1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#***********************************************************************
# This file is part of OpenMolcas. *
# *
# OpenMolcas is free software; you can redistribute it and/or modify *
# it under the terms of the GNU Lesser General Public License, v. 2.1. *
# OpenMolcas is distributed in the hope that it will be useful, but it *
# is provided "as is" and without any express or implied warranties. *
# For more details see the full text of the license in the file *
# LICENSE or in <http://www.gnu.org/licenses/>. *
# *
# Copyright (C) 2017,2020,2024, Ignacio Fdez. Galván *
#***********************************************************************
'''
This script checks that the OpenMolcas header exist and that the copyright
has the right format.
'''
import sys
import re
import argparse
from codecs import getwriter
from locale import getpreferredencoding
from io import open
from os.path import isfile, join, relpath, splitext
from os import walk
try:
from colorama import init, Fore, Back, Style
except ImportError:
def init(*args, **kwargs):
pass
class Dummy(object):
pass
Fore = Dummy()
Fore.RED = ''
Fore.BLUE = ''
Back = Dummy()
Back.RED = ''
Style = Dummy()
Style.RESET_ALL = ''
# Define command-line arguments
parser = argparse.ArgumentParser(formatter_class=lambda prog: argparse.HelpFormatter(prog))
parser.add_argument('-p', '--print', help='print copyright information found in files', action='store_true')
parser.add_argument('-r', '--report', help='check and report some formatting problems', action='store_true')
parser.add_argument('-n', '--no-copyright', help='report files with no copyright information', action='store_true')
parser.add_argument('-a', '--authors', help='list all authors with their contributed files', action='store_true')
parser.add_argument('root', help='filename or tree to check')
args = vars(parser.parse_args())
if (not (args['print'] or args['report'] or args['no_copyright'] or args['authors'])):
parser.error('At least one of the optional arguments is required')
# Use colors in terminal, not if output is redirected to file
if sys.stdout.isatty():
init()
else:
init(strip=True)
files = []
if (isfile(args['root'])):
files.append(args['root'])
else:
for dname, dirs, fnames in walk(args['root']):
for fname in fnames:
files.append(join(dname, fname))
rc = 0
authors = {}
for filename in sorted(files):
copyright = []
if (isfile(filename)):
if (filename == args['root']):
relfile = filename
else:
relfile = relpath(filename, args['root'])
with open(filename, 'r', encoding='utf-8') as f:
header = False
copy = False
blank = False
blank_error = False
try:
for l in f:
prev_blank = blank
blank = (l.find(70*' ') >= 0)
if (l.find('This file is part of OpenMolcas') > 0):
header = True
elif (header and re.search(r'copyright', l, re.IGNORECASE)):
copy = True
blank_error = not prev_blank
elif (header and (l.find(70*'*') >= 0)):
break
if (copy):
match = re.match(r'^.\s*(Copyright \(C\))?\s*(([\d,-]*?),)?\s+(.*?)\s*\*$', l)
if (match):
year = match.group(3)
name = match.group(4)
if (year is None):
year = '(?)'
copyright.append([year, name])
aname = re.sub(r'\s*\(.*', '', name)
if (aname in authors):
authors[aname].append(relfile)
else:
authors[aname] = [relfile]
if (((not match) or blank_error) and args['report']):
print('{0}*** {1}: Format error ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
print(l)
rc = 1
if (not header and args['report']):
if (splitext(filename)[1] in ['.f', '.F', '.f90', '.F90', '.fh', '.c', '.h', '.cmake', '.py', '.ascii', '.tbl', '.vim']):
print('{0}*** {1}: No header ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
rc = 1
except UnicodeDecodeError:
if (args['report']):
if (splitext(filename)[1] not in ['.png', '.jpg']):
print('{0}*** Problem decoding {1} ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
rc = 1
# Write all copyrights
if (args['print']):
fmt = '© {0}{{0}}{1}, {2}{{1}}{1}'.format(Fore.RED, Style.RESET_ALL, Fore.BLUE)
if (len(copyright) > 0):
print('··· {0} ···'.format(relfile))
for item in copyright:
print(fmt.format(item[0],item[1]))
# Find issues
if (args['no_copyright']):
if (len(copyright) == 0):
print('{0}*** {1}: No copyright ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
if (args['report']):
names = set([])
for item in copyright:
if (re.search('[\d,]', item[1])):
print('{0}*** {1}: Name error? ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
print(item[1])
rc = 1
if (item[1] in names):
print('{0}*** {1}: Duplicate name ***{2}'.format(Back.RED, relfile, Style.RESET_ALL))
print(item[1])
rc = 1
else:
names.add(item[1])
# Print authors and files
if (args['authors']):
for k in sorted(authors.keys()):
print('\n==================')
print(k)
print('------------------')
for f in (authors[k]):
print(f)
sys.exit(rc)
|