On Wed, May 26, 2021 at 7:39 PM Chris Johns <chr...@rtems.org> wrote: > > On 12/5/21 3:19 am, Alex White wrote: > > This adds the improved mailer.py script from rtems-tools. > > > > Closes #4388 > > --- > > source-builder/sb/mailer.py | 194 ++++++++++++++++++++++++++------ > > source-builder/sb/options.py | 26 ++++- > > source-builder/sb/setbuilder.py | 2 + > > 3 files changed, 189 insertions(+), 33 deletions(-) > > > > diff --git a/source-builder/sb/mailer.py b/source-builder/sb/mailer.py > > index ff25df5..aafe6d6 100644 > > --- a/source-builder/sb/mailer.py > > +++ b/source-builder/sb/mailer.py > > @@ -1,21 +1,33 @@ > > # > > # RTEMS Tools Project (http://www.rtems.org/) > > -# Copyright 2013 Chris Johns (chr...@rtems.org) > > +# Copyright 2013-2016 Chris Johns (chr...@rtems.org) > > +# Copyright (C) 2021 On-Line Applications Research Corporation (OAR) > > # All rights reserved. > > # > > # This file is part of the RTEMS Tools package in 'rtems-tools'. > > # > > -# Permission to use, copy, modify, and/or distribute this software for any > > -# purpose with or without fee is hereby granted, provided that the above > > -# copyright notice and this permission notice appear in all copies. > > +# Redistribution and use in source and binary forms, with or without > > +# modification, are permitted provided that the following conditions are > > met: > > +# > > +# 1. Redistributions of source code must retain the above copyright notice, > > +# this list of conditions and the following disclaimer. > > +# > > +# 2. Redistributions in binary form must reproduce the above copyright > > notice, > > +# this list of conditions and the following disclaimer in the documentation > > +# and/or other materials provided with the distribution. > > +# > > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > > IS" > > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > > PURPOSE > > +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE > > +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > > +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > > +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > > +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > > +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > > +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > > THE > > +# POSSIBILITY OF SUCH DAMAGE. > > # > > -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > > -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > > -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > > -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > > -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > > -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > > -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > > > > # > > # Manage emailing results or reports. > > @@ -28,18 +40,72 @@ import smtplib > > import socket > > > > from . import error > > +from . import execute > > from . import options > > from . import path > > > > +_options = { > > + '--mail' : 'Send email report or results.', > > + '--use-gitconfig': 'Use mail configuration from git config.', > > + '--mail-to' : 'Email address to send the email to.', > > + '--mail-from' : 'Email address the report is from.', > > + '--smtp-host' : 'SMTP host to send via.', > > + '--smtp-port' : 'SMTP port to send via.', > > + '--smtp-user' : 'User for SMTP authentication.', > > + '--smtp-password': 'Password for SMTP authentication.' > > +} > > + > > def append_options(opts): > > - opts['--mail'] = 'Send email report or results.' > > - opts['--smtp-host'] = 'SMTP host to send via.' > > - opts['--mail-to'] = 'Email address to send the email too.' > > - opts['--mail-from'] = 'Email address the report is from.' > > + for o in _options: > > + opts[o] = _options[o] > > + > > +def add_arguments(argsp): > > + argsp.add_argument('--mail', help = _options['--mail'], action = > > 'store_true') > > + argsp.add_argument('--use-gitconfig', help = > > _options['--use-gitconfig'], action = 'store_true') > > + no_add = ['--mail', '--use-gitconfig'] > > + for o in [opt for opt in list(_options) if opt not in no_add]: > > + argsp.add_argument(o, help = _options[o], type = str) > > > > class mail: > > def __init__(self, opts): > > self.opts = opts > > + self.gitconfig_lines = None > > + if opts.find_arg('--use-gitconfig') is not None: > > + # Read the output of `git config --list` instead of reading the > > + # .gitconfig file directly because Python 2 ConfigParser does > > not > > + # accept tabs at the beginning of lines. > > + e = execute.capture_execution() > > + exit_code, proc, output = e.open('git config --list', > > shell=True) > > + if exit_code == 0: > > + self.gitconfig_lines = output.split(os.linesep) > > + > > + def _args_are_macros(self): > > + return isinstance(self.opts, options.command_line) > > + > > + def _get_arg(self, arg): > > + if self._args_are_macros(): > > + value = self.opts.find_arg(arg) > > + if value is not None: > > + value = self.opts.find_arg(arg)[1] > > + else: > > + if arg.startswith('--'): > > + arg = arg[2:] > > + arg = arg.replace('-', '_') > > + if arg in vars(self.opts): > > + value = vars(self.opts)[arg] > > + else: > > + value = None > > + return value > > + > > + def _get_from_gitconfig(self, variable_name): > > + if self.gitconfig_lines is None: > > + return None > > + > > + for line in self.gitconfig_lines: > > + if line.startswith(variable_name): > > + ls = line.split('=') > > + if len(ls) >= 2: > > + return ls[1] > > > > def from_address(self): > > > > @@ -52,9 +118,15 @@ class mail: > > l = l[:l.index('\n')] > > return l.strip() > > > > - addr = self.opts.get_arg('--mail-from') > > + addr = self._get_arg('--mail-from') > > if addr is not None: > > - return addr[1] > > + return addr > > + addr = self._get_from_gitconfig('user.email') > > + if addr is not None: > > + name = self._get_from_gitconfig('user.name') > > + if name is not None: > > + addr = '%s <%s>' % (name, addr) > > + return addr > > mailrc = None > > if 'MAILRC' in os.environ: > > mailrc = os.environ['MAILRC'] > > @@ -63,9 +135,8 @@ class mail: > > if mailrc is not None and path.exists(mailrc): > > # set from="Joe Blow <j...@blow.org>" > > try: > > - mrc = open(mailrc, 'r') > > - lines = mrc.readlines() > > - mrc.close() > > + with open(mailrc, 'r') as mrc: > > + lines = mrc.readlines() > > except IOError as err: > > raise error.general('error reading: %s' % (mailrc)) > > for l in lines: > > @@ -76,40 +147,99 @@ class mail: > > addr = fa[fa.index('=') + 1:].replace('"', ' > > ').strip() > > if addr is not None: > > return addr > > - addr = self.opts.defaults.get_value('%{_sbgit_mail}') > > + if self._args_are_macros(): > > + addr = self.opts.defaults.get_value('%{_sbgit_mail}') > > + else: > > + raise error.general('no valid from address for mail') > > return addr > > > > def smtp_host(self): > > - host = self.opts.get_arg('--smtp-host') > > + host = self._get_arg('--smtp-host') > > if host is not None: > > - return host[1] > > - host = self.opts.defaults.get_value('%{_mail_smtp_host}') > > + return host > > + host = self._get_from_gitconfig('sendemail.smtpserver') > > + if host is not None: > > + return host > > + if self._args_are_macros(): > > + host = self.opts.defaults.get_value('%{_mail_smtp_host}') > > if host is not None: > > return host > > return 'localhost' > > > > + def smtp_port(self): > > + port = self._get_arg('--smtp-port') > > + if port is not None: > > + return port > > + port = self._get_from_gitconfig('sendemail.smtpserverport') > > + if port is not None: > > + return port > > + if self._args_are_macros(): > > + port = self.opts.defaults.get_value('%{_mail_smtp_port}') > > + return port > > + > > + def smtp_user(self): > > + user = self._get_arg('--smtp-user') > > + if user is not None: > > + return user > > + user = self._get_from_gitconfig('sendemail.smtpuser') > > + return user > > + > > + def smtp_password(self): > > + password = self._get_arg('--smtp-password') > > + if password is not None: > > + return password > > + password = self._get_from_gitconfig('sendemail.smtppass') > > + return password > > + > > def send(self, to_addr, subject, body): > > from_addr = self.from_address() > > msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % \ > > (from_addr, to_addr, subject) + body > > - if type(to_addr) is str: > > - to_addr = to_addr.split(',') > > - if type(to_addr) is not list: > > - raise error.general('invalid to_addr type') > > + port = self.smtp_port() > > + > > try: > > - s = smtplib.SMTP(self.smtp_host()) > > - s.sendmail(from_addr, to_addr, msg) > > + s = smtplib.SMTP(self.smtp_host(), port, timeout=10) > > + > > + password = self.smtp_password() > > + # If a password is provided, assume that authentication is > > required. > > + if password is not None: > > + user = self.smtp_user() > > + if user is None: > > + user = from_addr > > + s.starttls() > > + s.login(user, password) > > + > > + s.sendmail(from_addr, [to_addr], msg) > > except smtplib.SMTPException as se: > > raise error.general('sending mail: %s' % (str(se))) > > except socket.error as se: > > raise error.general('sending mail: %s' % (str(se))) > > > > + def send_file_as_body(self, to_addr, subject, name, intro = None): > > + try: > > + with open(name, 'r') as f: > > + body = f.readlines() > > + except IOError as err: > > + raise error.general('error reading mail body: %s' % (name)) > > + if intro is not None: > > + body = intro + body > > + self.send(to_addr, from_addr, body) > > What is this call for?
This function is brought over from the rtems-tools mailer.py script. It appears that it is unused both in this repo and in rtems-tools as well: $ grep -r send_file_as_body . ./rtemstoolkit/mailer.py: def send_file_as_body(self, to_addr, subject, name, intro = None): Would you like me to remove it from both? Alex > > Chris > > > + > > if __name__ == '__main__': > > import sys > > + from . import macros > > optargs = {} > > + rtdir = 'source-builder' > > + defaults = '%s/defaults.mc' % (rtdir) > > append_options(optargs) > > - opts = options.load(sys.argv, optargs = optargs, defaults = > > 'defaults.mc') > > + opts = options.command_line(base_path = '.', > > + argv = sys.argv, > > + optargs = optargs, > > + defaults = macros.macros(name = defaults, > > rtdir = rtdir), > > + command_path = '.') > > + options.load(opts) > > m = mail(opts) > > print('From: %s' % (m.from_address())) > > print('SMTP Host: %s' % (m.smtp_host())) > > - m.send(m.from_address(), 'Test mailer.py', 'This is a test') > > + if '--mail' in sys.argv: > > + m.send(m.from_address(), 'Test mailer.py', 'This is a test') > > diff --git a/source-builder/sb/options.py b/source-builder/sb/options.py > > index d6bffd0..a0f196b 100644 > > --- a/source-builder/sb/options.py > > +++ b/source-builder/sb/options.py > > @@ -517,6 +517,15 @@ class command_line: > > return None > > return self.parse_args(arg) > > > > + def find_arg(self, arg): > > + if self.optargs is None or arg not in self.optargs: > > + raise error.internal('bad arg: %s' % (arg)) > > + for a in self.args: > > + sa = a.split('=') > > + if sa[0].startswith(arg): > > + return sa > > + return None > > + > > def with_arg(self, label, default = 'not-found'): > > # the default if there is no option for without. > > result = default > > @@ -582,7 +591,22 @@ class command_line: > > self.opts['no-install'] = '1' > > > > def info(self): > > - s = ' Command Line: %s%s' % (' '.join(self.argv), os.linesep) > > + # Filter potentially sensitive mail options out. > > + filtered_args = [ > > + arg for arg in self.argv > > + if all( > > + smtp_opt not in arg > > + for smtp_opt in [ > > + '--smtp-host', > > + '--mail-to', > > + '--mail-from', > > + '--smtp-user', > > + '--smtp-password', > > + '--smtp-port' > > + ] > > + ) > > + ] > > + s = ' Command Line: %s%s' % (' '.join(filtered_args), os.linesep) > > s += ' Python: %s' % (sys.version.replace('\n', '')) > > return s > > > > diff --git a/source-builder/sb/setbuilder.py > > b/source-builder/sb/setbuilder.py > > index b0e2b23..c8c8fee 100644 > > --- a/source-builder/sb/setbuilder.py > > +++ b/source-builder/sb/setbuilder.py > > @@ -695,6 +695,8 @@ def run(): > > 'log' : '', > > 'reports': [], > > 'failure': None } > > + # Request this now to generate any errors. > > + smtp_host = mail['mail'].smtp_host() > > to_addr = opts.get_arg('--mail-to') > > if to_addr is not None: > > mail['to'] = to_addr[1] > > > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel