mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: rfr: Add address book
Add an address book that lets devs use short hand for specifying --to and --cc targets. For example, if a dev wants to CC the MISRA list this can be used: $ ./scripts/rfr -e --cc misra ... The address book also lets devs add their own names/email addresses since this makes it convenient to CC individual people. For example: $ ./scripts/rfr -e --cc alex ... Several new arguments were added to support the address book. There are arguments to list/search the address book, ignore the address book, and to prevent nvgpu-core from being added to the to address by default. For more details see the help page. To use an address book there's several options: place one at ~/.rfr-addrbook Export an RFR_ADDRBOOK environment variable pointing to the address book, or specify one with the `-a' option. The address book contents is simple. All empty lines and lines beginning with '#' are ignored. The remaining lines are split by '|' and the first half of the line is considered a nickname and the latter half the address. An example: alex | alex waterman <alexw@nvidia.com> This will let you specify `--to alex' instead of the full email address. This is especially useful for mailing lists. Lastly there is more documentation located at: https://confluence.nvidia.com/display/TGS/NVGPU+Request+For+Review [Bump version to 1.1.0] Change-Id: Iac7ec05ae28d7e888d2bf36bd23574ec49eb04dc Signed-off-by: Alex Waterman <alexw@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1983695 Reviewed-by: Rohit Khanna <rokhanna@nvidia.com>
This commit is contained in:
committed by
Rohit Khanna
parent
164e387940
commit
dd4c60aeb5
59
scripts/rfr
59
scripts/rfr
@@ -33,10 +33,14 @@ import smtplib
|
|||||||
|
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
VERSION = '1.0.3'
|
from rfr_addrbook import rfr_ab_load
|
||||||
|
from rfr_addrbook import rfr_ab_query
|
||||||
|
from rfr_addrbook import rfr_ab_lookup
|
||||||
|
|
||||||
|
VERSION = '1.1.0'
|
||||||
|
|
||||||
# Default email address.
|
# Default email address.
|
||||||
to_addr = 'SW-Mobile-nvgpu-core <SW-Mobile-nvgpu-core@exchange.nvidia.com>'
|
to_addr = 'sw-mobile-nvgpu-core <sw-mobile-nvgpu-core@exchange.nvidia.com>'
|
||||||
|
|
||||||
# Gerrit commit URL formats. These are regular expressions to match the
|
# Gerrit commit URL formats. These are regular expressions to match the
|
||||||
# incoming URLs against.
|
# incoming URLs against.
|
||||||
@@ -63,7 +67,7 @@ def parse_args():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
ep="""This program will format commit messages into something that can be
|
ep="""This program will format commit messages into something that can be
|
||||||
sent to the nvgpu mailing list for review
|
sent to the nvgpu mailing list for review.
|
||||||
"""
|
"""
|
||||||
help_msg="""Git or gerrit commits to describe. Can be either a git or gerrit
|
help_msg="""Git or gerrit commits to describe. Can be either a git or gerrit
|
||||||
commit ID. If the ID starts with a 'I' then it will be treated as a gerrit ID.
|
commit ID. If the ID starts with a 'I' then it will be treated as a gerrit ID.
|
||||||
@@ -93,6 +97,18 @@ Otherwise it's treated as a git commit ID.
|
|||||||
'Can be repeated (-c a -c b).')
|
'Can be repeated (-c a -c b).')
|
||||||
parser.add_argument('-F', '--file', action='store', default=None,
|
parser.add_argument('-F', '--file', action='store', default=None,
|
||||||
help='File with commits, one per line')
|
help='File with commits, one per line')
|
||||||
|
parser.add_argument('-q', '--query-addrbook', action='store', default=None,
|
||||||
|
nargs='?', const='.', metavar='regex',
|
||||||
|
help='Regex query for address book')
|
||||||
|
parser.add_argument('-a', '--addrbook', action='store', default=None,
|
||||||
|
metavar='addrbook',
|
||||||
|
help='Specify location to look for address book')
|
||||||
|
parser.add_argument('-I', '--ignore-addrbook', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Ignore address book lookup. Default is false.')
|
||||||
|
parser.add_argument('--no-default-addr', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Do not use the default address.')
|
||||||
|
|
||||||
# Positionals: the gerrit URLs.
|
# Positionals: the gerrit URLs.
|
||||||
parser.add_argument('commits', metavar='Commit-IDs',
|
parser.add_argument('commits', metavar='Commit-IDs',
|
||||||
@@ -297,9 +313,12 @@ def format_msg_comment(subject, to_addrs, cc_addrs):
|
|||||||
knows who they are sending an email to.
|
knows who they are sending an email to.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
msg_comment = """# Lines that begin with a '#' will be ignored in the final
|
msg_comment = """# RFR commit editor
|
||||||
# message. This includes white space so ' # blah', for example,
|
#
|
||||||
# will _not_ be ignored.
|
# Lines that begin with a '#' are comments and will be ignored in the final
|
||||||
|
# message. '#' characters that appear else where in the line will be ignored.
|
||||||
|
# White space is not stripped from lines so, for example, ' # blah' will not
|
||||||
|
# be ignored!
|
||||||
#
|
#
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -324,8 +343,21 @@ def email_commits(commits_info, sender, subject, args):
|
|||||||
Directly email commits to the nvgpu-core mailing list for review!
|
Directly email commits to the nvgpu-core mailing list for review!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
to_addrs = [to_addr] + args.to
|
# Lets you drop nvgpu-core from the to-addr if you desire. You can then
|
||||||
cc_addrs = args.cc
|
# add it back to CC if you wish.
|
||||||
|
if not args.no_default_addr:
|
||||||
|
args.to.append(to_addr)
|
||||||
|
|
||||||
|
to_addrs = rfr_ab_lookup(args.to, args.ignore_addrbook)
|
||||||
|
if to_addrs == None:
|
||||||
|
print('Junk address: aborting!')
|
||||||
|
print('Use `-I\' to ignore.')
|
||||||
|
return
|
||||||
|
cc_addrs = rfr_ab_lookup(args.cc, args.ignore_addrbook)
|
||||||
|
if cc_addrs == None:
|
||||||
|
print('Junk address: aborting!')
|
||||||
|
print('Use `-I\' to ignore.')
|
||||||
|
return
|
||||||
|
|
||||||
if args.no_msg:
|
if args.no_msg:
|
||||||
args.msg = None
|
args.msg = None
|
||||||
@@ -380,6 +412,17 @@ def main():
|
|||||||
print('Version: %s' % VERSION)
|
print('Version: %s' % VERSION)
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
if arg_parser.addrbook:
|
||||||
|
success = rfr_ab_load(arg_parser.addrbook)
|
||||||
|
if not success:
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
rfr_ab_load(None)
|
||||||
|
|
||||||
|
if arg_parser.query_addrbook:
|
||||||
|
rfr_ab_query(arg_parser.query_addrbook)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
if arg_parser.file:
|
if arg_parser.file:
|
||||||
filp = open(arg_parser.file, 'r')
|
filp = open(arg_parser.file, 'r')
|
||||||
|
|
||||||
|
|||||||
191
scripts/rfr_addrbook.py
Normal file
191
scripts/rfr_addrbook.py
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
# Copyright (c) 2019, NVIDIA CORPORATION. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Nvgpu address book. Entries in here let us do translations from human readable
|
||||||
|
# email names/aliases to the real NV email addresses.
|
||||||
|
#
|
||||||
|
# This is structured as a dictionary with keys as human readable names which
|
||||||
|
# point to the real email address.
|
||||||
|
#
|
||||||
|
# It's fine to have multiple keys pointing to the same thing. Aliases are nice.
|
||||||
|
#
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
# The table itself is private. Use the methods below to do AB lookups, etc.
|
||||||
|
#
|
||||||
|
# Also please note: the table should be all lower case! This makes it easy to
|
||||||
|
# just lowercase all incoming queries so that we can do case insensitive
|
||||||
|
# lookups.
|
||||||
|
__rfr_address_book = { }
|
||||||
|
|
||||||
|
def __rfr_parse_addrbook(ab):
|
||||||
|
"""
|
||||||
|
Parse an address book. Ignore empty lines and lines that begin with '#'.
|
||||||
|
All other lines are split by the '|' character into 2 strings - a key and
|
||||||
|
a value. The key is a nickname and the value is the real address. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
alex | Alex Waterman <alexw@nvidia.com>
|
||||||
|
|
||||||
|
Note: if there's a syntax error detected an error is always printed. Unlike
|
||||||
|
if there's missing files in which errors may be silent.
|
||||||
|
|
||||||
|
Returns True/False for pass/fail.
|
||||||
|
"""
|
||||||
|
|
||||||
|
global __rfr_address_book
|
||||||
|
|
||||||
|
tmp_ab = { }
|
||||||
|
line_nr = 0
|
||||||
|
|
||||||
|
for line in ab.readlines():
|
||||||
|
line_nr += 1
|
||||||
|
l = line.strip()
|
||||||
|
|
||||||
|
if len(l) == 0 or l[0] == '#':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Only allow at most 1 split.
|
||||||
|
kv = l.split('|', 1)
|
||||||
|
|
||||||
|
if len(kv) != 2:
|
||||||
|
print('Error: unable to parse address book. Invalid line:')
|
||||||
|
print(' > \'%s\' @ line: %d' % (line, line_nr))
|
||||||
|
return False
|
||||||
|
|
||||||
|
tmp_ab[kv[0].strip().lower()] = kv[1].strip().lower()
|
||||||
|
|
||||||
|
__rfr_address_book = tmp_ab
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __rfr_load_ab(path, silent=False):
|
||||||
|
"""
|
||||||
|
Load the passed address book and print errors if silent is False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
success = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(path) as ab:
|
||||||
|
if not __rfr_parse_addrbook(ab):
|
||||||
|
success = False
|
||||||
|
except Exception as err:
|
||||||
|
success = False
|
||||||
|
if not silent:
|
||||||
|
print 'Error: %s' % err
|
||||||
|
|
||||||
|
# It's not a very helpful error message I suppose. Eh. We will get more
|
||||||
|
# detail from the __rfr_parse_addrbook() call itself.
|
||||||
|
if not success and not silent:
|
||||||
|
print('Failed to parse AB: %s' % path)
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
|
def rfr_ab_load(ab_path):
|
||||||
|
"""
|
||||||
|
Attempt to load an address book.
|
||||||
|
|
||||||
|
If ab_path is None then look for the book at the environment variable
|
||||||
|
RFR_ADDRBOOK. If that's not found or fails to load then fall back to trying
|
||||||
|
~/.rfr-addrbook. If that doesn't work just silently return True and we will
|
||||||
|
have an empty address book.
|
||||||
|
|
||||||
|
If ab_path is not None then try to load the addr book from the passed path
|
||||||
|
and if there's an error print an error message. This will return the result
|
||||||
|
of the AB load.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if ab_path:
|
||||||
|
return __rfr_load_ab(ab_path)
|
||||||
|
|
||||||
|
# Ok, if we are here, do the whole env logic thing.
|
||||||
|
ab_path = os.getenv('RFR_ADDRBOOK')
|
||||||
|
if ab_path:
|
||||||
|
success = __rfr_load_ab(ab_path, silent=True)
|
||||||
|
if success:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Otherwise... Try ~/.rfr-addrbook
|
||||||
|
ab_path = os.getenv('HOME') + '/.rfr-addrbook'
|
||||||
|
if ab_path:
|
||||||
|
success = __rfr_load_ab(ab_path, silent=True)
|
||||||
|
if success:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Well, it all failed. But we don't care.
|
||||||
|
return True
|
||||||
|
|
||||||
|
def rfr_ab_query(regex):
|
||||||
|
"""
|
||||||
|
Print a list of keys that match the passed regex string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
matches = [ ]
|
||||||
|
|
||||||
|
p = re.compile(regex, re.IGNORECASE)
|
||||||
|
|
||||||
|
for k in __rfr_address_book.keys():
|
||||||
|
m = p.search(k)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
|
||||||
|
matches.append(k)
|
||||||
|
|
||||||
|
print('Address book query: %s' % regex)
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
print('> No matches')
|
||||||
|
return
|
||||||
|
|
||||||
|
for addr in sorted(matches):
|
||||||
|
print('> %-15s | %s' % (addr, __rfr_address_book[addr]))
|
||||||
|
|
||||||
|
def rfr_ab_lookup_single(addr):
|
||||||
|
"""
|
||||||
|
Exact lookup into the address book but if the addr isn't found in the keys
|
||||||
|
then also check the values. If the addr is not found in the values then
|
||||||
|
return None.
|
||||||
|
|
||||||
|
This lets the rfr script either ignore the AB lookup failure or bail out.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If there's no address book, just pass the addr through.
|
||||||
|
if len(__rfr_address_book.keys()) == 0:
|
||||||
|
return addr
|
||||||
|
|
||||||
|
lc_addr = addr.lower()
|
||||||
|
|
||||||
|
if lc_addr in __rfr_address_book:
|
||||||
|
return __rfr_address_book[lc_addr]
|
||||||
|
|
||||||
|
if lc_addr in __rfr_address_book.values():
|
||||||
|
# Return the orignal, un-lowercased.
|
||||||
|
return addr
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def rfr_ab_lookup(addrs, ignore_missing):
|
||||||
|
"""
|
||||||
|
Take a list of addresses and look them up in the address book. Return a new
|
||||||
|
list which contains the results of the lookups.
|
||||||
|
|
||||||
|
If ignore_missing is True then if there's an address book lookup failure
|
||||||
|
just ignore it and pass the address through to the new list. If False then
|
||||||
|
fail and bail (return None).
|
||||||
|
"""
|
||||||
|
|
||||||
|
lookups = [ ]
|
||||||
|
|
||||||
|
for a in addrs:
|
||||||
|
lookup = rfr_ab_lookup_single(a)
|
||||||
|
if not lookup and not ignore_missing:
|
||||||
|
print('Unknown address: %s' % a)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if lookup:
|
||||||
|
lookups.append(lookup)
|
||||||
|
else:
|
||||||
|
lookups.append(a)
|
||||||
|
|
||||||
|
return lookups
|
||||||
Reference in New Issue
Block a user