Show a patch.

Update a patch.

Update a patch.

GET /api/patches/1558030/
Content-Type: application/json
Vary: Accept

    "id": 1558030,
    "url": "",
    "web_url": "",
    "project": {
        "id": 47,
        "url": "",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "",
        "list_email": "",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    "msgid": "<>",
    "list_archive_url": null,
    "date": "2021-11-22T11:22:51",
    "name": "[ovs-dev,v1,13/18] python: detect changes in flow formatting code",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "87d9026a2cd3a42781e28d0bf081db1437dbddbf",
    "submitter": {
        "id": 77477,
        "url": "",
        "name": "Adrian Moreno",
        "email": ""
    "delegate": null,
    "mbox": "",
    "series": [
            "id": 273222,
            "url": "",
            "web_url": "",
            "date": "2021-11-22T11:22:39",
            "name": "python: add flow parsing library",
            "version": 1,
            "mbox": ""
    "comments": "",
    "check": "fail",
    "checks": "",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<>",
        "X-Original-To": [
        "Delivered-To": [
        "Authentication-Results": [
            ";\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.a=rsa-sha256\n header.s=mimecast20190719 header.b=di1i/H5l;\n\tdkim-atps=neutral",
            ";\n spf=pass (sender SPF authorized)\n (client-ip=2605:bc80:3010::133;;\n; receiver=<UNKNOWN>)",
            " (amavisd-new);\n dkim=pass (1024-bit key)",
            ";\n auth=pass smtp.auth=CUSA124A263"
        "Received": [
            "from ( [IPv6:2605:bc80:3010::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby (Postfix) with ESMTPS id 4HyQ0X4xFkz9sX3\n\tfor <>; Mon, 22 Nov 2021 22:24:44 +1100 (AEDT)",
            "from localhost (localhost [])\n\tby (Postfix) with ESMTP id 91A0C40970;\n\tMon, 22 Nov 2021 11:24:41 +0000 (UTC)",
            "from ([])\n\tby localhost ( []) (amavisd-new, port 10024)\n\twith ESMTP id R1bUXGO_AYAE; Mon, 22 Nov 2021 11:24:37 +0000 (UTC)",
            "from (\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby (Postfix) with ESMTPS id C3B3640593;\n\tMon, 22 Nov 2021 11:24:34 +0000 (UTC)",
            "from (localhost [])\n\tby (Postfix) with ESMTP id 8E458C002F;\n\tMon, 22 Nov 2021 11:24:33 +0000 (UTC)",
            "from ( [IPv6:2605:bc80:3010::136])\n by (Postfix) with ESMTP id 0F9DAC003E\n for <>; Mon, 22 Nov 2021 11:24:32 +0000 (UTC)",
            "from localhost (localhost [])\n by (Postfix) with ESMTP id DB57960673\n for <>; Mon, 22 Nov 2021 11:23:45 +0000 (UTC)",
            "from ([])\n by localhost ( []) (amavisd-new, port 10024)\n with ESMTP id KSBIK2ujkORz for <>;\n Mon, 22 Nov 2021 11:23:44 +0000 (UTC)",
            "from\n ( [])\n by (Postfix) with ESMTPS id BD81560A5A\n for <>; Mon, 22 Nov 2021 11:23:44 +0000 (UTC)",
            "from (\n []) by with ESMTP with STARTTLS\n (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n us-mta-372-5h1-Zi5YOI2IJLPW7K8umg-1; Mon, 22 Nov 2021 06:23:40 -0500",
            "from (\n [])\n (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n (No client certificate requested)\n by (Postfix) with ESMTPS id 9644B806694\n for <>; Mon, 22 Nov 2021 11:23:39 +0000 (UTC)",
            "from (unknown [])\n by (Postfix) with ESMTP id C342860862;\n Mon, 22 Nov 2021 11:23:38 +0000 (UTC)"
        "X-Virus-Scanned": [
            "amavisd-new at",
            "amavisd-new at"
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;;\n s=mimecast20190719; t=1637580223;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=OP8HkWZs2I0Zj3w2U4ugRLzK9hRNJuZAlKv7SbkR6TQ=;\n b=di1i/H5l6JQjV0WhzJbWrH18XfipCj9CqMbSTkIbYI8aGGAZ3gS/MOQbpPTYHEnUS2tBp+\n aO3fEvh37qN4LOcYgGgcdMDYOH2/rHLhMsPBCTrr0x1jPYJquAiGLqVqTWc9ArY7q1OFlg\n NhgyFcxGkpX3UfcoY7qYHDSPVFZA4ek=",
        "X-MC-Unique": "5h1-Zi5YOI2IJLPW7K8umg-1",
        "From": "Adrian Moreno <>",
        "To": "",
        "Date": "Mon, 22 Nov 2021 12:22:51 +0100",
        "Message-Id": "<>",
        "In-Reply-To": "<>",
        "References": "<>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 2.79 on",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "",
        "Subject": "[ovs-dev] [PATCH v1 13/18] python: detect changes in flow\n\tformatting code",
        "X-BeenThere": "",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<>",
        "List-Unsubscribe": "<>,\n <>",
        "List-Archive": "<>",
        "List-Post": "<>",
        "List-Help": "<>",
        "List-Subscribe": "<>,\n <>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "",
        "Sender": "\"dev\" <>"
    "content": "In order to minimize the risk of having the python flow parsing code and\nthe C flow formatting code divert, add a target that checks if the\nformatting code has been changed since the last revision and warn the\ndeveloper if it has.\n\nThe script also makes it easy to update the dependency file so hopefully\nit will not cause too much trouble for a developer that has modifed the\nfile without changing the flow string format.\n\nSigned-off-by: Adrian Moreno <>\n---\n .gitignore                      |   1 +\n python/              |  13 +++-\n python/build/ | 101 ++++++++++++++++++++++++++++++++\n python/ovs/flows/        |   5 ++\n 4 files changed, 118 insertions(+), 2 deletions(-)\n create mode 100755 python/build/\n create mode 100644 python/ovs/flows/",
    "diff": "diff --git a/.gitignore b/.gitignore\nindex f1cdcf124..e6bca1cd2 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -79,3 +79,4 @@ testsuite.tmp.orig\n /Documentation/_build\n /.venv\n /cxx-check\n+/flowparse-deps-check\ndiff --git a/python/ b/python/\nindex 21aa897f2..da6ef08b4 100644\n--- a/python/\n+++ b/python/\n@@ -50,7 +50,8 @@ ovs_pyfiles = \\\n \tpython/ovs/flows/ \\\n \tpython/ovs/flows/ \\\n \tpython/ovs/flows/ \\\n-\tpython/ovs/flows/\n+\tpython/ovs/flows/ \\\n+\tpython/ovs/flows/\n \n # These python files are used at build time but not runtime,\n # so they are not installed.\n@@ -58,7 +59,8 @@ EXTRA_DIST += \\\n \tpython/build/ \\\n \tpython/build/ \\\n \tpython/build/ \\\n-\tpython/build/\n+\tpython/build/ \\\n+\tpython/build/\n \n # PyPI support.\n EXTRA_DIST += \\\n@@ -135,3 +137,10 @@ $(srcdir)/python/ovs/flows/ $(srcdir)/build-aux/gen_ofp_field_deco\n EXTRA_DIST += python/ovs/flows/\n CLEANFILES += python/ovs/flows/\n \n+ALL_LOCAL += flowparse-deps-check\n+DEPS = $(shell $(AM_V_GEN)$(run_python) $(srcdir)/python/build/ list)\n+flowparse-deps-check: $(srcdir)/python/build/ $(DEPS)\n+\techo $(DEPS)\n+\t$(AM_V_GEN)$(run_python) $(srcdir)/python/build/ check\n+\ttouch $@\n+CLEANFILES += flowparse-deps-check\ndiff --git a/python/build/ b/python/build/\nnew file mode 100755\nindex 000000000..9adb1d89c\n--- /dev/null\n+++ b/python/build/\n@@ -0,0 +1,101 @@\n+#!/usr/bin/env python3\n+# Copyright (c) 2021 Red Hat, Inc.\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at:\n+#\n+#\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+# Breaks lines read from stdin into groups using blank lines as\n+# group separators, then sorts lines within the groups for\n+# reproducibility.\n+\n+\n+# ovs-test-ofparse is just a wrapper around ovs-ofctl\n+# that also runs the python flow parsing utility to check that flows are\n+# parseable\n+\n+import hashlib\n+import sys\n+\n+DEPENDENCIES = [\"lib/ofp-actions.c\", \"lib/odp-util.c\"]\n+DEPENDENCY_FILE = \"python/ovs/flows/\"\n+\n+\n+def usage():\n+    print(\n+        \"\"\"\n+Usage {cmd} [check | update | list]\n+Tool to verify flow parsing python code is kept in sync with\n+flow printing C code.\n+\n+Commands:\n+  check: check the dependencies are met\n+  update: update the dependencies based on current file content\n+  list: list the dependency files\n+\"\"\".format(\n+            cmd=sys.argv[0]\n+        )\n+    )\n+\n+\n+def digest(filename):\n+    with open(filename, \"rb\") as f:\n+        return hashlib.md5(\n+\n+\n+def main():\n+    if len(sys.argv) != 2:\n+        usage()\n+        sys.exit(1)\n+\n+    if sys.argv[1] == \"list\":\n+        print(\" \".join(DEPENDENCIES))\n+    elif sys.argv[1] == \"update\":\n+        dep_str = list()\n+        for dep in DEPENDENCIES:\n+            dep_str.append(\n+                '    \"{dep}\": \"{digest}\"'.format(dep=dep, digest=digest(dep))\n+            )\n+\n+        depends = \"\"\"# File automatically generated. Do not modify manually\n+dependencies = {{\n+{dependencies_dict}\n+}}\"\"\".format(\n+            dependencies_dict=\",\\n\".join(dep_str)\n+        )\n+        with open(DEPENDENCY_FILE, \"w\") as f:\n+            print(depends, file=f)\n+\n+    elif sys.argv[1] == \"check\":\n+        from ovs.flows.deps import dependencies\n+\n+        for dep in DEPENDENCIES:\n+            expected = dependencies.get(dep)\n+            if not expected or expected != digest(dep):\n+                print(\n+                    \"\"\"\n+Dependency file {dep} has changed.\n+Please verify the flow output format has not changed or modify the python flow parsing code accordingly.\n+\n+Once you're done, update the dependencies by running '{cmd} update' and check in the new dependency file.\n+\"\"\".format(\n+                        dep=dep,\n+                        cmd=sys.argv[0],\n+                    )\n+                )\n+                return 2\n+    else:\n+        usage()\n+        sys.exit(1)\n+\n+\n+if __name__ == \"__main__\":\n+    sys.exit(main())\ndiff --git a/python/ovs/flows/ b/python/ovs/flows/\nnew file mode 100644\nindex 000000000..aaf428917\n--- /dev/null\n+++ b/python/ovs/flows/\n@@ -0,0 +1,5 @@\n+# File automatically generated. Do not modify manually\n+dependencies = {\n+    \"lib/ofp-actions.c\": \"f108b3e119f03b3373064589aecdeaf0\",\n+    \"lib/odp-util.c\": \"c946c21d8f644869ce778842167f9129\"\n+}\n",
    "prefixes": [