Files
linux-nvgpu/scripts/rfr_addrbook.py
Alex Waterman dd4c60aeb5 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>
2019-01-16 15:38:18 -08:00

192 lines
5.2 KiB
Python

# 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