diff options
Diffstat (limited to 'import-layers/yocto-poky/scripts/contrib/oe-build-perf-report-email.py')
-rwxr-xr-x | import-layers/yocto-poky/scripts/contrib/oe-build-perf-report-email.py | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/import-layers/yocto-poky/scripts/contrib/oe-build-perf-report-email.py b/import-layers/yocto-poky/scripts/contrib/oe-build-perf-report-email.py deleted file mode 100755 index 913847bbe..000000000 --- a/import-layers/yocto-poky/scripts/contrib/oe-build-perf-report-email.py +++ /dev/null @@ -1,282 +0,0 @@ -#!/usr/bin/python3 -# -# Send build performance test report emails -# -# Copyright (c) 2017, Intel Corporation. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2, as published by the Free Software Foundation. -# -# This program is distributed in the hope 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. -# -import argparse -import base64 -import logging -import os -import pwd -import re -import shutil -import smtplib -import socket -import subprocess -import sys -import tempfile -from email.mime.image import MIMEImage -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText - - -# Setup logging -logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") -log = logging.getLogger('oe-build-perf-report') - - -# Find js scaper script -SCRAPE_JS = os.path.join(os.path.dirname(__file__), '..', 'lib', 'build_perf', - 'scrape-html-report.js') -if not os.path.isfile(SCRAPE_JS): - log.error("Unableto find oe-build-perf-report-scrape.js") - sys.exit(1) - - -class ReportError(Exception): - """Local errors""" - pass - - -def check_utils(): - """Check that all needed utils are installed in the system""" - missing = [] - for cmd in ('phantomjs', 'optipng'): - if not shutil.which(cmd): - missing.append(cmd) - if missing: - log.error("The following tools are missing: %s", ' '.join(missing)) - sys.exit(1) - - -def parse_args(argv): - """Parse command line arguments""" - description = """Email build perf test report""" - parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description=description) - - parser.add_argument('--debug', '-d', action='store_true', - help="Verbose logging") - parser.add_argument('--quiet', '-q', action='store_true', - help="Only print errors") - parser.add_argument('--to', action='append', - help="Recipients of the email") - parser.add_argument('--cc', action='append', - help="Carbon copy recipients of the email") - parser.add_argument('--bcc', action='append', - help="Blind carbon copy recipients of the email") - parser.add_argument('--subject', default="Yocto build perf test report", - help="Email subject") - parser.add_argument('--outdir', '-o', - help="Store files in OUTDIR. Can be used to preserve " - "the email parts") - parser.add_argument('--text', - help="Plain text message") - parser.add_argument('--html', - help="HTML peport generated by oe-build-perf-report") - parser.add_argument('--phantomjs-args', action='append', - help="Extra command line arguments passed to PhantomJS") - - args = parser.parse_args(argv) - - if not args.html and not args.text: - parser.error("Please specify --html and/or --text") - - return args - - -def decode_png(infile, outfile): - """Parse/decode/optimize png data from a html element""" - with open(infile) as f: - raw_data = f.read() - - # Grab raw base64 data - b64_data = re.sub('^.*href="data:image/png;base64,', '', raw_data, 1) - b64_data = re.sub('">.+$', '', b64_data, 1) - - # Replace file with proper decoded png - with open(outfile, 'wb') as f: - f.write(base64.b64decode(b64_data)) - - subprocess.check_output(['optipng', outfile], stderr=subprocess.STDOUT) - - -def mangle_html_report(infile, outfile, pngs): - """Mangle html file into a email compatible format""" - paste = True - png_dir = os.path.dirname(outfile) - with open(infile) as f_in: - with open(outfile, 'w') as f_out: - for line in f_in.readlines(): - stripped = line.strip() - # Strip out scripts - if stripped == '<!--START-OF-SCRIPTS-->': - paste = False - elif stripped == '<!--END-OF-SCRIPTS-->': - paste = True - elif paste: - if re.match('^.+href="data:image/png;base64', stripped): - # Strip out encoded pngs (as they're huge in size) - continue - elif 'www.gstatic.com' in stripped: - # HACK: drop references to external static pages - continue - - # Replace charts with <img> elements - match = re.match('<div id="(?P<id>\w+)"', stripped) - if match and match.group('id') in pngs: - f_out.write('<img src="cid:{}"\n'.format(match.group('id'))) - else: - f_out.write(line) - - -def scrape_html_report(report, outdir, phantomjs_extra_args=None): - """Scrape html report into a format sendable by email""" - tmpdir = tempfile.mkdtemp(dir='.') - log.debug("Using tmpdir %s for phantomjs output", tmpdir) - - if not os.path.isdir(outdir): - os.mkdir(outdir) - if os.path.splitext(report)[1] not in ('.html', '.htm'): - raise ReportError("Invalid file extension for report, needs to be " - "'.html' or '.htm'") - - try: - log.info("Scraping HTML report with PhangomJS") - extra_args = phantomjs_extra_args if phantomjs_extra_args else [] - subprocess.check_output(['phantomjs', '--debug=true'] + extra_args + - [SCRAPE_JS, report, tmpdir], - stderr=subprocess.STDOUT) - - pngs = [] - images = [] - for fname in os.listdir(tmpdir): - base, ext = os.path.splitext(fname) - if ext == '.png': - log.debug("Decoding %s", fname) - decode_png(os.path.join(tmpdir, fname), - os.path.join(outdir, fname)) - pngs.append(base) - images.append(fname) - elif ext in ('.html', '.htm'): - report_file = fname - else: - log.warning("Unknown file extension: '%s'", ext) - #shutil.move(os.path.join(tmpdir, fname), outdir) - - log.debug("Mangling html report file %s", report_file) - mangle_html_report(os.path.join(tmpdir, report_file), - os.path.join(outdir, report_file), pngs) - return (os.path.join(outdir, report_file), - [os.path.join(outdir, i) for i in images]) - finally: - shutil.rmtree(tmpdir) - -def send_email(text_fn, html_fn, image_fns, subject, recipients, copy=[], - blind_copy=[]): - """Send email""" - # Generate email message - text_msg = html_msg = None - if text_fn: - with open(text_fn) as f: - text_msg = MIMEText("Yocto build performance test report.\n" + - f.read(), 'plain') - if html_fn: - html_msg = msg = MIMEMultipart('related') - with open(html_fn) as f: - html_msg.attach(MIMEText(f.read(), 'html')) - for img_fn in image_fns: - # Expect that content id is same as the filename - cid = os.path.splitext(os.path.basename(img_fn))[0] - with open(img_fn, 'rb') as f: - image_msg = MIMEImage(f.read()) - image_msg['Content-ID'] = '<{}>'.format(cid) - html_msg.attach(image_msg) - - if text_msg and html_msg: - msg = MIMEMultipart('alternative') - msg.attach(text_msg) - msg.attach(html_msg) - elif text_msg: - msg = text_msg - elif html_msg: - msg = html_msg - else: - raise ReportError("Neither plain text nor html body specified") - - pw_data = pwd.getpwuid(os.getuid()) - full_name = pw_data.pw_gecos.split(',')[0] - email = os.environ.get('EMAIL', - '{}@{}'.format(pw_data.pw_name, socket.getfqdn())) - msg['From'] = "{} <{}>".format(full_name, email) - msg['To'] = ', '.join(recipients) - if copy: - msg['Cc'] = ', '.join(copy) - if blind_copy: - msg['Bcc'] = ', '.join(blind_copy) - msg['Subject'] = subject - - # Send email - with smtplib.SMTP('localhost') as smtp: - smtp.send_message(msg) - - -def main(argv=None): - """Script entry point""" - args = parse_args(argv) - if args.quiet: - log.setLevel(logging.ERROR) - if args.debug: - log.setLevel(logging.DEBUG) - - check_utils() - - if args.outdir: - outdir = args.outdir - if not os.path.exists(outdir): - os.mkdir(outdir) - else: - outdir = tempfile.mkdtemp(dir='.') - - try: - log.debug("Storing email parts in %s", outdir) - html_report = images = None - if args.html: - html_report, images = scrape_html_report(args.html, outdir, - args.phantomjs_args) - - if args.to: - log.info("Sending email to %s", ', '.join(args.to)) - if args.cc: - log.info("Copying to %s", ', '.join(args.cc)) - if args.bcc: - log.info("Blind copying to %s", ', '.join(args.bcc)) - send_email(args.text, html_report, images, args.subject, - args.to, args.cc, args.bcc) - except subprocess.CalledProcessError as err: - log.error("%s, with output:\n%s", str(err), err.output.decode()) - return 1 - except ReportError as err: - log.error(err) - return 1 - finally: - if not args.outdir: - log.debug("Wiping %s", outdir) - shutil.rmtree(outdir) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) |