Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/build_config/checkAuthors.py
169674 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2011-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file checkAuthors.py
15
# @author Michael Behrisch
16
# @author Daniel Krajzewicz
17
# @date 2011-11-07
18
19
from __future__ import absolute_import
20
from __future__ import print_function
21
22
import os
23
import subprocess
24
import xml.sax
25
from optparse import OptionParser
26
27
_SOURCE_EXT = [".h", ".cpp", ".py", ".pl", ".java"]
28
29
30
class PropertyReader(xml.sax.handler.ContentHandler):
31
32
"""Reads the svn properties of files as written by svn log --xml"""
33
34
def __init__(self, outfile):
35
self._out = outfile
36
self._authors = set()
37
self._currAuthor = None
38
self._value = ""
39
self._revision = None
40
41
def startElement(self, name, attrs):
42
self._value = ""
43
if name == 'logentry':
44
self._revision = attrs['revision']
45
46
def characters(self, content):
47
self._value += content
48
49
def endElement(self, name):
50
if name == 'author':
51
self._currAuthor = realNames.get(self._value, self._value)
52
if name == "msg":
53
msg = self._value.lower()
54
if self._revision in ignoreRevisions:
55
return
56
keep = True
57
ticket = msg.find("#")
58
while ticket >= 0:
59
keep = False
60
e = ticket + 1
61
while e < len(msg) and msg[e].isdigit():
62
e += 1
63
if msg[ticket + 1:e] not in ignoreTickets:
64
keep = True
65
break
66
ticket = msg.find("#", e)
67
if not keep:
68
return
69
if self._currAuthor not in self._authors:
70
self._authors.add(self._currAuthor)
71
print("@author", self._currAuthor, file=self._out)
72
try:
73
print(msg, file=self._out)
74
except UnicodeEncodeError:
75
pass
76
if self._currAuthor not in authorFiles:
77
authorFiles[self._currAuthor] = set()
78
authorFiles[self._currAuthor].add(self._out.name)
79
if "thank" in msg:
80
try:
81
print("THANKS", " ".join(msg.splitlines()), file=self._out)
82
print("thank %s %s" % (msg, self._out.name), file=log)
83
except UnicodeEncodeError:
84
pass
85
authorFiles["thank"].add(self._out.name)
86
87
88
def checkAuthors(fullName, pattern):
89
authors = set()
90
found = False
91
for line in open(fullName):
92
if line.startswith(pattern):
93
for item in line[len(pattern):].split(","):
94
a = item.strip()
95
found = True
96
if a in realNames.values():
97
authors.add(a)
98
else:
99
print("unknown author", a, fullName, file=log)
100
if not found:
101
print("no author", fullName, file=log)
102
return authors
103
104
105
def setAuthors(fullName, removal, add, pattern):
106
if options.fix:
107
out = open(fullName + ".tmp", "w")
108
authors = []
109
for line in open(fullName):
110
if line.startswith(pattern):
111
for item in line[len(pattern):].split(","):
112
a = item.strip()
113
if a in removal:
114
print("author %s not in svn log for %s" % (
115
a, fullName), file=log)
116
authors.append(a)
117
elif authors:
118
if options.fix:
119
for a in authors:
120
print("%s %s" % (pattern, a), file=out)
121
for a in add:
122
print("%s %s" % (pattern, a), file=out)
123
out.write(line)
124
elif add:
125
print("need to add author %s to %s" %
126
(add, fullName), file=log)
127
authors = []
128
elif options.fix:
129
out.write(line)
130
if options.fix:
131
out.close()
132
os.rename(out.name, fullName)
133
134
135
ignoreRevisions = set(["12129", "12128", "11445", "10974", "9705", "9477", "9429", "9348", "8566",
136
"8439", "8000", "7728", "7533", "6958", "6589", "6537",
137
"6399", "6069", "5922", "5048", "4669", "4389", "4257", "4166",
138
"4165", "4084", "4076", "4015", "3966", "3486"])
139
ignoreTickets = set(["2", "22", "409"])
140
sumoRoot = os.path.dirname(
141
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
142
optParser = OptionParser()
143
optParser.add_option("-v", "--verbose", action="store_true",
144
default=False, help="tell me what you are doing")
145
optParser.add_option("-f", "--fix", action="store_true",
146
default=False, help="fix invalid svn properties")
147
optParser.add_option("-a", "--authors", action="store_true",
148
default=False, help="print author files")
149
optParser.add_option(
150
"-r", "--root", default=sumoRoot, help="root to start parsing at")
151
(options, args) = optParser.parse_args()
152
authorFiles = {"thank": set()}
153
realNames = {}
154
for line in open(os.path.join(sumoRoot, 'AUTHORS')):
155
entries = line.split()
156
author = ""
157
authorDone = False
158
getAccounts = False
159
for e in line.split():
160
if e[0] == "<":
161
author = author[:-1]
162
authorDone = True
163
if not authorDone:
164
author += e + " "
165
if e[-1] == ">":
166
getAccounts = True
167
if getAccounts:
168
realNames[e] = author
169
if author and author not in realNames.values():
170
realNames[author] = author
171
log = open(os.path.join(sumoRoot, 'author.log'), "w")
172
for root, dirs, files in os.walk(options.root):
173
for name in files:
174
ext = os.path.splitext(name)[1]
175
if ext in _SOURCE_EXT:
176
fullName = os.path.join(root, name)
177
print("checking authors for", fullName)
178
if ext in _SOURCE_EXT[:2]:
179
pattern = "/// @author"
180
elif ext == ".py":
181
pattern = "@author"
182
else:
183
print("cannot parse for authors", fullName, file=log)
184
continue
185
authors = checkAuthors(fullName, pattern)
186
p = subprocess.Popen(
187
["svn", "log", "--xml", fullName], stdout=subprocess.PIPE)
188
output = p.communicate()[0]
189
if p.returncode == 0:
190
if options.authors:
191
out = open(fullName + ".authors", "w")
192
else:
193
out = open(os.devnull, "w")
194
pr = PropertyReader(out)
195
xml.sax.parseString(output, pr)
196
out.close()
197
setAuthors(
198
fullName, authors - pr._authors, pr._authors - authors, pattern)
199
for ignoreDir in ['.svn', 'foreign', 'contributed', 'foxtools']:
200
if ignoreDir in dirs:
201
dirs.remove(ignoreDir)
202
print(authorFiles, file=log)
203
log.close()
204
205