get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 94658,
    "url": "https://patches.dpdk.org/api/patches/94658/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210621151100.406252-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": "<20210621151100.406252-1-mdr@ashroe.eu>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210621151100.406252-1-mdr@ashroe.eu",
    "date": "2021-06-21T15:11:00",
    "name": "devtools: script to track map symbols",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8e59bdbaf5b964e4a7702f007acba116a3d0cb58",
    "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/20210621151100.406252-1-mdr@ashroe.eu/mbox/",
    "series": [
        {
            "id": 17427,
            "url": "https://patches.dpdk.org/api/series/17427/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=17427",
            "date": "2021-06-21T15:11:00",
            "name": "devtools: script to track map symbols",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/17427/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/94658/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/94658/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 7AA13A0547;\n\tMon, 21 Jun 2021 17:19:17 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id F333741158;\n\tMon, 21 Jun 2021 17:19:16 +0200 (CEST)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by mails.dpdk.org (Postfix) with ESMTP id CE99540040\n for <dev@dpdk.org>; Mon, 21 Jun 2021 17:19:15 +0200 (CEST)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 21 Jun 2021 08:19:14 -0700",
            "from silpixa00396680.ir.intel.com (HELO\n silpixa00396680.ger.corp.intel.com) ([10.237.223.54])\n by orsmga008.jf.intel.com with ESMTP; 21 Jun 2021 08:19:12 -0700"
        ],
        "IronPort-SDR": [
            "\n wxxnKEUIPo6As1oSSbc4kGAVjfFhwmYdmlX8HBq57iDOB60XeryXFcCMBxg3rWKxJmgJa8i7KS\n kJk6hCfpY5nQ==",
            "\n olbmnbCuz4igOq3blyWlARt9tBuuQu1dxNRODNFd618WtiysEVa4AbrEvv4Ogu9aavfB8KsLoW\n iMyj9owCqUPg=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10022\"; a=\"292495713\"",
            "E=Sophos;i=\"5.83,289,1616482800\"; d=\"scan'208\";a=\"292495713\"",
            "E=Sophos;i=\"5.83,289,1616482800\"; d=\"scan'208\";a=\"452225488\""
        ],
        "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:11:00 +0100",
        "Message-Id": "<20210621151100.406252-1-mdr@ashroe.eu>",
        "X-Mailer": "git-send-email 2.26.2",
        "In-Reply-To": "<c13f57a1-aec7-fa82-aa4c-e8c5d4bb1d59@ashroe.eu>",
        "References": "<c13f57a1-aec7-fa82-aa4c-e8c5d4bb1d59@ashroe.eu>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH] 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---\n devtools/count_symbols.py | 230 ++++++++++++++++++++++++++++++++++++++\n 1 file changed, 230 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..7b29651044\n--- /dev/null\n+++ b/devtools/count_symbols.py\n@@ -0,0 +1,230 @@\n+#!/usr/bin/env python3\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2021 Intel Corporation\n+from pathlib import Path\n+import sys, 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+        exit()\n+\n+symbolMapGrammar = 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+#abi_ver = ['21', '20.0.1', '20.0', '20']\n+\n+def get_abi_versions():\n+    year = datetime.date.today().year - 2000\n+    s=\" |\".join(['\\'{}\\''.format(i) for i in reversed(range(21, year + 1)) ])\n+    s = s + ' | \\'20.0.1\\' | \\'20.0\\' | \\'20\\''\n+\n+    return s\n+\n+def get_dpdk_releases():\n+    year = datetime.date.today().year - 2000\n+    s=\"|\".join(\"{}\".format(i) for i in range(19,year + 1))\n+    pattern = re.compile('^\\\"v(' + s + ')\\.\\d{2}\\\"$')\n+\n+    cmd = ['git', 'for-each-ref', '--sort=taggerdate', '--format', '\"%(tag)\"']\n+    result = subprocess.run(cmd, \\\n+                            stdout=subprocess.PIPE, \\\n+                            stderr=subprocess.PIPE)\n+    if result.stderr.startswith(b'fatal'):\n+        result = None\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+\n+def get_terminal_rows():\n+    rows, _ = os.popen('stty size', 'r').read().split()\n+    return int(rows)\n+\n+def fix_directory_name(path):\n+    mapfilepath1 = str(path.parent.name)\n+    mapfilepath2 = str(path.parents[1])\n+    mapfilepath = mapfilepath2 + '/librte_' + mapfilepath1\n+\n+    return mapfilepath\n+\n+# fix removal of the librte_ from the directory names\n+def directory_renamed(path, rel):\n+    mapfilepath = fix_directory_name(path)\n+    tagfile = '{}:{}/{}'.format(rel, mapfilepath,  path.name)\n+\n+    result = subprocess.run(['git', 'show', tagfile], \\\n+                            stdout=subprocess.PIPE, \\\n+                            stderr=subprocess.PIPE)\n+    if result.stderr.startswith(b'fatal'):\n+        result = None\n+\n+    return result\n+\n+# fix renaming of map files\n+def mapfile_renamed(path, rel):\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+    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+        result = subprocess.run(['git', 'show', tagfile], \\\n+                                stdout=subprocess.PIPE, \\\n+                                stderr=subprocess.PIPE)\n+        if result.stderr.startswith(b'fatal'):\n+            result = None\n+\n+    else:\n+        result = None\n+\n+    return result\n+\n+# renaming of the map file & renaming of directory\n+def mapfile_and_directory_renamed(path, rel):\n+    mapfilepath = Path(\"{}/{}\".format(fix_directory_name(path),path.name))\n+\n+    return mapfile_renamed(mapfilepath, rel)\n+\n+fix_strategies = [directory_renamed, \\\n+                  mapfile_renamed, \\\n+                  mapfile_and_directory_renamed]\n+\n+fmt = col_fmt = \"\"\n+\n+def set_terminal_output(dpdk_rel):\n+    global fmt, col_fmt\n+\n+    fmt = '{:<50}'\n+    col_fmt = fmt\n+    for rel in dpdk_rel:\n+        fmt += '{:<6}{:<6}'\n+        col_fmt += '{:<12}'\n+\n+def set_csv_output(dpdk_rel):\n+    global fmt, col_fmt\n+\n+    fmt = '{},'\n+    col_fmt = fmt\n+    for rel in dpdk_rel:\n+        fmt += '{},{},'\n+        col_fmt += '{},,'\n+\n+output_formats = { None: set_terminal_output, \\\n+                   'terminal': set_terminal_output, \\\n+                   'csv': set_csv_output }\n+directories = 'drivers, lib'\n+\n+def main():\n+    global fmt, col_fmt, symbolMapGrammar\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=directories,\n+                        default=directories)\n+    args = parser.parse_args()\n+\n+    dpdk_rel = get_dpdk_releases()\n+\n+    # set the output format\n+    output_formats[args.format_output](dpdk_rel)\n+\n+    column_titles = ['mapfile'] + dpdk_rel\n+    print(col_fmt.format(*column_titles))\n+\n+    symbolMapGrammar = symbolMapGrammar.format(get_abi_versions())\n+    MAPParser = makeGrammar(symbolMapGrammar, {})\n+\n+    terminal_rows = get_terminal_rows()\n+    row = 0\n+\n+    for src_dir in args.directory.split(','):\n+        for path in Path(src_dir).rglob('*.map'):\n+            csym = [0] * 2\n+            relsym = [str(path)]\n+\n+            for rel in dpdk_rel:\n+                i = csym[0] = csym[1] = 0\n+                abi_sections = None\n+\n+                tagfile = '{}:{}'.format(rel,path)\n+                result = subprocess.run(['git', 'show', tagfile], \\\n+                                        stdout=subprocess.PIPE, \\\n+                                        stderr=subprocess.PIPE)\n+\n+                if result.stderr.startswith(b'fatal'):\n+                    result = None\n+\n+                while(result is None and i < len(fix_strategies)):\n+                    result = fix_strategies[i](path, rel)\n+                    i += 1\n+\n+                if result is not None:\n+                    mapfile = result.stdout.decode('utf-8')\n+                    abi_sections = MAPParser(mapfile).abi()\n+\n+                if abi_sections is not None:\n+                    # which versions are present, and we care about\n+                    ignore = ['EXPERIMENTAL','INTERNAL']\n+                    found_ver = [ver \\\n+                                 for ver in abi_sections \\\n+                                 if ver not in ignore]\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+                relsym += csym\n+\n+            print(fmt.format(*relsym))\n+            row += 1\n+\n+        if((terminal_rows>0) and ((row % terminal_rows) == 0)):\n+            print(col_fmt.format(*column_titles))\n+\n+if __name__ == '__main__':\n+        main()\n",
    "prefixes": []
}