blob: 690fdbfb80200f79f4cc0c323a023fb7e517020d [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 yaml
from optparse import OptionParser
import maintainer_utils as maintutils
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)
forgeid = ask("Your sourceware forge ID (if you have one)", None,
required=False)
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
if forgeid:
newuser['forgeid'] = forgeid
print("If you are using a Developer Certificate of Origin (DCO)")
print("you can add appropriate email addresses here")
dco = []
inactive_emails = []
while (e := ask("DCO email (return to stop)", None, required=False)):
if email_valid(e):
dco.append(e)
if e not in newuser['email']:
print(f"<{e}> not mentioned in the above list of emails.")
print("Adding it to inactive_emails list.")
inactive_emails.append(e)
else:
print ("That address does not look valid. Ignored.")
if len(inactive_emails) > 0:
newuser['inactive_email'] = inactive_emails
if len(dco) > 0:
newuser['DCO'] = dco
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)
if opts.outfilename and opts.outfilename == '-':
maintutils.store(data)
else:
maintutils.store(
data,
file=opts.outfilename if opts.outfilename else args[0])
return 0
if __name__ == "__main__":
sys.exit (main())