blob: 9c93324bc9096fb773e1508adae0b76b76518158 [file]
#! /usr/bin/env python3
# Add a new Write-After account to MAINTAINERS.yml
# Copyright (C) 2026 Free Software Foundation, Inc.
#
# This file is part of GCC.
#
# GCC 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; either version 3, or (at your option)
# any later version.
#
# GCC 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 GCC; see the file COPYING. If not, write to
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
import os
import pwd
import re
import sys
import unidecode
import yaml
from optparse import OptionParser
import maintainer_utils as maintutils
def unilower(txt):
"""return a lower-case version of txt, mapping accented characters
onto their ASCII near equivalents."""
return unidecode.unidecode(txt).lower()
def get_surname(name):
parts = name.split()
surname = parts[-1]
if surname.startswith("d'"):
surname = surname[2:]
return surname
def ask(prompt, default, required=True):
while True:
print(f"{prompt} [{default if default else '(no default)'}]: ", end="",
flush=True)
result = sys.stdin.readline().strip()
if result != "":
return result
if default or not required:
return default
def email_valid(e):
template = r"^[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}$"
if re.match(template, e):
return True
return False
def getuserdata():
user = pwd.getpwuid(os.getuid())
# Make an initial guess that the name and GCC account will match
# the local account name.
# GECOS fields sometime contain a comma-separated list; in that case
# we only want the first component (the user's name)
print ("Please enter the details of your Sourceware account.")
print ("Some details have been guessed, based on your local account,")
print ("but you can adjust as required.")
newuser = {
'sn': "",
'cn': "",
'email': [],
'roles': [],
'account': "",
}
newuser['cn'] = ask("Your name", user.pw_gecos.split(",", 1)[0])
newuser['sn'] = ask("Your surname (only used for sorting entries)",
get_surname(newuser['cn']))
account = ask("Your sourceware account", user.pw_name)
while True:
e = ask("Primary email address", None)
if email_valid(e):
break
print ("That address does not look valid.")
newuser['email'].append(e)
while (e := ask("Additional email (return to stop)", None,
required=False)):
if email_valid(e):
newuser['email'].append(e)
else:
print ("That address does not look valid. Ignored.")
gcc_email = account + "@gcc.gnu.org"
if not gcc_email in newuser['email']:
print(f"Appending {gcc_email} to the list of email addresses")
newuser['email'].append(gcc_email)
newuser['roles'] = list()
newuser['roles'].append('WriteAfter')
newuser['account'] = account
print("If you are using a Developer Certificate of Origin (DCO)")
print("you can add appropriate email addresses here")
while (e := ask("DCO email (return to stop)", None, required=False)):
if email_valid(e):
newuser['roles'].append({'DCO': e})
else:
print ("That address does not look valid. Ignored.")
return newuser
def main():
optp = OptionParser(usage="Usage: %prog [<options>] <maintainers.yml>")
optp.add_option("-o", "--output", metavar="FILE",
default=None, dest="outfilename",
help="Write to FILE instead of updating original file")
opts, args = optp.parse_args()
if len(args) != 1:
optp.print_help()
sys.exit(1)
data = maintutils.load(args[0])
# Check the data before we try to update it.
maintutils.validate(data)
newuser = getuserdata()
if not newuser:
return 0
existing = [u for u in filter(lambda x: (x.get('account')
== newuser['account']),
data['users'])]
if len(existing):
print(f"Sorry that account name ({newuser['account']}) has already been used.")
print("Note, this script can only be used to add new accounts.")
return 1
data['users'].append (newuser)
data['users'] = sorted(data['users'],
key = lambda k: (unilower(k['sn']),
unilower(k['cn'])))
if opts.outfilename and opts.outfilename != '-':
outfd = open (opts.outfilename, "w", encoding="utf-8")
elif opts.outfilename and opts.outfilename == '-':
outfd = sys.stdout
else:
outfd = open (args[0], "w", encoding="utf-8")
yaml.dump (data, outfd, allow_unicode = True, sort_keys = False)
return 0
if __name__ == "__main__":
sys.exit (main())