get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/94659/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 94659,
    "url": "https://patches.dpdk.org/api/patches/94659/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210621152515.408384-1-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": "<20210621152515.408384-1-mdr@ashroe.eu>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210621152515.408384-1-mdr@ashroe.eu",
    "date": "2021-06-21T15:25:15",
    "name": "[v3] devtools: script to track map symbols",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c144e2e9a9ca88f566542490760b7230544e50b8",
    "submitter": {
        "id": 1310,
        "url": "https://patches.dpdk.org/api/people/1310/?format=api",
        "name": "Ray Kinsella",
        "email": "mdr@ashroe.eu"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210621152515.408384-1-mdr@ashroe.eu/mbox/",
    "series": [
        {
            "id": 17428,
            "url": "https://patches.dpdk.org/api/series/17428/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=17428",
            "date": "2021-06-21T15:25:15",
            "name": "[v3] devtools: script to track map symbols",
            "version": 3,
            "mbox": "https://patches.dpdk.org/series/17428/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/94659/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/94659/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 D21C3A0547;\n\tMon, 21 Jun 2021 17:33:27 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id B95E3411B9;\n\tMon, 21 Jun 2021 17:33:27 +0200 (CEST)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by mails.dpdk.org (Postfix) with ESMTP id 36D8B41199\n for <dev@dpdk.org>; Mon, 21 Jun 2021 17:33:26 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 21 Jun 2021 08:33:25 -0700",
            "from silpixa00396680.ir.intel.com (HELO\n silpixa00396680.ger.corp.intel.com) ([10.237.223.54])\n by orsmga001.jf.intel.com with ESMTP; 21 Jun 2021 08:33:22 -0700"
        ],
        "IronPort-SDR": [
            "\n dYjLC5FEScPrs6SRDLia0irggDLz6bsIAprUwhDmi/88Jy/FCmrbkxumFy7aD+BwLTkQN3vdR4\n tklWFxhQI1Yw==",
            "\n F9T2ZAAeUMdKiLBd79Uac3umuH5XtvIaEolwlgZTIqOqjXjIY8zNqZUmj1bQqMNwocD0zX1hME\n nfnSOgzYyyiA=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10022\"; a=\"292498741\"",
            "E=Sophos;i=\"5.83,289,1616482800\"; d=\"scan'208\";a=\"292498741\"",
            "E=Sophos;i=\"5.83,289,1616482800\"; d=\"scan'208\";a=\"486530427\""
        ],
        "X-ExtLoop1": "1",
        "From": "Ray Kinsella <mdr@ashroe.eu>",
        "To": "dev@dpdk.org",
        "Cc": "stephen@networkplumber.org, ferruh.yigit@intel.com, thomas@monjalon.net,\n ktraynor@redhat.com, bruce.richardson@intel.com, mdr@ashroe.eu",
        "Date": "Mon, 21 Jun 2021 16:25:15 +0100",
        "Message-Id": "<20210621152515.408384-1-mdr@ashroe.eu>",
        "X-Mailer": "git-send-email 2.26.2",
        "In-Reply-To": "<20210618163659.85933-1-mdr@ashroe.eu>",
        "References": "<20210618163659.85933-1-mdr@ashroe.eu>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v3] devtools: script to track map 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": "Script to track growth of stable and experimental symbols\nover releases since v19.11.\n\nSigned-off-by: Ray Kinsella <mdr@ashroe.eu>\n---\nv2: reworked to fix pylint errors\nv3: sent with the current in-reply-to\n\n devtools/count_symbols.py | 262 ++++++++++++++++++++++++++++++++++++++\n 1 file changed, 262 insertions(+)\n create mode 100755 devtools/count_symbols.py",
    "diff": "diff --git a/devtools/count_symbols.py b/devtools/count_symbols.py\nnew file mode 100755\nindex 0000000000..30be09754f\n--- /dev/null\n+++ b/devtools/count_symbols.py\n@@ -0,0 +1,262 @@\n+#!/usr/bin/env python3\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2021 Intel Corporation\n+'''Tool to count the number of symbols in each DPDK release'''\n+from pathlib import Path\n+import sys\n+import os\n+import subprocess\n+import argparse\n+import re\n+import datetime\n+\n+try:\n+    from parsley import makeGrammar\n+except ImportError:\n+    print('This script uses the package Parsley to parse C Mapfiles.\\n'\n+          'This can be installed with \\\"pip install parsley\".')\n+    sys.exit()\n+\n+MAP_GRAMMAR = r\"\"\"\n+\n+ws = (' ' | '\\r' | '\\n' | '\\t')*\n+\n+ABI_VER = ({})\n+DPDK_VER = ('DPDK_' ABI_VER)\n+ABI_NAME = ('INTERNAL' | 'EXPERIMENTAL' | DPDK_VER)\n+comment = '#' (~'\\n' anything)+ '\\n'\n+symbol = (~(';' | '}}' | '#') anything )+:c ';' -> ''.join(c)\n+global = 'global:'\n+local = 'local: *;'\n+symbols = comment* symbol:s ws comment* -> s\n+\n+abi = (abi_section+):m -> dict(m)\n+abi_section = (ws ABI_NAME:e ws '{{' ws global* (~local ws symbols)*:s ws local* ws '}}' ws DPDK_VER* ';' ws) -> (e,s)\n+\"\"\"\n+\n+def get_abi_versions():\n+    '''Returns a string of possible dpdk abi versions'''\n+\n+    year = datetime.date.today().year - 2000\n+    tags = \" |\".join(['\\'{}\\''.format(i) \\\n+                     for i in reversed(range(21, year + 1)) ])\n+    tags  = tags + ' | \\'20.0.1\\' | \\'20.0\\' | \\'20\\''\n+\n+    return tags\n+\n+def get_dpdk_releases():\n+    '''Returns a list of dpdk release tags names  since v19.11'''\n+\n+    year = datetime.date.today().year - 2000\n+    year_range = \"|\".join(\"{}\".format(i) for i in range(19,year + 1))\n+    pattern = re.compile(r'^\\\"v(' +  year_range + r')\\.\\d{2}\\\"$')\n+\n+    cmd = ['git', 'for-each-ref', '--sort=taggerdate', '--format', '\"%(tag)\"']\n+    try:\n+        result = subprocess.run(cmd, \\\n+                                stdout=subprocess.PIPE, \\\n+                                stderr=subprocess.PIPE,\n+                                check=True)\n+    except subprocess.CalledProcessError:\n+        print(\"Failed to interogate git for release tags\")\n+        sys.exit()\n+\n+    tags = result.stdout.decode('utf-8').split('\\n')\n+\n+    # find the non-rcs between now and v19.11\n+    tags = [ tag.replace('\\\"','') \\\n+             for tag in reversed(tags) \\\n+             if pattern.match(tag) ][:-3]\n+\n+    return tags\n+\n+def fix_directory_name(path):\n+    '''Prepend librte to the source directory name'''\n+    mapfilepath1 = str(path.parent.name)\n+    mapfilepath2 = str(path.parents[1])\n+    mapfilepath = mapfilepath2 + '/librte_' + mapfilepath1\n+\n+    return mapfilepath\n+\n+def directory_renamed(path, rel):\n+    '''Fix removal of the librte_ from the directory names'''\n+\n+    mapfilepath = fix_directory_name(path)\n+    tagfile = '{}:{}/{}'.format(rel, mapfilepath,  path.name)\n+\n+    try:\n+        result = subprocess.run(['git', 'show', tagfile], \\\n+                                stdout=subprocess.PIPE, \\\n+                                stderr=subprocess.PIPE,\n+                                check=True)\n+    except subprocess.CalledProcessError:\n+        result = None\n+\n+    return result\n+\n+def mapfile_renamed(path, rel):\n+    '''Fix renaming of map files'''\n+    newfile = None\n+\n+    result = subprocess.run(['git', 'ls-tree', \\\n+                             rel, str(path.parent) + '/'], \\\n+                            stdout=subprocess.PIPE, \\\n+                            stderr=subprocess.PIPE,\n+                            check=True)\n+    dentries = result.stdout.decode('utf-8')\n+    dentries = dentries.split('\\n')\n+\n+    # filter entries looking for the map file\n+    dentries = [dentry for dentry in dentries if dentry.endswith('.map')]\n+    if len(dentries) > 1 or len(dentries) == 0:\n+        return None\n+\n+    dparts = dentries[0].split('/')\n+    newfile = dparts[len(dparts) - 1]\n+\n+    if newfile is not None:\n+        tagfile = '{}:{}/{}'.format(rel, path.parent, newfile)\n+\n+        try:\n+            result = subprocess.run(['git', 'show', tagfile], \\\n+                                    stdout=subprocess.PIPE, \\\n+                                    stderr=subprocess.PIPE,\n+                                    check=True)\n+        except subprocess.CalledProcessError:\n+            result = None\n+\n+    else:\n+        result = None\n+\n+    return result\n+\n+def mapfile_and_directory_renamed(path, rel):\n+    '''Fix renaming of the map file & the source directory'''\n+    mapfilepath = Path(\"{}/{}\".format(fix_directory_name(path),path.name))\n+\n+    return mapfile_renamed(mapfilepath, rel)\n+\n+def get_terminal_rows():\n+    '''Find the number of rows in the terminal'''\n+\n+    rows, _ = os.popen('stty size', 'r').read().split()\n+    return int(rows)\n+\n+class FormatOutput():\n+    '''Format the output to supported formats'''\n+    output_fmt = \"\"\n+    column_fmt = \"\"\n+\n+    def __init__(self, format_output, dpdk_releases):\n+        self.OUTPUT_FORMATS[format_output](self,dpdk_releases)\n+        self.column_titles = ['mapfile'] +  dpdk_releases\n+\n+        self.terminal_rows = get_terminal_rows()\n+        self.row = 0\n+\n+    def set_terminal_output(self,dpdk_rel):\n+        '''Set the output format to Tabbed Seperated Values'''\n+\n+        self.output_fmt = '{:<50}' + \\\n+            ''.join(['{:<6}{:<6}'] * (len(dpdk_rel)))\n+        self.column_fmt = '{:50}' + \\\n+            ''.join(['{:<12}'] * (len(dpdk_rel)))\n+\n+    def set_csv_output(self,dpdk_rel):\n+        '''Set the output format to Comma Seperated Values'''\n+\n+        self.output_fmt = '{},' + \\\n+            ','.join(['{},{}'] * (len(dpdk_rel)))\n+        self.column_fmt = '{},' + \\\n+            ','.join(['{},'] * (len(dpdk_rel)))\n+\n+    def print_columns(self):\n+        '''Print column rows with release names'''\n+        print(self.column_fmt.format(*self.column_titles))\n+        self.row += 1\n+\n+    def print_row(self,symbols):\n+        '''Print row of symbol values'''\n+        print(self.output_fmt.format(*symbols))\n+        self.row += 1\n+\n+        if((self.terminal_rows>0) and ((self.row % self.terminal_rows) == 0)):\n+            self.print_columns()\n+\n+    OUTPUT_FORMATS = { None: set_terminal_output, \\\n+                       'terminal': set_terminal_output, \\\n+                       'csv': set_csv_output }\n+\n+SRC_DIRECTORIES = 'drivers, lib'\n+IGNORE_SECTIONS = ['EXPERIMENTAL','INTERNAL']\n+FIX_STRATEGIES = [directory_renamed, \\\n+                  mapfile_renamed, \\\n+                  mapfile_and_directory_renamed]\n+\n+def count_release_symbols(map_parser, release, mapfile_path):\n+    '''Count the symbols for a given release and mapfile'''\n+    csym = [0] * 2\n+    abi_sections = None\n+\n+    tagfile = '{}:{}'.format(release,mapfile_path)\n+    try:\n+        result = subprocess.run(['git', 'show', tagfile], \\\n+                                stdout=subprocess.PIPE, \\\n+                                stderr=subprocess.PIPE,\n+                                check=True)\n+    except subprocess.CalledProcessError:\n+        result = None\n+\n+    for fix_strategy in FIX_STRATEGIES:\n+        if result is not None:\n+            break\n+        result = fix_strategy(mapfile_path, release)\n+\n+    if result is not None:\n+        mapfile = result.stdout.decode('utf-8')\n+        abi_sections = map_parser(mapfile).abi()\n+\n+    if abi_sections is not None:\n+        # which versions are present, and we care about\n+        found_ver = [ver \\\n+                     for ver in abi_sections \\\n+                     if ver not in IGNORE_SECTIONS]\n+\n+        for ver in found_ver:\n+            csym[0] += len(abi_sections[ver])\n+\n+        # count experimental symbols\n+        if 'EXPERIMENTAL' in abi_sections:\n+            csym[1] = len(abi_sections['EXPERIMENTAL'])\n+\n+    return csym\n+\n+def main():\n+    '''Main entry point'''\n+\n+    parser = argparse.ArgumentParser(description='Count symbols in DPDK Libs')\n+    parser.add_argument('--format-output', choices=['terminal','csv'], \\\n+                        default='terminal')\n+    parser.add_argument('--directory', choices=SRC_DIRECTORIES,\n+                        default=SRC_DIRECTORIES)\n+    args = parser.parse_args()\n+\n+    dpdk_releases = get_dpdk_releases()\n+    format_output = FormatOutput(args.format_output, dpdk_releases)\n+\n+    map_grammar = MAP_GRAMMAR.format(get_abi_versions())\n+    map_parser = makeGrammar(map_grammar, {})\n+\n+    format_output.print_columns()\n+    for src_dir in args.directory.split(','):\n+        for path in Path(src_dir).rglob('*.map'):\n+            relsym = [str(path)]\n+\n+            for release in dpdk_releases:\n+                csym = count_release_symbols(map_parser, release, path)\n+                relsym += csym\n+\n+            format_output.print_row(relsym)\n+\n+if __name__ == '__main__':\n+    main()\n",
    "prefixes": [
        "v3"
    ]
}