Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/98438/?format=api
https://patches.dpdk.org/api/patches/98438/?format=api", "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210909134808.1585777-3-mdr@ashroe.eu/", "project": { "id": 1, "url": "https://patches.dpdk.org/api/projects/1/?format=api", "name": "DPDK", "link_name": "dpdk", "list_id": "dev.dpdk.org", "list_email": "dev@dpdk.org", "web_url": "http://core.dpdk.org", "scm_url": "git://dpdk.org/dpdk", "webscm_url": "http://git.dpdk.org/dpdk", "list_archive_url": "https://inbox.dpdk.org/dev", "list_archive_url_format": "https://inbox.dpdk.org/dev/{}", "commit_url_format": "" }, "msgid": "<20210909134808.1585777-3-mdr@ashroe.eu>", "list_archive_url": "https://inbox.dpdk.org/dev/20210909134808.1585777-3-mdr@ashroe.eu", "date": "2021-09-09T13:48:06", "name": "[v13,2/4] devtools: script to send notifications of expired symbols", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "881bbea5c777b65fb8d0b993f841c5fcb1605090", "submitter": { "id": 1310, "url": "https://patches.dpdk.org/api/people/1310/?format=api", "name": "Ray Kinsella", "email": "mdr@ashroe.eu" }, "delegate": { "id": 1, "url": "https://patches.dpdk.org/api/users/1/?format=api", "username": "tmonjalo", "first_name": "Thomas", "last_name": "Monjalon", "email": "thomas@monjalon.net" }, "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210909134808.1585777-3-mdr@ashroe.eu/mbox/", "series": [ { "id": 18795, "url": "https://patches.dpdk.org/api/series/18795/?format=api", "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=18795", "date": "2021-09-09T13:48:04", "name": "devtools: scripts to count and track symbols", "version": 13, "mbox": "https://patches.dpdk.org/series/18795/mbox/" } ], "comments": "https://patches.dpdk.org/api/patches/98438/comments/", "check": "success", "checks": "https://patches.dpdk.org/api/patches/98438/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<dev-bounces@dpdk.org>", "X-Original-To": "patchwork@inbox.dpdk.org", "Delivered-To": "patchwork@inbox.dpdk.org", "Received": [ "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 56E49A0547;\n\tThu, 9 Sep 2021 15:50:41 +0200 (CEST)", "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3E49641149;\n\tThu, 9 Sep 2021 15:50:32 +0200 (CEST)", "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n by mails.dpdk.org (Postfix) with ESMTP id 8A4C241162\n for <dev@dpdk.org>; Thu, 9 Sep 2021 15:50:30 +0200 (CEST)", "from orsmga004.jf.intel.com ([10.7.209.38])\n by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 09 Sep 2021 06:50:30 -0700", "from silpixa00396680.ir.intel.com (HELO\n silpixa00396680.ger.corp.intel.com) ([10.237.223.54])\n by orsmga004.jf.intel.com with ESMTP; 09 Sep 2021 06:50:27 -0700" ], "X-IronPort-AV": [ "E=McAfee;i=\"6200,9189,10101\"; a=\"200318423\"", "E=Sophos;i=\"5.85,280,1624345200\"; d=\"scan'208\";a=\"200318423\"", "E=Sophos;i=\"5.85,280,1624345200\"; d=\"scan'208\";a=\"580894512\"" ], "X-ExtLoop1": "1", "From": "Ray Kinsella <mdr@ashroe.eu>", "To": "dev@dpdk.org", "Cc": "bruce.richardson@intel.com, stephen@networkplumber.org,\n ferruh.yigit@intel.com, thomas@monjalon.net, ktraynor@redhat.com,\n mdr@ashroe.eu, aconole@redhat.com, roy.fan.zhang@intel.com,\n arkadiuszx.kusztal@intel.com, gakhil@marvell.com", "Date": "Thu, 9 Sep 2021 14:48:06 +0100", "Message-Id": "<20210909134808.1585777-3-mdr@ashroe.eu>", "X-Mailer": "git-send-email 2.26.2", "In-Reply-To": "<20210909134808.1585777-1-mdr@ashroe.eu>", "References": "<20210618163659.85933-1-mdr@ashroe.eu>\n <20210909134808.1585777-1-mdr@ashroe.eu>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[dpdk-dev] [PATCH v13 2/4] devtools: script to send notifications\n of expired symbols", "X-BeenThere": "dev@dpdk.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "DPDK patches and discussions <dev.dpdk.org>", "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>", "List-Archive": "<http://mails.dpdk.org/archives/dev/>", "List-Post": "<mailto:dev@dpdk.org>", "List-Help": "<mailto:dev-request@dpdk.org?subject=help>", "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>", "Errors-To": "dev-bounces@dpdk.org", "Sender": "\"dev\" <dev-bounces@dpdk.org>" }, "content": "Use this script with the output of the DPDK symbol tool, to notify\nmaintainers of expired symbols by email. You need to define the environment\nvariable DPDK_GETMAINTAINER_PATH for this tool to work.\n\nUse terminal output to review the emails before sending.\ne.g.\n$ devtools/symbol-tool.py list-expired --format-output csv \\\n| DPDK_GETMAINTAINER_PATH=<somewhere>/get_maintainer.pl \\\ndevtools/notify_expired_symbols.py --format-output terminal\n\nThen use email output to send the emails to the maintainers.\ne.g.\n$ devtools/symbol-tool.py list-expired --format-output csv \\\n| DPDK_GETMAINTAINER_PATH=<somewhere>/get_maintainer.pl \\\ndevtools/notify_expired_symbols.py --format-output email \\\n--smtp-server <server> --sender <someone@somewhere.com> \\\n--password <password> --cc <someone@somewhere.com>\n\nSigned-off-by: Ray Kinsella <mdr@ashroe.eu>\n---\n devtools/notify-symbol-maintainers.py | 302 ++++++++++++++++++++++++++\n 1 file changed, 302 insertions(+)\n create mode 100755 devtools/notify-symbol-maintainers.py", "diff": "diff --git a/devtools/notify-symbol-maintainers.py b/devtools/notify-symbol-maintainers.py\nnew file mode 100755\nindex 0000000000..edf330f88b\n--- /dev/null\n+++ b/devtools/notify-symbol-maintainers.py\n@@ -0,0 +1,302 @@\n+#!/usr/bin/env python3\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2021 Intel Corporation\n+# pylint: disable=invalid-name\n+'''Tool to notify maintainers of expired symbols'''\n+import os\n+import smtplib\n+import ssl\n+import sys\n+import subprocess\n+import argparse\n+from argparse import RawTextHelpFormatter\n+import time\n+from email.message import EmailMessage\n+from pathlib import Path\n+\n+DESCRIPTION = '''\n+Use this script with the output of the DPDK symbol tool, to notify maintainers\n+and contributors of expired symbols by email. You need to define the environment\n+variable DPDK_GETMAINTAINER_PATH for this tool to work.\n+\n+Use terminal output to review the emails before sending.\n+e.g.\n+$ devtools/symbol-tool.py list-expired --format-output csv \\\\\n+| DPDK_GETMAINTAINER_PATH=<somewhere>/get_maintainer.pl \\\\\n+{s} --format-output terminal\n+\n+Then use email output to send the emails to the maintainers.\n+e.g.\n+$ devtools/symbol-tool.py list-expired --format-output csv \\\\\n+| DPDK_GETMAINTAINER_PATH=<somewhere>/get_maintainer.pl \\\\\n+{s} --format-output email \\\\\n+--smtp-server <server> --sender <someone@somewhere.com> --password <password> \\\\\n+--cc <someone@somewhere.com>\n+''' # noqa: E501\n+\n+EMAIL_TEMPLATE = '''Hi there,\n+\n+Please note the symbols listed below have expired. In line with the DPDK ABI\n+policy, they should be scheduled for removal, in the next DPDK release.\n+\n+For more information, please see the DPDK ABI Policy, section 3.5.3.\n+https://doc.dpdk.org/guides/contributing/abi_policy.html\n+\n+Thanks,\n+\n+The DPDK Symbol Bot\n+\n+''' # noqa: E501\n+\n+ABI_POLICY = 'doc/guides/contributing/abi_policy.rst'\n+DPDK_GMP_ENV_VAR = 'DPDK_GETMAINTAINER_PATH'\n+MAINTAINERS = 'MAINTAINERS'\n+get_maintainer = ['devtools/get-maintainer.sh',\n+ '--email', '-f']\n+\n+\n+class EnvironException(Exception):\n+ '''Subclass exception for Pylint\\'s happiness.'''\n+\n+\n+def _die_on_exception(e):\n+ '''Print an exception, and quit'''\n+\n+ print('Fatal Error: ' + str(e))\n+ sys.exit()\n+\n+\n+def _check_get_maintainers_env():\n+ '''Check get maintainers scripts are setup'''\n+\n+ if not Path(get_maintainer[0]).is_file():\n+ raise EnvironException('Cannot locate DPDK\\'s get maintainers script, '\n+ ' usually at $' + get_maintainer[0] + '.')\n+\n+ if DPDK_GMP_ENV_VAR not in os.environ:\n+ raise EnvironException(DPDK_GMP_ENV_VAR + ' is not defined.')\n+\n+ if not Path(os.environ[DPDK_GMP_ENV_VAR]).is_file():\n+ raise EnvironException('Cannot locate get maintainers script, usually'\n+ ' at ' + DPDK_GMP_ENV_VAR + '.')\n+\n+\n+def _get_maintainers(libpath):\n+ '''Get the maintainers for given library'''\n+\n+ try:\n+ _check_get_maintainers_env()\n+ except EnvironException as e:\n+ _die_on_exception(e)\n+\n+ try:\n+ cmd = get_maintainer + [libpath]\n+ result = subprocess.run(cmd,\n+ stdout=subprocess.PIPE,\n+ stderr=subprocess.PIPE,\n+ check=True)\n+ except subprocess.CalledProcessError as e:\n+ _die_on_exception(e)\n+\n+ if result is None:\n+ return None\n+\n+ email = result.stdout.decode('utf-8')\n+ if email == '':\n+ return None\n+\n+ email = list(filter(None, email.split('\\n')))\n+ return email\n+\n+\n+default_maintainers = _get_maintainers(ABI_POLICY) + \\\n+ _get_maintainers(MAINTAINERS)\n+\n+\n+def get_maintainers(libpath):\n+ '''Get the maintainers for given library'''\n+ maintainers = _get_maintainers(libpath)\n+\n+ if maintainers is None:\n+ maintainers = default_maintainers\n+\n+ return maintainers\n+\n+\n+def get_message(library, symbols, config):\n+ '''Build email message from symbols, config and maintainers'''\n+ contributors = {}\n+ message = {}\n+ maintainers = get_maintainers(library)\n+\n+ if maintainers != default_maintainers:\n+ message['CC'] = default_maintainers.copy()\n+\n+ if 'CC' in config:\n+ message.setdefault('CC', []).append(config['CC'])\n+\n+ message['Subject'] = 'Expired symbols in {}\\n'.format(library)\n+\n+ body = EMAIL_TEMPLATE\n+ body += '{:<50}{:<25}{:<25}\\n'.format('Symbol', 'Contributor', 'Email')\n+ for sym in symbols:\n+ body += ('{:<50}{:<25}{:<25}\\n'.format(sym,\n+ symbols[sym]['name'],\n+ symbols[sym]['email']))\n+ email = symbols[sym]['email']\n+ contributors[email] = ''\n+\n+ contributors = list(contributors.keys())\n+\n+ message['To'] = maintainers + contributors\n+ message['Body'] = body\n+\n+ return message\n+\n+\n+class OutputEmail():\n+ '''Format the output for email'''\n+\n+ def __init__(self, config):\n+ self.config = config\n+\n+ self.terminal = OutputTerminal(config)\n+ context = ssl.create_default_context()\n+\n+ # Try to log in to server and send email\n+ try:\n+ self.server = smtplib.SMTP(config['smtp_server'], 587)\n+ self.server.starttls(context=context) # Secure the connection\n+ self.server.login(config['sender'], config['password'])\n+ except EnvironException as e:\n+ _die_on_exception(e)\n+\n+ def message(self, message):\n+ '''send email'''\n+ self.terminal.message(message)\n+\n+ msg = EmailMessage()\n+ msg.set_content(message.pop('Body'))\n+\n+ for key in message.keys():\n+ msg[key] = message[key]\n+\n+ msg['From'] = self.config['sender']\n+ msg['Reply-To'] = 'no-reply@dpdk.org'\n+\n+ self.server.send_message(msg)\n+\n+ time.sleep(1)\n+\n+ def __del__(self):\n+ self.server.quit()\n+\n+\n+class OutputTerminal(): # pylint: disable=too-few-public-methods\n+ '''Format the output for the terminal'''\n+\n+ def __init__(self, config):\n+ self.config = config\n+\n+ def message(self, message):\n+ '''Print email to terminal'''\n+\n+ terminal = 'To:' + ', '.join(message['To']) + '\\n'\n+ if 'sender' in self.config.keys():\n+ terminal += 'From:' + self.config['sender'] + '\\n'\n+\n+ terminal += 'Reply-To:' + 'no-reply@dpdk.org' + '\\n'\n+\n+ if 'CC' in message:\n+ terminal += 'CC:' + ', '.join(message['CC']) + '\\n'\n+\n+ terminal += 'Subject:' + message['Subject'] + '\\n'\n+ terminal += 'Body:' + message['Body'] + '\\n'\n+\n+ print(terminal)\n+ print('-' * 80)\n+\n+\n+def parse_config(args):\n+ '''put the command line args in the right places'''\n+ config = {}\n+ error_msg = None\n+\n+ outputs = {\n+ None: OutputTerminal,\n+ 'terminal': OutputTerminal,\n+ 'email': OutputEmail\n+ }\n+\n+ if args.format_output == 'email':\n+ if args.smtp_server is None:\n+ error_msg = 'SMTP server'\n+ else:\n+ config['smtp_server'] = args.smtp_server\n+\n+ if args.sender is None:\n+ error_msg = 'sender'\n+ else:\n+ config['sender'] = args.sender\n+\n+ if args.password is None:\n+ error_msg = 'password'\n+ else:\n+ config['password'] = args.password\n+\n+ if args.cc is not None:\n+ config['CC'] = args.cc\n+\n+ if error_msg is not None:\n+ print('Please specify a {} for email output'.format(error_msg))\n+ return None\n+\n+ config['output'] = outputs[args.format_output]\n+ return config\n+\n+\n+def main():\n+ '''Main entry point'''\n+ parser = \\\n+ argparse.ArgumentParser(description=DESCRIPTION.format(s=__file__),\n+ formatter_class=RawTextHelpFormatter)\n+ parser.add_argument('--format-output',\n+ choices=['terminal', 'email'],\n+ default='terminal')\n+ parser.add_argument('--smtp-server')\n+ parser.add_argument('--password')\n+ parser.add_argument('--sender')\n+ parser.add_argument('--cc')\n+\n+ args = parser.parse_args()\n+ config = parse_config(args)\n+ if config is None:\n+ return\n+\n+ symbols = {}\n+ lastlib = library = ''\n+\n+ output = config['output'](config)\n+\n+ for line in sys.stdin:\n+ line = line.rstrip('\\n')\n+\n+ if line.find('mapfile') >= 0:\n+ continue\n+ library, symbol, name, email = line.split(',')\n+\n+ if library != lastlib:\n+ message = get_message(lastlib, symbols, config)\n+ output.message(message)\n+ symbols = {}\n+\n+ lastlib = library\n+ symbols[symbol] = {'name': name, 'email': email}\n+\n+ # print the last library\n+ message = get_message(lastlib, symbols, config)\n+ output.message(message)\n+\n+\n+if __name__ == '__main__':\n+ main()\n", "prefixes": [ "v13", "2/4" ] }{ "id": 98438, "url": "