From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68FFA1F4631; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=WVeYR4bC/zNy5Qpmk9TiEr9udnp4hitpDphpdmeRlK1kSCw5Naeqbi7tl8mgusM1pIJ90l6HLH7hDB9/rEC25+Di6Y4ozYlKTlRyvdBf8aVEzBT38NHiMTjiwdcU9SCt4SrfNlrvMcAz6eF2SM0E7mVYBUagmJWBC3PAwBMDZws= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=8JLj251EiGtS/E11n5n+267zLGC8qyxQhPvEcm7GqEQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jrv7LaPSrfSZmzcv5iZnus+OaTChVkbDxFVNhNOpwIinEkm9J/wNJaLfZPnUmqWgEgNbyyeWCQaJODFOb1fMvjfDA+WLP38zQ0407jkVr3MhoFeJDKmVnGIkoECBLoZG48jL5/2n5+A6yy2VK0vFREbInC05i2kCFDOz3JXnRug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=umeedEFn; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="umeedEFn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E8901C4CEF2; Sat, 14 Jun 2025 08:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=8JLj251EiGtS/E11n5n+267zLGC8qyxQhPvEcm7GqEQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=umeedEFnlci600SipXlsi0H6C/9NbbdgnZQ+uUcYKUUcOwhDRHylvby3pkc6uxuUj gUpz0wA7vicDAg7GMtCsGBJ9LGa/T5Z/a5Q8Lo6DynAT53+IFEMv3lulVXJSBYByTo 0hq4Wcco5yoa1OMPIoCEKVxl7MdAJsIjoUWG1CWKASL2t35GzKCVb5RB+RKcghXsv1 EssBfDGOQij865I4tnSb4ZQqBMwRsCeQk+lsqM/JMKZDGToJ5zcXmrOLzk6LHTIkyr nPfaL+VU/L0+rZBf16bfLYnPo/fZWecRgnxxUI63PFYplWOUpxlUCFP8mz5rf65eSq KxFkI3aO5YlKA== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgR-000000064ah-3uBS; Sat, 14 Jun 2025 10:56:15 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 01/14] tools: ynl_gen_rst.py: create a top-level reference Date: Sat, 14 Jun 2025 10:55:55 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Currently, rt documents are referred with: Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`rt-link<../../ne= tworking/netlink_spec/rt-link>` Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`tc<../../network= ing/netlink_spec/tc>` Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`tc<../../network= ing/netlink_spec/tc>` that's hard to maintain, and may break if we change the way rst files are generated from yaml. Better to use instead a reference for the netlink family. So, add a netlink- reference to all generated docs. Signed-off-by: Mauro Carvalho Chehab --- tools/net/ynl/pyynl/ynl_gen_rst.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_g= en_rst.py index 0cb6348e28d3..7bfb8ceeeefc 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -314,10 +314,11 @@ def parse_yaml(obj: Dict[str, Any]) -> str: =20 # Main header =20 - lines.append(rst_header()) - family =3D obj['name'] =20 + lines.append(rst_header()) + lines.append(rst_label("netlink-" + family)) + title =3D f"Family ``{family}`` netlink specification" lines.append(rst_title(title)) lines.append(rst_paragraph(".. contents:: :depth: 3\n")) --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 634181E5B9E; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=JLL2CP3XoqUUij2d3mzi/hLKugkmbGK85weoIaBX/qG7jeMYRL7In17NH69LT2dIK8R+EhbaERDj+jnJE2AnRFL/0t+aETxx7xyTKvlou3LZPE3mEiMcm/2/O/WftZhEBNn5gnBmkHvDlSeBis9OOXNJgJbPhJ0WXxuR89GX+5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=5GdVV6A8bXN64ovkNLx7Xdx5aR1iPXnV/yeu24lgmqI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CtTRnhzzx+kZS9ULlsCZCrf3NnxcHgvV1SGcImUXwg1L5fxaTGY54yPPRchoRNIxBoMFH9lDQcdSWYnjSrlWjDdvkek9aloH8OKBQaLDFTBdZx2NMxooElB1+l740w9RfA9ZlPKKr7Aus1RPLB0m7wWsnLqqlQ7XIgJI81ROxdw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FSKpp81l; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FSKpp81l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DFBFBC4CEED; Sat, 14 Jun 2025 08:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891377; bh=5GdVV6A8bXN64ovkNLx7Xdx5aR1iPXnV/yeu24lgmqI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FSKpp81lQ0MUsTOKq4LT3MWqv+ebKW7/olXbn6+7/BhJwyga0wPYoUQv9GDecCoWC bR4tFN043An72M8yE8pqrHkgyRcaK2lC92xapRoRNoFJlMHpXdcJSnBPkMTbaGMH62 cM9kHuJTp2RilU5XMZxgXgDYJyUrYhN3NLDuPsfGHOTNN8XCb5R3ZwsWTv+v10DmsF v5WHZQaZGvR5Wxcol4g1SmDhRzo7yNA/ZjnPkVacbURdMVJP6WOyYGoWqqAGY62BUc uspLo1bhL8x+s3QixbXcnrC+l2vC5KOk9vj1178/JYcXUPH0OMuCh7lle4K1HfdM6c MJuHzjjIYiHpA== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgR-000000064al-49Nk; Sat, 14 Jun 2025 10:56:15 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 02/14] docs: netlink: netlink-raw.rst: use :ref: instead of :doc: Date: Sat, 14 Jun 2025 10:55:56 +0200 Message-ID: <4d46b08e43e37403afc09412692cb5eb295019b6.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Having :doc: references with relative paths doesn't always work, as it may have troubles when O=3D is used. So, replace them by Sphinx cross-reference tag that are now created by ynl_gen_rst.py. Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/netlink/netlink-raw.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/userspace-api/netlink/netlink-raw.rst b/Document= ation/userspace-api/netlink/netlink-raw.rst index 31fc91020eb3..aae296c170c5 100644 --- a/Documentation/userspace-api/netlink/netlink-raw.rst +++ b/Documentation/userspace-api/netlink/netlink-raw.rst @@ -62,8 +62,8 @@ Sub-messages ------------ =20 Several raw netlink families such as -:doc:`rt-link<../../networking/netlink_spec/rt-link>` and -:doc:`tc<../../networking/netlink_spec/tc>` use attribute nesting as an +:ref:`rt-link` and +:ref:`tc` use attribute nesting as an abstraction to carry module specific information. =20 Conceptually it looks as follows:: @@ -162,7 +162,7 @@ then this is an error. Nested struct definitions ------------------------- =20 -Many raw netlink families such as :doc:`tc<../../networking/netlink_spec/t= c>` +Many raw netlink families such as :ref:`tc` make use of nested struct definitions. The ``netlink-raw`` schema makes it possible to embed a struct within a struct definition using the ``struct`` property. For example, the following struct definition embeds the --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 634731E991B; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=EN9SnkiHKDs7aJQ63AT5BrmyXEzqaZNfrB+6zZGcCUfq/Ybo0pPNn7bKokvT3+8l5hdbiQ32s3dUXKI0Aqv4pIi6Tj/5iVY4ZMIQh/83eboYdrj1QlkMeYWyyURnrD7Gpe+8Un05V8soJN/LAqRdl7v9I5+DWzul/PtitfV397s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=nVMNn0VSngYDSLAUJezTR2b19OzJ86I1XkvSWoGjSbY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ATgnxt1+Qz4CYs9vMj0eZmCnzG7v28Q470sf9rYATzacCxKyYFH9MkHGHP1aWLl7lOwG1/tQkgrHuDBWEDFTTkoUkEjvbHsDZCZ8fU5Eb1aDvHZPgXrwBlqGNAu/qyrMOI+gFIfoeUikNhwYY0WeQGEQaDn8gcB8aKSGOhWq4vM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dVjE2+p6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dVjE2+p6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E23C8C4CEF0; Sat, 14 Jun 2025 08:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=nVMNn0VSngYDSLAUJezTR2b19OzJ86I1XkvSWoGjSbY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dVjE2+p6DMNi0/6HW/eClvFnJuABscnX65t/MQFmNMtpkuKkOnjin6f2iw9AQTLke xPqX+NBm6gUv6VohevhM87xaVRsLKE7Gg6sT+SHkMRhDXDEBG/AnPn3ucar2PQ9ME2 6SOfJXWMNP4XY2FMbt0HB3Xavt6hlp5uYmdJTtA6Vp/KEUHshiKBBmIBFO/Gzj1mmm aMsluO/2zFcQAcFBC3bWmp4FxCr9VfgwuEzEqCny1oivUnAh8a+kkWtRol6Xq1nf7r +XBIVis1Bo0y5LqDT4H7xPtMt88FEyIVyl+Z67TF2CRSyHVlA+YmGQIBf4UkEdVy0s jwjc9bEKamQxA== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064ap-0CB8; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 03/14] docs: netlink: don't ignore generated rst files Date: Sat, 14 Jun 2025 10:55:57 +0200 Message-ID: <1cf12ab4c027cf27decf70a40aafdd0e2f669299.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Currently, the build system generates ReST files inside the source directory. This is not a good idea, specially when we have renames, as make clean won't get rid of them. As the first step to address the issue, stop ignoring those files. This way, we can see exactly what has been produced at build time inside $(srctree): Documentation/networking/netlink_spec/conntrack.rst Documentation/networking/netlink_spec/devlink.rst Documentation/networking/netlink_spec/dpll.rst Documentation/networking/netlink_spec/ethtool.rst Documentation/networking/netlink_spec/fou.rst Documentation/networking/netlink_spec/handshake.rst Documentation/networking/netlink_spec/index.rst Documentation/networking/netlink_spec/lockd.rst Documentation/networking/netlink_spec/mptcp_pm.rst Documentation/networking/netlink_spec/net_shaper.rst Documentation/networking/netlink_spec/netdev.rst Documentation/networking/netlink_spec/nfsd.rst Documentation/networking/netlink_spec/nftables.rst Documentation/networking/netlink_spec/nl80211.rst Documentation/networking/netlink_spec/nlctrl.rst Documentation/networking/netlink_spec/ovs_datapath.rst Documentation/networking/netlink_spec/ovs_flow.rst Documentation/networking/netlink_spec/ovs_vport.rst Documentation/networking/netlink_spec/rt_addr.rst Documentation/networking/netlink_spec/rt_link.rst Documentation/networking/netlink_spec/rt_neigh.rst Documentation/networking/netlink_spec/rt_route.rst Documentation/networking/netlink_spec/rt_rule.rst Documentation/networking/netlink_spec/tc.rst Documentation/networking/netlink_spec/tcp_metrics.rst Documentation/networking/netlink_spec/team.rst Signed-off-by: Mauro Carvalho Chehab --- Documentation/networking/netlink_spec/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Documentation/networking/netlink_spec/.gitignore diff --git a/Documentation/networking/netlink_spec/.gitignore b/Documentati= on/networking/netlink_spec/.gitignore deleted file mode 100644 index 30d85567b592..000000000000 --- a/Documentation/networking/netlink_spec/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.rst --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 634C81EC014; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=dJx0bPIhCzSSKqVD6iRHjQT0mg5uJhpesRToZ+w+meTp2cK+z+7v+WemthGbcIOykSCozQRAxCN/tnHBkzUBRRg1HQajk9b5J8hjDR8IBmim32U6Bv/zZFpZz8d0ImuuhvZuCxYfH3b/UohifOqroOEXsI+sFfr+M+l2sCzQ0Bo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=zjfj2Tm7h9LKUnhgzAVTuVnT8YUaP6pYYIdRhxmKFAc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BJ5qaE24Q7sWn/t0PU3RvwbKi8wSAoxK8DnbS3/jBqB5t5VueTnYXmOsohw8heAc8Wi5wlGl6RLbUNscU881NvV+Jqy3CmmzlUyjEzPQapYuYkfTHXOU/KmS8mCIzo2moNsdWobLAHJcmSOmYtBAO33wX3acpervgWLCK49eZy8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XN8xx+lC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XN8xx+lC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E578EC4CEF1; Sat, 14 Jun 2025 08:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=zjfj2Tm7h9LKUnhgzAVTuVnT8YUaP6pYYIdRhxmKFAc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XN8xx+lChxGcgbZ/ztz2429Ca+3Vh91S/41P+iBhSYgUXxOCXNENr5YO36mz5p5Qr 5BWkw16tgrbiIUcPp7S13/Gl77VY9kk2ygbQN63bxhZFLidlPN/Oowf0EDBjQvaUvx +DOsNDt2bvoKH9r3H9OC9ng+uu6wNAzKctC2Lxp3xfWKlY27zGLQUUQtoErQSFTb4U Zqh9IQjyxvtwmnkya21jQ4Ic47BZLEiUNVkrVD+MPiRs3LrVclJlIdMLloniEKL7F0 i2qTV7k2UGBFK8PYLuWc3kN6SGblRv/qIHNWsRE08Cdqy8W7G/0GNwLlytCSyJkbdI 0TQD+6uNa2hOw== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064at-0Rls; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 04/14] tools: ynl_gen_rst.py: make the index parser more generic Date: Sat, 14 Jun 2025 10:55:58 +0200 Message-ID: <3fb42a4aa79631d69041f6750dc0d55dd3067162.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" It is not a good practice to store build-generated files inside $(srctree), as one may be using O=3D and even have the Kernel on a read-only directory. Change the YAML generation for netlink files to allow it to parse data based on the source or on the object tree. Signed-off-by: Mauro Carvalho Chehab --- tools/net/ynl/pyynl/ynl_gen_rst.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_g= en_rst.py index 7bfb8ceeeefc..b1e5acafb998 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -365,6 +365,7 @@ def parse_arguments() -> argparse.Namespace: =20 parser.add_argument("-v", "--verbose", action=3D"store_true") parser.add_argument("-o", "--output", help=3D"Output file name") + parser.add_argument("-d", "--input_dir", help=3D"YAML input directory") =20 # Index and input are mutually exclusive group =3D parser.add_mutually_exclusive_group() @@ -405,11 +406,14 @@ def write_to_rstfile(content: str, filename: str) -> = None: """Write the generated content into an RST file""" logging.debug("Saving RST file to %s", filename) =20 + dir =3D os.path.dirname(filename) + os.makedirs(dir, exist_ok=3DTrue) + with open(filename, "w", encoding=3D"utf-8") as rst_file: rst_file.write(content) =20 =20 -def generate_main_index_rst(output: str) -> None: +def generate_main_index_rst(output: str, index_dir: str) -> None: """Generate the `networking_spec/index` content and write to the file"= "" lines =3D [] =20 @@ -418,12 +422,18 @@ def generate_main_index_rst(output: str) -> None: lines.append(rst_title("Netlink Family Specifications")) lines.append(rst_toctree(1)) =20 - index_dir =3D os.path.dirname(output) - logging.debug("Looking for .rst files in %s", index_dir) + index_fname =3D os.path.basename(output) + base, ext =3D os.path.splitext(index_fname) + + if not index_dir: + index_dir =3D os.path.dirname(output) + + logging.debug(f"Looking for {ext} files in %s", index_dir) for filename in sorted(os.listdir(index_dir)): - if not filename.endswith(".rst") or filename =3D=3D "index.rst": + if not filename.endswith(ext) or filename =3D=3D index_fname: continue - lines.append(f" {filename.replace('.rst', '')}\n") + base, ext =3D os.path.splitext(filename) + lines.append(f" {base}\n") =20 logging.debug("Writing an index file at %s", output) write_to_rstfile("".join(lines), output) @@ -447,7 +457,7 @@ def main() -> None: =20 if args.index: # Generate the index RST file - generate_main_index_rst(args.output) + generate_main_index_rst(args.output, args.input_dir) =20 =20 if __name__ =3D=3D "__main__": --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B942E29826A; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=fFTf4QpYlzaxnF9Zd2tnlyXm3MTHruliOdhTSkIBnQJUruj8nuIq1BVo3fcCJMrBR+Tf7W0RL5Yz5/jKmFOHl6UqaFMEFVaGQWAqmwHQuR2j6Wft9tmHVEnAhRxyf50nWvGcZLo4PXO3VUbeTptvOrorFNwriKdS5UkHF/RVhx4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=cha/mIMe25mR2f/nu4En+YRz7qL3BMOeexKVvY2Yu/Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NJbcKAOxZxEiHmU4PYgJ5ZO8NvKK9rtrwaVVEvOJzDU0aEynILVD9F5MLDx9/yJ6bRjevwizY0FQs2Fl4SxVKqiq90VetN8gSxDg4/H/AlVT0uLrHOPklrGsacY+VFGgrAkfKA5rtx/RM8aZJkV4VaTTk90sYv9sUXXF/hELerw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KqnZtDHr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KqnZtDHr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 05F9FC4CEF5; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=cha/mIMe25mR2f/nu4En+YRz7qL3BMOeexKVvY2Yu/Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KqnZtDHraGKNNbKbCCAKRMSsQUE0ruP98DMLFAZcNzEAX8sT+t/XibtVUMXGCnntG BZz/Rz66HC6zoE+iT4ciZxuZNYy+xfP7H1WPHGofEte/TQNLXMRlhq9ztUha8a0Mrd LKDcbYhBh9/PHXp2IAlfOb10ZGmV6B50eLueLQYqVxQWQoasVzc8MbKl/8Q49sGEZT rpU+5mL5InGoUnTRJ1s9Eht8EQFTqm5EME3GTgL+mzFcTihOh7dZh4qYvOb7ilRwKn mfhXeea12LG6Hr9CSHDT6w9Qmz/g9lGdW4Vz7coibYC1JzH3fCnUQfhWnqftmwlf+W 6z7ZH7+Nap2IQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064ax-0iCK; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 05/14] tools: ynl_gen_rst.py: Split library from command line tool Date: Sat, 14 Jun 2025 10:55:59 +0200 Message-ID: <440956b08faee14ed22575bea6c7b022666e5402.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" As we'll be using the Netlink specs parser inside a Sphinx extension, move the library part from the command line parser. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- scripts/lib/netlink_yml_parser.py | 391 +++++++++++++++++++++++++++++ tools/net/ynl/pyynl/ynl_gen_rst.py | 374 +-------------------------- 2 files changed, 401 insertions(+), 364 deletions(-) create mode 100755 scripts/lib/netlink_yml_parser.py diff --git a/scripts/lib/netlink_yml_parser.py b/scripts/lib/netlink_yml_pa= rser.py new file mode 100755 index 000000000000..3c15b578f947 --- /dev/null +++ b/scripts/lib/netlink_yml_parser.py @@ -0,0 +1,391 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Script to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This script performs extensive parsing to the Linux kernel's netlink Y= AML + spec files, in an effort to avoid needing to heavily mark up the origi= nal + YAML file. + + This code is split in three big parts: + 1) RST formatters: Use to convert a string to a RST output + 2) Parser helpers: Functions to parse the YAML data structure + 3) Main function and small helpers +""" + +from typing import Any, Dict, List +import os.path +import logging +import yaml + + +SPACE_PER_LEVEL =3D 4 + + +# RST Formatters +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * SPACE_PER_LEVEL) + + +def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" + + +def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" + + +def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple lines + return str(text).replace("\n", " ").strip() + + +def rst_fields(key: str, value: str, level: int =3D 0) -> str: + """Return a RST formatted field""" + return headroom(level) + f":{key}: {value}" + + +def rst_definition(key: str, value: Any, level: int =3D 0) -> str: + """Format a single rst definition""" + return headroom(level) + key + "\n" + headroom(level + 1) + str(value) + + +def rst_paragraph(paragraph: str, level: int =3D 0) -> str: + """Return a formatted paragraph""" + return headroom(level) + paragraph + + +def rst_bullet(item: str, level: int =3D 0) -> str: + """Return a formatted a bullet""" + return headroom(level) + f"- {item}" + + +def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) + + +def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) + + +def rst_section(namespace: str, prefix: str, title: str) -> str: + """Add a section to the document""" + return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=3D" * len= (title) + + +def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "= \n\n" + + +def rst_title(title: str) -> str: + """Add a title to the document""" + return "=3D" * len(title) + f"\n{title}\n" + "=3D" * len(title) + "\n\= n" + + +def rst_list_inline(list_: List[str], level: int =3D 0) -> str: + """Format a list using inlines""" + return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "= ]" + + +def rst_ref(namespace: str, prefix: str, name: str) -> str: + """Add a hyperlink to the document""" + mappings =3D {'enum': 'definition', + 'fixed-header': 'definition', + 'nested-attributes': 'attribute-set', + 'struct': 'definition'} + if prefix in mappings: + prefix =3D mappings[prefix] + return f":ref:`{namespace}-{prefix}-{name}`" + + +def rst_header() -> str: + """The headers for all the auto generated RST files""" + lines =3D [] + + lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) + lines.append(rst_paragraph(".. NOTE: This document was auto-generated.= \n\n")) + + return "\n".join(lines) + + +def rst_toctree(maxdepth: int =3D 2) -> str: + """Generate a toctree RST primitive""" + lines =3D [] + + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") + + return "\n".join(lines) + + +def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" + + +# Parsers +# =3D=3D=3D=3D=3D=3D=3D + + +def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines =3D [] + for group in mcast_group: + lines.append(rst_bullet(group["name"])) + + return "\n".join(lines) + + +def parse_do(do_dict: Dict[str, Any], level: int =3D 0) -> str: + """Parse 'do' section and return a formatted string""" + lines =3D [] + for key in do_dict.keys(): + lines.append(rst_paragraph(bold(key), level + 1)) + if key in ['request', 'reply']: + lines.append(parse_do_attributes(do_dict[key], level + 1) + "\= n") + else: + lines.append(headroom(level + 2) + do_dict[key] + "\n") + + return "\n".join(lines) + + +def parse_do_attributes(attrs: Dict[str, Any], level: int =3D 0) -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines =3D [rst_fields("attributes", rst_list_inline(attrs["attributes"= ]), level + 1)] + + return "\n".join(lines) + + +def parse_operations(operations: List[Dict[str, Any]], namespace: str) -> = str: + """Parse operations block""" + preprocessed =3D ["name", "doc", "title", "do", "dump", "flags"] + linkable =3D ["fixed-header", "attribute-set"] + lines =3D [] + + for operation in operations: + lines.append(rst_section(namespace, 'operation', operation["name"]= )) + lines.append(rst_paragraph(operation["doc"]) + "\n") + + for key in operation.keys(): + if key in preprocessed: + # Skip the special fields + continue + value =3D operation[key] + if key in linkable: + value =3D rst_ref(namespace, key, value) + lines.append(rst_fields(key, value, 0)) + if 'flags' in operation: + lines.append(rst_fields('flags', rst_list_inline(operation['fl= ags']))) + + if "do" in operation: + lines.append(rst_paragraph(":do:", 0)) + lines.append(parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(rst_paragraph(":dump:", 0)) + lines.append(parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + +def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: + """Parse a list of entries""" + ignored =3D ["pad"] + lines =3D [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + field_name =3D entry.get("name", "") + if field_name in ignored: + continue + type_ =3D entry.get("type") + if type_: + field_name +=3D f" ({inline(type_)})" + lines.append( + rst_fields(field_name, sanitize(entry.get("doc", "")), lev= el) + ) + elif isinstance(entry, list): + lines.append(rst_list_inline(entry, level)) + else: + lines.append(rst_bullet(inline(sanitize(entry)), level)) + + lines.append("\n") + return "\n".join(lines) + + +def parse_definitions(defs: Dict[str, Any], namespace: str) -> str: + """Parse definitions section""" + preprocessed =3D ["name", "entries", "members"] + ignored =3D ["render-max"] # This is not printed + lines =3D [] + + for definition in defs: + lines.append(rst_section(namespace, 'definition', definition["name= "])) + for k in definition.keys(): + if k in preprocessed + ignored: + continue + lines.append(rst_fields(k, sanitize(definition[k]), 0)) + + # Field list needs to finish with a new line + lines.append("\n") + if "entries" in definition: + lines.append(rst_paragraph(":entries:", 0)) + lines.append(parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(rst_paragraph(":members:", 0)) + lines.append(parse_entries(definition["members"], 1)) + + return "\n".join(lines) + + +def parse_attr_sets(entries: List[Dict[str, Any]], namespace: str) -> str: + """Parse attribute from attribute-set""" + preprocessed =3D ["name", "type"] + linkable =3D ["enum", "nested-attributes", "struct", "sub-message"] + ignored =3D ["checks"] + lines =3D [] + + for entry in entries: + lines.append(rst_section(namespace, 'attribute-set', entry["name"]= )) + for attr in entry["attributes"]: + type_ =3D attr.get("type") + attr_line =3D attr["name"] + if type_: + # Add the attribute type in the same line + attr_line +=3D f" ({inline(type_)})" + + lines.append(rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k in preprocessed + ignored: + continue + if k in linkable: + value =3D rst_ref(namespace, k, attr[k]) + else: + value =3D sanitize(attr[k]) + lines.append(rst_fields(k, value, 0)) + lines.append("\n") + + return "\n".join(lines) + + +def parse_sub_messages(entries: List[Dict[str, Any]], namespace: str) -> s= tr: + """Parse sub-message definitions""" + lines =3D [] + + for entry in entries: + lines.append(rst_section(namespace, 'sub-message', entry["name"])) + for fmt in entry["formats"]: + value =3D fmt["value"] + + lines.append(rst_bullet(bold(value))) + for attr in ['fixed-header', 'attribute-set']: + if attr in fmt: + lines.append(rst_fields(attr, + rst_ref(namespace, attr, fmt[a= ttr]), + 1)) + lines.append("\n") + + return "\n".join(lines) + + +def parse_yaml(obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines =3D [] + + # Main header + + family =3D obj['name'] + + lines.append(rst_header()) + lines.append(rst_label("netlink-" + family)) + + title =3D f"Family ``{family}`` netlink specification" + lines.append(rst_title(title)) + lines.append(rst_paragraph(".. contents:: :depth: 3\n")) + + if "doc" in obj: + lines.append(rst_subtitle("Summary")) + lines.append(rst_paragraph(obj["doc"], 0)) + + # Operations + if "operations" in obj: + lines.append(rst_subtitle("Operations")) + lines.append(parse_operations(obj["operations"]["list"], family)) + + # Multicast groups + if "mcast-groups" in obj: + lines.append(rst_subtitle("Multicast groups")) + lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) + + # Definitions + if "definitions" in obj: + lines.append(rst_subtitle("Definitions")) + lines.append(parse_definitions(obj["definitions"], family)) + + # Attributes set + if "attribute-sets" in obj: + lines.append(rst_subtitle("Attribute sets")) + lines.append(parse_attr_sets(obj["attribute-sets"], family)) + + # Sub-messages + if "sub-messages" in obj: + lines.append(rst_subtitle("Sub-messages")) + lines.append(parse_sub_messages(obj["sub-messages"], family)) + + return "\n".join(lines) + + +# Main functions +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +def parse_yaml_file(filename: str) -> str: + """Transform the YAML specified by filename into an RST-formatted stri= ng""" + with open(filename, "r", encoding=3D"utf-8") as spec_file: + yaml_data =3D yaml.safe_load(spec_file) + content =3D parse_yaml(yaml_data) + + return content + + +def generate_main_index_rst(output: str, index_dir: str) -> str: + """Generate the `networking_spec/index` content and write to the file"= "" + lines =3D [] + + lines.append(rst_header()) + lines.append(rst_label("specs")) + lines.append(rst_title("Netlink Family Specifications")) + lines.append(rst_toctree(1)) + + index_fname =3D os.path.basename(output) + base, ext =3D os.path.splitext(index_fname) + + if not index_dir: + index_dir =3D os.path.dirname(output) + + logging.debug(f"Looking for {ext} files in %s", index_dir) + for filename in sorted(os.listdir(index_dir)): + if not filename.endswith(ext) or filename =3D=3D index_fname: + continue + base, ext =3D os.path.splitext(filename) + lines.append(f" {base}\n") + + return "".join(lines), output diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_g= en_rst.py index b1e5acafb998..38dafe3d9179 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -18,345 +18,17 @@ 3) Main function and small helpers """ =20 -from typing import Any, Dict, List import os.path import sys import argparse import logging -import yaml =20 +LIB_DIR =3D "../../../../scripts/lib" +SRC_DIR =3D os.path.dirname(os.path.realpath(__file__)) =20 -SPACE_PER_LEVEL =3D 4 +sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) =20 - -# RST Formatters -# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -def headroom(level: int) -> str: - """Return space to format""" - return " " * (level * SPACE_PER_LEVEL) - - -def bold(text: str) -> str: - """Format bold text""" - return f"**{text}**" - - -def inline(text: str) -> str: - """Format inline text""" - return f"``{text}``" - - -def sanitize(text: str) -> str: - """Remove newlines and multiple spaces""" - # This is useful for some fields that are spread across multiple lines - return str(text).replace("\n", " ").strip() - - -def rst_fields(key: str, value: str, level: int =3D 0) -> str: - """Return a RST formatted field""" - return headroom(level) + f":{key}: {value}" - - -def rst_definition(key: str, value: Any, level: int =3D 0) -> str: - """Format a single rst definition""" - return headroom(level) + key + "\n" + headroom(level + 1) + str(value) - - -def rst_paragraph(paragraph: str, level: int =3D 0) -> str: - """Return a formatted paragraph""" - return headroom(level) + paragraph - - -def rst_bullet(item: str, level: int =3D 0) -> str: - """Return a formatted a bullet""" - return headroom(level) + f"- {item}" - - -def rst_subsection(title: str) -> str: - """Add a sub-section to the document""" - return f"{title}\n" + "-" * len(title) - - -def rst_subsubsection(title: str) -> str: - """Add a sub-sub-section to the document""" - return f"{title}\n" + "~" * len(title) - - -def rst_section(namespace: str, prefix: str, title: str) -> str: - """Add a section to the document""" - return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=3D" * len= (title) - - -def rst_subtitle(title: str) -> str: - """Add a subtitle to the document""" - return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "= \n\n" - - -def rst_title(title: str) -> str: - """Add a title to the document""" - return "=3D" * len(title) + f"\n{title}\n" + "=3D" * len(title) + "\n\= n" - - -def rst_list_inline(list_: List[str], level: int =3D 0) -> str: - """Format a list using inlines""" - return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "= ]" - - -def rst_ref(namespace: str, prefix: str, name: str) -> str: - """Add a hyperlink to the document""" - mappings =3D {'enum': 'definition', - 'fixed-header': 'definition', - 'nested-attributes': 'attribute-set', - 'struct': 'definition'} - if prefix in mappings: - prefix =3D mappings[prefix] - return f":ref:`{namespace}-{prefix}-{name}`" - - -def rst_header() -> str: - """The headers for all the auto generated RST files""" - lines =3D [] - - lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) - lines.append(rst_paragraph(".. NOTE: This document was auto-generated.= \n\n")) - - return "\n".join(lines) - - -def rst_toctree(maxdepth: int =3D 2) -> str: - """Generate a toctree RST primitive""" - lines =3D [] - - lines.append(".. toctree::") - lines.append(f" :maxdepth: {maxdepth}\n\n") - - return "\n".join(lines) - - -def rst_label(title: str) -> str: - """Return a formatted label""" - return f".. _{title}:\n\n" - - -# Parsers -# =3D=3D=3D=3D=3D=3D=3D - - -def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: - """Parse 'multicast' group list and return a formatted string""" - lines =3D [] - for group in mcast_group: - lines.append(rst_bullet(group["name"])) - - return "\n".join(lines) - - -def parse_do(do_dict: Dict[str, Any], level: int =3D 0) -> str: - """Parse 'do' section and return a formatted string""" - lines =3D [] - for key in do_dict.keys(): - lines.append(rst_paragraph(bold(key), level + 1)) - if key in ['request', 'reply']: - lines.append(parse_do_attributes(do_dict[key], level + 1) + "\= n") - else: - lines.append(headroom(level + 2) + do_dict[key] + "\n") - - return "\n".join(lines) - - -def parse_do_attributes(attrs: Dict[str, Any], level: int =3D 0) -> str: - """Parse 'attributes' section""" - if "attributes" not in attrs: - return "" - lines =3D [rst_fields("attributes", rst_list_inline(attrs["attributes"= ]), level + 1)] - - return "\n".join(lines) - - -def parse_operations(operations: List[Dict[str, Any]], namespace: str) -> = str: - """Parse operations block""" - preprocessed =3D ["name", "doc", "title", "do", "dump", "flags"] - linkable =3D ["fixed-header", "attribute-set"] - lines =3D [] - - for operation in operations: - lines.append(rst_section(namespace, 'operation', operation["name"]= )) - lines.append(rst_paragraph(operation["doc"]) + "\n") - - for key in operation.keys(): - if key in preprocessed: - # Skip the special fields - continue - value =3D operation[key] - if key in linkable: - value =3D rst_ref(namespace, key, value) - lines.append(rst_fields(key, value, 0)) - if 'flags' in operation: - lines.append(rst_fields('flags', rst_list_inline(operation['fl= ags']))) - - if "do" in operation: - lines.append(rst_paragraph(":do:", 0)) - lines.append(parse_do(operation["do"], 0)) - if "dump" in operation: - lines.append(rst_paragraph(":dump:", 0)) - lines.append(parse_do(operation["dump"], 0)) - - # New line after fields - lines.append("\n") - - return "\n".join(lines) - - -def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: - """Parse a list of entries""" - ignored =3D ["pad"] - lines =3D [] - for entry in entries: - if isinstance(entry, dict): - # entries could be a list or a dictionary - field_name =3D entry.get("name", "") - if field_name in ignored: - continue - type_ =3D entry.get("type") - if type_: - field_name +=3D f" ({inline(type_)})" - lines.append( - rst_fields(field_name, sanitize(entry.get("doc", "")), lev= el) - ) - elif isinstance(entry, list): - lines.append(rst_list_inline(entry, level)) - else: - lines.append(rst_bullet(inline(sanitize(entry)), level)) - - lines.append("\n") - return "\n".join(lines) - - -def parse_definitions(defs: Dict[str, Any], namespace: str) -> str: - """Parse definitions section""" - preprocessed =3D ["name", "entries", "members"] - ignored =3D ["render-max"] # This is not printed - lines =3D [] - - for definition in defs: - lines.append(rst_section(namespace, 'definition', definition["name= "])) - for k in definition.keys(): - if k in preprocessed + ignored: - continue - lines.append(rst_fields(k, sanitize(definition[k]), 0)) - - # Field list needs to finish with a new line - lines.append("\n") - if "entries" in definition: - lines.append(rst_paragraph(":entries:", 0)) - lines.append(parse_entries(definition["entries"], 1)) - if "members" in definition: - lines.append(rst_paragraph(":members:", 0)) - lines.append(parse_entries(definition["members"], 1)) - - return "\n".join(lines) - - -def parse_attr_sets(entries: List[Dict[str, Any]], namespace: str) -> str: - """Parse attribute from attribute-set""" - preprocessed =3D ["name", "type"] - linkable =3D ["enum", "nested-attributes", "struct", "sub-message"] - ignored =3D ["checks"] - lines =3D [] - - for entry in entries: - lines.append(rst_section(namespace, 'attribute-set', entry["name"]= )) - for attr in entry["attributes"]: - type_ =3D attr.get("type") - attr_line =3D attr["name"] - if type_: - # Add the attribute type in the same line - attr_line +=3D f" ({inline(type_)})" - - lines.append(rst_subsubsection(attr_line)) - - for k in attr.keys(): - if k in preprocessed + ignored: - continue - if k in linkable: - value =3D rst_ref(namespace, k, attr[k]) - else: - value =3D sanitize(attr[k]) - lines.append(rst_fields(k, value, 0)) - lines.append("\n") - - return "\n".join(lines) - - -def parse_sub_messages(entries: List[Dict[str, Any]], namespace: str) -> s= tr: - """Parse sub-message definitions""" - lines =3D [] - - for entry in entries: - lines.append(rst_section(namespace, 'sub-message', entry["name"])) - for fmt in entry["formats"]: - value =3D fmt["value"] - - lines.append(rst_bullet(bold(value))) - for attr in ['fixed-header', 'attribute-set']: - if attr in fmt: - lines.append(rst_fields(attr, - rst_ref(namespace, attr, fmt[a= ttr]), - 1)) - lines.append("\n") - - return "\n".join(lines) - - -def parse_yaml(obj: Dict[str, Any]) -> str: - """Format the whole YAML into a RST string""" - lines =3D [] - - # Main header - - family =3D obj['name'] - - lines.append(rst_header()) - lines.append(rst_label("netlink-" + family)) - - title =3D f"Family ``{family}`` netlink specification" - lines.append(rst_title(title)) - lines.append(rst_paragraph(".. contents:: :depth: 3\n")) - - if "doc" in obj: - lines.append(rst_subtitle("Summary")) - lines.append(rst_paragraph(obj["doc"], 0)) - - # Operations - if "operations" in obj: - lines.append(rst_subtitle("Operations")) - lines.append(parse_operations(obj["operations"]["list"], family)) - - # Multicast groups - if "mcast-groups" in obj: - lines.append(rst_subtitle("Multicast groups")) - lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) - - # Definitions - if "definitions" in obj: - lines.append(rst_subtitle("Definitions")) - lines.append(parse_definitions(obj["definitions"], family)) - - # Attributes set - if "attribute-sets" in obj: - lines.append(rst_subtitle("Attribute sets")) - lines.append(parse_attr_sets(obj["attribute-sets"], family)) - - # Sub-messages - if "sub-messages" in obj: - lines.append(rst_subtitle("Sub-messages")) - lines.append(parse_sub_messages(obj["sub-messages"], family)) - - return "\n".join(lines) - - -# Main functions -# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +from netlink_yml_parser import parse_yaml_file, generate_main_index_rst =20 =20 def parse_arguments() -> argparse.Namespace: @@ -393,50 +65,24 @@ def parse_arguments() -> argparse.Namespace: return args =20 =20 -def parse_yaml_file(filename: str) -> str: - """Transform the YAML specified by filename into an RST-formatted stri= ng""" - with open(filename, "r", encoding=3D"utf-8") as spec_file: - yaml_data =3D yaml.safe_load(spec_file) - content =3D parse_yaml(yaml_data) - - return content - - def write_to_rstfile(content: str, filename: str) -> None: """Write the generated content into an RST file""" logging.debug("Saving RST file to %s", filename) =20 - dir =3D os.path.dirname(filename) - os.makedirs(dir, exist_ok=3DTrue) + directory =3D os.path.dirname(filename) + os.makedirs(directory, exist_ok=3DTrue) =20 with open(filename, "w", encoding=3D"utf-8") as rst_file: rst_file.write(content) =20 =20 -def generate_main_index_rst(output: str, index_dir: str) -> None: +def write_index_rst(output: str, index_dir: str) -> None: """Generate the `networking_spec/index` content and write to the file"= "" - lines =3D [] =20 - lines.append(rst_header()) - lines.append(rst_label("specs")) - lines.append(rst_title("Netlink Family Specifications")) - lines.append(rst_toctree(1)) - - index_fname =3D os.path.basename(output) - base, ext =3D os.path.splitext(index_fname) - - if not index_dir: - index_dir =3D os.path.dirname(output) - - logging.debug(f"Looking for {ext} files in %s", index_dir) - for filename in sorted(os.listdir(index_dir)): - if not filename.endswith(ext) or filename =3D=3D index_fname: - continue - base, ext =3D os.path.splitext(filename) - lines.append(f" {base}\n") + msg =3D generate_main_index_rst(output, index_dir) =20 logging.debug("Writing an index file at %s", output) - write_to_rstfile("".join(lines), output) + write_to_rstfile(msg, output) =20 =20 def main() -> None: @@ -457,7 +103,7 @@ def main() -> None: =20 if args.index: # Generate the index RST file - generate_main_index_rst(args.output, args.input_dir) + write_index_rst(args.output, args.input_dir) =20 =20 if __name__ =3D=3D "__main__": --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A13E72980B8; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=gt7k4G14sQlTmsQX8cFFuZSZmwn7ux80DssBE4pfNJNy4/orKeKS7AyrxEA4j4DVwD04hZ+7rf4eKEI5qube2yo6BJGy+aP9vdbiFqbnQyhwte2ebrbFM/UPElI1Re4hJZZZhv8H0brncx07DCFuEfODdMOVc2Or/RBv9zOQS/A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=zezmn1agOmBkNvCAyVvPw67aKKtSSawUdLiTAnWFFpE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iPbUEZNMFQy3VwcIeti3phzywMrLeuD1A6wsuejQPjGVgwhYjceHrX1F+gxvWIsYPVoAbT4v5IVxQbYTyt6sOlboniuiefAV5yA71+1N6g8YDLQUc3zH+aES1tBAINTT3OZ2vNe/WNU4UE73RySu1yNYmc3yg9eUHSkEO8UdvoE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RyQLl55w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RyQLl55w" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0052CC4CEF3; Sat, 14 Jun 2025 08:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=zezmn1agOmBkNvCAyVvPw67aKKtSSawUdLiTAnWFFpE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RyQLl55wFVt23uwSTPA0U4gGOYStkAWXCyip50q97WQ08MsaZO8a0mdVfjSYWtyzy Aibs9Cx3fm4XjKAqxgDdfAnxtJ3UCz7KTWonI3ikpGKwMJ0Qyhsz58Fazu29/+jT22 1BOqVpv9qHqFTAzwzbJJ6IJoHndPldVM/SvrHANY9PNV/zxJ7JCf85WcnQ9O2vxyY/ NOxreHF5hZF/BlZN56hc/ZB/nwjLfo/fS43VX/BQ5omFbRPLb4ZSHlyXvkq2FeWHk0 r+jDAdzQJ9N2PK8eUUEAQfLXAaVbUczaDWv5hLTbFy1moaHx7NLbYxLIvVMQrFu9r9 sXwpyoxh8QG6w== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064b1-0yuq; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 06/14] scripts: lib: netlink_yml_parser.py: use classes Date: Sat, 14 Jun 2025 10:56:00 +0200 Message-ID: <9b22975b17bf42210f8432cf0832323c03b1c567.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" As we'll be importing netlink parser into a Sphinx extension, move all functions and global variables inside two classes: - RstFormatters, containing ReST formatter logic, which are YAML independent; - NetlinkYamlParser: contains the actual parser classes. That's the only class that needs to be imported by the script or by a Sphinx extension. With that, we won't pollute Sphinx namespace, avoiding any potential clashes. Signed-off-by: Mauro Carvalho Chehab --- scripts/lib/netlink_yml_parser.py | 594 +++++++++++++++-------------- tools/net/ynl/pyynl/ynl_gen_rst.py | 19 +- 2 files changed, 314 insertions(+), 299 deletions(-) diff --git a/scripts/lib/netlink_yml_parser.py b/scripts/lib/netlink_yml_pa= rser.py index 3c15b578f947..839e78b39de3 100755 --- a/scripts/lib/netlink_yml_parser.py +++ b/scripts/lib/netlink_yml_parser.py @@ -3,389 +3,407 @@ # -*- coding: utf-8; mode: python -*- =20 """ - Script to auto generate the documentation for Netlink specifications. + Class to auto generate the documentation for Netlink specifications. =20 :copyright: Copyright (C) 2023 Breno Leitao :license: GPL Version 2, June 1991 see linux/COPYING for details. =20 - This script performs extensive parsing to the Linux kernel's netlink Y= AML + This class performs extensive parsing to the Linux kernel's netlink YA= ML spec files, in an effort to avoid needing to heavily mark up the origi= nal YAML file. =20 - This code is split in three big parts: + This code is split in two classes: 1) RST formatters: Use to convert a string to a RST output - 2) Parser helpers: Functions to parse the YAML data structure - 3) Main function and small helpers + 2) YAML Netlink (YNL) doc generator: Generate docs from YAML data """ =20 from typing import Any, Dict, List import os.path +import sys +import argparse import logging import yaml =20 =20 -SPACE_PER_LEVEL =3D 4 - - +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # RST Formatters # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -def headroom(level: int) -> str: - """Return space to format""" - return " " * (level * SPACE_PER_LEVEL) +class RstFormatters: + SPACE_PER_LEVEL =3D 4 =20 + @staticmethod + def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * RstFormatters.SPACE_PER_LEVEL) =20 -def bold(text: str) -> str: - """Format bold text""" - return f"**{text}**" =20 + @staticmethod + def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" =20 -def inline(text: str) -> str: - """Format inline text""" - return f"``{text}``" =20 + @staticmethod + def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" =20 -def sanitize(text: str) -> str: - """Remove newlines and multiple spaces""" - # This is useful for some fields that are spread across multiple lines - return str(text).replace("\n", " ").strip() =20 + @staticmethod + def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple l= ines + return str(text).replace("\n", " ").strip() =20 -def rst_fields(key: str, value: str, level: int =3D 0) -> str: - """Return a RST formatted field""" - return headroom(level) + f":{key}: {value}" =20 + def rst_fields(self, key: str, value: str, level: int =3D 0) -> str: + """Return a RST formatted field""" + return self.headroom(level) + f":{key}: {value}" =20 -def rst_definition(key: str, value: Any, level: int =3D 0) -> str: - """Format a single rst definition""" - return headroom(level) + key + "\n" + headroom(level + 1) + str(value) =20 + def rst_definition(self, key: str, value: Any, level: int =3D 0) -> st= r: + """Format a single rst definition""" + return self.headroom(level) + key + "\n" + self.headroom(level + 1= ) + str(value) =20 -def rst_paragraph(paragraph: str, level: int =3D 0) -> str: - """Return a formatted paragraph""" - return headroom(level) + paragraph =20 + def rst_paragraph(self, paragraph: str, level: int =3D 0) -> str: + """Return a formatted paragraph""" + return self.headroom(level) + paragraph =20 -def rst_bullet(item: str, level: int =3D 0) -> str: - """Return a formatted a bullet""" - return headroom(level) + f"- {item}" =20 + def rst_bullet(self, item: str, level: int =3D 0) -> str: + """Return a formatted a bullet""" + return self.headroom(level) + f"- {item}" =20 -def rst_subsection(title: str) -> str: - """Add a sub-section to the document""" - return f"{title}\n" + "-" * len(title) =20 + @staticmethod + def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) =20 -def rst_subsubsection(title: str) -> str: - """Add a sub-sub-section to the document""" - return f"{title}\n" + "~" * len(title) =20 + @staticmethod + def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) =20 -def rst_section(namespace: str, prefix: str, title: str) -> str: - """Add a section to the document""" - return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=3D" * len= (title) =20 + @staticmethod + def rst_section(namespace: str, prefix: str, title: str) -> str: + """Add a section to the document""" + return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=3D" *= len(title) =20 -def rst_subtitle(title: str) -> str: - """Add a subtitle to the document""" - return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "= \n\n" =20 + @staticmethod + def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title)= + "\n\n" =20 -def rst_title(title: str) -> str: - """Add a title to the document""" - return "=3D" * len(title) + f"\n{title}\n" + "=3D" * len(title) + "\n\= n" =20 + @staticmethod + def rst_title(title: str) -> str: + """Add a title to the document""" + return "=3D" * len(title) + f"\n{title}\n" + "=3D" * len(title) + = "\n\n" =20 -def rst_list_inline(list_: List[str], level: int =3D 0) -> str: - """Format a list using inlines""" - return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "= ]" =20 + def rst_list_inline(self, list_: List[str], level: int =3D 0) -> str: + """Format a list using inlines""" + return self.headroom(level) + "[" + ", ".join(self.inline(i) for i= in list_) + "]" =20 -def rst_ref(namespace: str, prefix: str, name: str) -> str: - """Add a hyperlink to the document""" - mappings =3D {'enum': 'definition', - 'fixed-header': 'definition', - 'nested-attributes': 'attribute-set', - 'struct': 'definition'} - if prefix in mappings: - prefix =3D mappings[prefix] - return f":ref:`{namespace}-{prefix}-{name}`" =20 + @staticmethod + def rst_ref(namespace: str, prefix: str, name: str) -> str: + """Add a hyperlink to the document""" + mappings =3D {'enum': 'definition', + 'fixed-header': 'definition', + 'nested-attributes': 'attribute-set', + 'struct': 'definition'} + if prefix in mappings: + prefix =3D mappings[prefix] + return f":ref:`{namespace}-{prefix}-{name}`" =20 -def rst_header() -> str: - """The headers for all the auto generated RST files""" - lines =3D [] =20 - lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) - lines.append(rst_paragraph(".. NOTE: This document was auto-generated.= \n\n")) + def rst_header(self) -> str: + """The headers for all the auto generated RST files""" + lines =3D [] =20 - return "\n".join(lines) + lines.append(self.rst_paragraph(".. SPDX-License-Identifier: GPL-2= .0")) + lines.append(self.rst_paragraph(".. NOTE: This document was auto-g= enerated.\n\n")) =20 + return "\n".join(lines) =20 -def rst_toctree(maxdepth: int =3D 2) -> str: - """Generate a toctree RST primitive""" - lines =3D [] =20 - lines.append(".. toctree::") - lines.append(f" :maxdepth: {maxdepth}\n\n") + @staticmethod + def rst_toctree(maxdepth: int =3D 2) -> str: + """Generate a toctree RST primitive""" + lines =3D [] =20 - return "\n".join(lines) + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") =20 + return "\n".join(lines) =20 -def rst_label(title: str) -> str: - """Return a formatted label""" - return f".. _{title}:\n\n" =20 + @staticmethod + def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" =20 +# =3D=3D=3D=3D=3D=3D=3D # Parsers # =3D=3D=3D=3D=3D=3D=3D +class YnlDocGenerator: + + fmt =3D RstFormatters() + + def parse_mcast_group(self, mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines =3D [] + for group in mcast_group: + lines.append(self.fmt.rst_bullet(group["name"])) + + return "\n".join(lines) + + + def parse_do(self, do_dict: Dict[str, Any], level: int =3D 0) -> str: + """Parse 'do' section and return a formatted string""" + lines =3D [] + for key in do_dict.keys(): + lines.append(self.fmt.rst_paragraph(self.fmt.bold(key), level = + 1)) + if key in ['request', 'reply']: + lines.append(self.parse_do_attributes(do_dict[key], level = + 1) + "\n") + else: + lines.append(self.fmt.headroom(level + 2) + do_dict[key] += "\n") + + return "\n".join(lines) + + + def parse_do_attributes(self, attrs: Dict[str, Any], level: int =3D 0)= -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines =3D [self.fmt.rst_fields("attributes", self.fmt.rst_list_inl= ine(attrs["attributes"]), level + 1)] + + return "\n".join(lines) + + + def parse_operations(self, operations: List[Dict[str, Any]], namespace= : str) -> str: + """Parse operations block""" + preprocessed =3D ["name", "doc", "title", "do", "dump", "flags"] + linkable =3D ["fixed-header", "attribute-set"] + lines =3D [] + + for operation in operations: + lines.append(self.fmt.rst_section(namespace, 'operation', oper= ation["name"])) + lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") + + for key in operation.keys(): + if key in preprocessed: + # Skip the special fields + continue + value =3D operation[key] + if key in linkable: + value =3D self.fmt.rst_ref(namespace, key, value) + lines.append(self.fmt.rst_fields(key, value, 0)) + if 'flags' in operation: + lines.append(self.fmt.rst_fields('flags', self.fmt.rst_lis= t_inline(operation['flags']))) + + if "do" in operation: + lines.append(self.fmt.rst_paragraph(":do:", 0)) + lines.append(self.parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(self.fmt.rst_paragraph(":dump:", 0)) + lines.append(self.parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + + def parse_entries(self, entries: List[Dict[str, Any]], level: int) -> = str: + """Parse a list of entries""" + ignored =3D ["pad"] + lines =3D [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + field_name =3D entry.get("name", "") + if field_name in ignored: + continue + type_ =3D entry.get("type") + if type_: + field_name +=3D f" ({self.fmt.inline(type_)})" + lines.append( + self.fmt.rst_fields(field_name, self.fmt.sanitize(entr= y.get("doc", "")), level) + ) + elif isinstance(entry, list): + lines.append(self.fmt.rst_list_inline(entry, level)) + else: + lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.= sanitize(entry)), level)) =20 + lines.append("\n") + return "\n".join(lines) =20 -def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: - """Parse 'multicast' group list and return a formatted string""" - lines =3D [] - for group in mcast_group: - lines.append(rst_bullet(group["name"])) - - return "\n".join(lines) - - -def parse_do(do_dict: Dict[str, Any], level: int =3D 0) -> str: - """Parse 'do' section and return a formatted string""" - lines =3D [] - for key in do_dict.keys(): - lines.append(rst_paragraph(bold(key), level + 1)) - if key in ['request', 'reply']: - lines.append(parse_do_attributes(do_dict[key], level + 1) + "\= n") - else: - lines.append(headroom(level + 2) + do_dict[key] + "\n") - - return "\n".join(lines) - - -def parse_do_attributes(attrs: Dict[str, Any], level: int =3D 0) -> str: - """Parse 'attributes' section""" - if "attributes" not in attrs: - return "" - lines =3D [rst_fields("attributes", rst_list_inline(attrs["attributes"= ]), level + 1)] - - return "\n".join(lines) - - -def parse_operations(operations: List[Dict[str, Any]], namespace: str) -> = str: - """Parse operations block""" - preprocessed =3D ["name", "doc", "title", "do", "dump", "flags"] - linkable =3D ["fixed-header", "attribute-set"] - lines =3D [] - - for operation in operations: - lines.append(rst_section(namespace, 'operation', operation["name"]= )) - lines.append(rst_paragraph(operation["doc"]) + "\n") - - for key in operation.keys(): - if key in preprocessed: - # Skip the special fields - continue - value =3D operation[key] - if key in linkable: - value =3D rst_ref(namespace, key, value) - lines.append(rst_fields(key, value, 0)) - if 'flags' in operation: - lines.append(rst_fields('flags', rst_list_inline(operation['fl= ags']))) - - if "do" in operation: - lines.append(rst_paragraph(":do:", 0)) - lines.append(parse_do(operation["do"], 0)) - if "dump" in operation: - lines.append(rst_paragraph(":dump:", 0)) - lines.append(parse_do(operation["dump"], 0)) =20 - # New line after fields - lines.append("\n") + def parse_definitions(self, defs: Dict[str, Any], namespace: str) -> s= tr: + """Parse definitions section""" + preprocessed =3D ["name", "entries", "members"] + ignored =3D ["render-max"] # This is not printed + lines =3D [] =20 - return "\n".join(lines) - - -def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: - """Parse a list of entries""" - ignored =3D ["pad"] - lines =3D [] - for entry in entries: - if isinstance(entry, dict): - # entries could be a list or a dictionary - field_name =3D entry.get("name", "") - if field_name in ignored: - continue - type_ =3D entry.get("type") - if type_: - field_name +=3D f" ({inline(type_)})" - lines.append( - rst_fields(field_name, sanitize(entry.get("doc", "")), lev= el) - ) - elif isinstance(entry, list): - lines.append(rst_list_inline(entry, level)) - else: - lines.append(rst_bullet(inline(sanitize(entry)), level)) - - lines.append("\n") - return "\n".join(lines) - - -def parse_definitions(defs: Dict[str, Any], namespace: str) -> str: - """Parse definitions section""" - preprocessed =3D ["name", "entries", "members"] - ignored =3D ["render-max"] # This is not printed - lines =3D [] - - for definition in defs: - lines.append(rst_section(namespace, 'definition', definition["name= "])) - for k in definition.keys(): - if k in preprocessed + ignored: - continue - lines.append(rst_fields(k, sanitize(definition[k]), 0)) - - # Field list needs to finish with a new line - lines.append("\n") - if "entries" in definition: - lines.append(rst_paragraph(":entries:", 0)) - lines.append(parse_entries(definition["entries"], 1)) - if "members" in definition: - lines.append(rst_paragraph(":members:", 0)) - lines.append(parse_entries(definition["members"], 1)) - - return "\n".join(lines) - - -def parse_attr_sets(entries: List[Dict[str, Any]], namespace: str) -> str: - """Parse attribute from attribute-set""" - preprocessed =3D ["name", "type"] - linkable =3D ["enum", "nested-attributes", "struct", "sub-message"] - ignored =3D ["checks"] - lines =3D [] - - for entry in entries: - lines.append(rst_section(namespace, 'attribute-set', entry["name"]= )) - for attr in entry["attributes"]: - type_ =3D attr.get("type") - attr_line =3D attr["name"] - if type_: - # Add the attribute type in the same line - attr_line +=3D f" ({inline(type_)})" - - lines.append(rst_subsubsection(attr_line)) - - for k in attr.keys(): + for definition in defs: + lines.append(self.fmt.rst_section(namespace, 'definition', def= inition["name"])) + for k in definition.keys(): if k in preprocessed + ignored: continue - if k in linkable: - value =3D rst_ref(namespace, k, attr[k]) - else: - value =3D sanitize(attr[k]) - lines.append(rst_fields(k, value, 0)) + lines.append(self.fmt.rst_fields(k, self.fmt.sanitize(defi= nition[k]), 0)) + + # Field list needs to finish with a new line lines.append("\n") + if "entries" in definition: + lines.append(self.fmt.rst_paragraph(":entries:", 0)) + lines.append(self.parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(self.fmt.rst_paragraph(":members:", 0)) + lines.append(self.parse_entries(definition["members"], 1)) =20 - return "\n".join(lines) + return "\n".join(lines) =20 =20 -def parse_sub_messages(entries: List[Dict[str, Any]], namespace: str) -> s= tr: - """Parse sub-message definitions""" - lines =3D [] + def parse_attr_sets(self, entries: List[Dict[str, Any]], namespace: st= r) -> str: + """Parse attribute from attribute-set""" + preprocessed =3D ["name", "type"] + linkable =3D ["enum", "nested-attributes", "struct", "sub-message"] + ignored =3D ["checks"] + lines =3D [] =20 - for entry in entries: - lines.append(rst_section(namespace, 'sub-message', entry["name"])) - for fmt in entry["formats"]: - value =3D fmt["value"] + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'attribute-set', = entry["name"])) + for attr in entry["attributes"]: + type_ =3D attr.get("type") + attr_line =3D attr["name"] + if type_: + # Add the attribute type in the same line + attr_line +=3D f" ({self.fmt.inline(type_)})" =20 - lines.append(rst_bullet(bold(value))) - for attr in ['fixed-header', 'attribute-set']: - if attr in fmt: - lines.append(rst_fields(attr, - rst_ref(namespace, attr, fmt[a= ttr]), - 1)) - lines.append("\n") + lines.append(self.fmt.rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k in preprocessed + ignored: + continue + if k in linkable: + value =3D self.fmt.rst_ref(namespace, k, attr[k]) + else: + value =3D self.fmt.sanitize(attr[k]) + lines.append(self.fmt.rst_fields(k, value, 0)) + lines.append("\n") + + return "\n".join(lines) + + + def parse_sub_messages(self, entries: List[Dict[str, Any]], namespace:= str) -> str: + """Parse sub-message definitions""" + lines =3D [] + + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'sub-message', en= try["name"])) + for fmt in entry["formats"]: + value =3D fmt["value"] + + lines.append(self.fmt.rst_bullet(self.fmt.bold(value))) + for attr in ['fixed-header', 'attribute-set']: + if attr in fmt: + lines.append(self.fmt.rst_fields(attr, + self.fmt.rst_ref(namespace= , attr, fmt[attr]), + 1)) + lines.append("\n") + + return "\n".join(lines) =20 - return "\n".join(lines) =20 + def parse_yaml(self, obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines =3D [] =20 -def parse_yaml(obj: Dict[str, Any]) -> str: - """Format the whole YAML into a RST string""" - lines =3D [] + # Main header =20 - # Main header + family =3D obj['name'] =20 - family =3D obj['name'] + lines.append(self.fmt.rst_header()) + lines.append(self.fmt.rst_label("netlink-" + family)) =20 - lines.append(rst_header()) - lines.append(rst_label("netlink-" + family)) + title =3D f"Family ``{family}`` netlink specification" + lines.append(self.fmt.rst_title(title)) + lines.append(self.fmt.rst_paragraph(".. contents:: :depth: 3\n")) =20 - title =3D f"Family ``{family}`` netlink specification" - lines.append(rst_title(title)) - lines.append(rst_paragraph(".. contents:: :depth: 3\n")) + if "doc" in obj: + lines.append(self.fmt.rst_subtitle("Summary")) + lines.append(self.fmt.rst_paragraph(obj["doc"], 0)) =20 - if "doc" in obj: - lines.append(rst_subtitle("Summary")) - lines.append(rst_paragraph(obj["doc"], 0)) + # Operations + if "operations" in obj: + lines.append(self.fmt.rst_subtitle("Operations")) + lines.append(self.parse_operations(obj["operations"]["list"], = family)) =20 - # Operations - if "operations" in obj: - lines.append(rst_subtitle("Operations")) - lines.append(parse_operations(obj["operations"]["list"], family)) + # Multicast groups + if "mcast-groups" in obj: + lines.append(self.fmt.rst_subtitle("Multicast groups")) + lines.append(self.parse_mcast_group(obj["mcast-groups"]["list"= ])) =20 - # Multicast groups - if "mcast-groups" in obj: - lines.append(rst_subtitle("Multicast groups")) - lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) + # Definitions + if "definitions" in obj: + lines.append(self.fmt.rst_subtitle("Definitions")) + lines.append(self.parse_definitions(obj["definitions"], family= )) =20 - # Definitions - if "definitions" in obj: - lines.append(rst_subtitle("Definitions")) - lines.append(parse_definitions(obj["definitions"], family)) + # Attributes set + if "attribute-sets" in obj: + lines.append(self.fmt.rst_subtitle("Attribute sets")) + lines.append(self.parse_attr_sets(obj["attribute-sets"], famil= y)) =20 - # Attributes set - if "attribute-sets" in obj: - lines.append(rst_subtitle("Attribute sets")) - lines.append(parse_attr_sets(obj["attribute-sets"], family)) + # Sub-messages + if "sub-messages" in obj: + lines.append(self.fmt.rst_subtitle("Sub-messages")) + lines.append(self.parse_sub_messages(obj["sub-messages"], fami= ly)) =20 - # Sub-messages - if "sub-messages" in obj: - lines.append(rst_subtitle("Sub-messages")) - lines.append(parse_sub_messages(obj["sub-messages"], family)) + return "\n".join(lines) =20 - return "\n".join(lines) =20 + # Main functions + # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -# Main functions -# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 + def parse_yaml_file(self, filename: str) -> str: + """Transform the YAML specified by filename into an RST-formatted = string""" + with open(filename, "r", encoding=3D"utf-8") as spec_file: + yaml_data =3D yaml.safe_load(spec_file) + content =3D self.parse_yaml(yaml_data) =20 -def parse_yaml_file(filename: str) -> str: - """Transform the YAML specified by filename into an RST-formatted stri= ng""" - with open(filename, "r", encoding=3D"utf-8") as spec_file: - yaml_data =3D yaml.safe_load(spec_file) - content =3D parse_yaml(yaml_data) + return content =20 - return content =20 + def generate_main_index_rst(self, output: str, index_dir: str) -> None: + """Generate the `networking_spec/index` content and write to the f= ile""" + lines =3D [] =20 -def generate_main_index_rst(output: str, index_dir: str) -> str: - """Generate the `networking_spec/index` content and write to the file"= "" - lines =3D [] + lines.append(self.fmt.rst_header()) + lines.append(self.fmt.rst_label("specs")) + lines.append(self.fmt.rst_title("Netlink Family Specifications")) + lines.append(self.fmt.rst_toctree(1)) =20 - lines.append(rst_header()) - lines.append(rst_label("specs")) - lines.append(rst_title("Netlink Family Specifications")) - lines.append(rst_toctree(1)) + index_fname =3D os.path.basename(output) + base, ext =3D os.path.splitext(index_fname) =20 - index_fname =3D os.path.basename(output) - base, ext =3D os.path.splitext(index_fname) + if not index_dir: + index_dir =3D os.path.dirname(output) =20 - if not index_dir: - index_dir =3D os.path.dirname(output) + logging.debug(f"Looking for {ext} files in %s", index_dir) + for filename in sorted(os.listdir(index_dir)): + if not filename.endswith(ext) or filename =3D=3D index_fname: + continue + base, ext =3D os.path.splitext(filename) + lines.append(f" {base}\n") =20 - logging.debug(f"Looking for {ext} files in %s", index_dir) - for filename in sorted(os.listdir(index_dir)): - if not filename.endswith(ext) or filename =3D=3D index_fname: - continue - base, ext =3D os.path.splitext(filename) - lines.append(f" {base}\n") + logging.debug("Writing an index file at %s", output) =20 - return "".join(lines), output + return "".join(lines) diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_g= en_rst.py index 38dafe3d9179..624b0960476e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -10,12 +10,7 @@ =20 This script performs extensive parsing to the Linux kernel's netlink Y= AML spec files, in an effort to avoid needing to heavily mark up the origi= nal - YAML file. - - This code is split in three big parts: - 1) RST formatters: Use to convert a string to a RST output - 2) Parser helpers: Functions to parse the YAML data structure - 3) Main function and small helpers + YAML file. It uses the library code from scripts/lib. """ =20 import os.path @@ -28,7 +23,7 @@ SRC_DIR =3D os.path.dirname(os.path.realpath(__file__)) =20 sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) =20 -from netlink_yml_parser import parse_yaml_file, generate_main_index_rst +from netlink_yml_parser import YnlDocGenerator =20 =20 def parse_arguments() -> argparse.Namespace: @@ -76,10 +71,10 @@ def write_to_rstfile(content: str, filename: str) -> No= ne: rst_file.write(content) =20 =20 -def write_index_rst(output: str, index_dir: str) -> None: +def write_index_rst(parser: YnlDocGenerator, output: str, index_dir: str) = -> None: """Generate the `networking_spec/index` content and write to the file"= "" =20 - msg =3D generate_main_index_rst(output, index_dir) + msg =3D parser.generate_main_index_rst(output, index_dir) =20 logging.debug("Writing an index file at %s", output) write_to_rstfile(msg, output) @@ -90,10 +85,12 @@ def main() -> None: =20 args =3D parse_arguments() =20 + parser =3D YnlDocGenerator() + if args.input: logging.debug("Parsing %s", args.input) try: - content =3D parse_yaml_file(os.path.join(args.input)) + content =3D parser.parse_yaml_file(os.path.join(args.input)) except Exception as exception: logging.warning("Failed to parse %s.", args.input) logging.warning(exception) @@ -103,7 +100,7 @@ def main() -> None: =20 if args.index: # Generate the index RST file - write_index_rst(args.output, args.input_dir) + write_index_rst(parser, args.output, args.input_dir) =20 =20 if __name__ =3D=3D "__main__": --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3AC6298CD9; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891379; cv=none; b=GEXj+ATU12QAHEq60FBTp/MkwFnO4E0zWSisZRzm5qd1uOByoD8DurVtm4Aqn4nUp41H2QiINIB0zuD5bwQJIL77OhsviF+0yGrg57ELFddJttTMSYUssUT9qs3CPHvMz9RBsK7Yy72nRg7qqY3omRpjtqpS2w0HxSPyc8FlUr0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891379; c=relaxed/simple; bh=UkQ2QCYIxkOHq/xgNgAQuH6x4IS3MJ30nbw+w5JKF/U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gnXdVih3mVlYrDNWxVcoFSNcvXA7bDan9yzpqGNXplWP1s9/scHjeBp2PheVoq8CGXBPECmZymam+ntvZCTbNLzUcR+bPVkUcuJDV8uTq+i27hUuVtfQ6EjcC9bPALlIzGmef1P0HAUhrUcPIRcZg4Tavc1jOFNPUBSr+wa45M8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kMGNknnJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kMGNknnJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1D2C6C4CEF9; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=UkQ2QCYIxkOHq/xgNgAQuH6x4IS3MJ30nbw+w5JKF/U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kMGNknnJNn8kQK832ElSawoVXYKE3mHZ/v1lpBCxbGMTZvYacqL6FJw1Pm1PrOF8a VhgXacirqUeJLLMQzMhRppdRiPlZ2cL2XX41tKP1F/bMcgFWHh8cgbhNop/8UVAO7V 2G39xgebJFJGbR/QZNQCPlBh5BFdEQ72aqQCja8kSuCLAZXQopA/7S7u5q0qiJLj3X 0T4QI5n1ggPLjIIYRyV+Lyl4F6O4k/eBT2XupsSltFKCS+WKOud6iJinXrTbEJIdzN ikvHNrSRKKSeZ0Vc4J8Fp4OGFBbKdiTezBBWRigpgKjo/n3+eHmlrxy0ess1Q5S5ow /tgFh0FivHsMQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064b5-1FVt; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 07/14] tools: ynl_gen_rst.py: move index.rst generator to the script Date: Sat, 14 Jun 2025 10:56:01 +0200 Message-ID: <31466ece9905956c2e1a3d3fc744cfc272df5d88.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" The index.rst generator doesn't really belong to the parsing function. Move it to the command line tool, as it won't be used elsewhere. While here, make it more generic, allowing it to handle either .yaml or .rst as input files. Signed-off-by: Mauro Carvalho Chehab --- scripts/lib/netlink_yml_parser.py | 101 ++++++++--------------------- tools/net/ynl/pyynl/ynl_gen_rst.py | 28 +++++++- 2 files changed, 52 insertions(+), 77 deletions(-) diff --git a/scripts/lib/netlink_yml_parser.py b/scripts/lib/netlink_yml_pa= rser.py index 839e78b39de3..866551726723 100755 --- a/scripts/lib/netlink_yml_parser.py +++ b/scripts/lib/netlink_yml_parser.py @@ -18,17 +18,12 @@ """ =20 from typing import Any, Dict, List -import os.path -import sys -import argparse -import logging import yaml =20 =20 -# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -# RST Formatters -# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D class RstFormatters: + """RST Formatters""" + SPACE_PER_LEVEL =3D 4 =20 @staticmethod @@ -36,81 +31,67 @@ class RstFormatters: """Return space to format""" return " " * (level * RstFormatters.SPACE_PER_LEVEL) =20 - @staticmethod def bold(text: str) -> str: """Format bold text""" return f"**{text}**" =20 - @staticmethod def inline(text: str) -> str: """Format inline text""" return f"``{text}``" =20 - @staticmethod def sanitize(text: str) -> str: """Remove newlines and multiple spaces""" # This is useful for some fields that are spread across multiple l= ines return str(text).replace("\n", " ").strip() =20 - def rst_fields(self, key: str, value: str, level: int =3D 0) -> str: """Return a RST formatted field""" return self.headroom(level) + f":{key}: {value}" =20 - def rst_definition(self, key: str, value: Any, level: int =3D 0) -> st= r: """Format a single rst definition""" return self.headroom(level) + key + "\n" + self.headroom(level + 1= ) + str(value) =20 - def rst_paragraph(self, paragraph: str, level: int =3D 0) -> str: """Return a formatted paragraph""" return self.headroom(level) + paragraph =20 - def rst_bullet(self, item: str, level: int =3D 0) -> str: """Return a formatted a bullet""" return self.headroom(level) + f"- {item}" =20 - @staticmethod def rst_subsection(title: str) -> str: """Add a sub-section to the document""" return f"{title}\n" + "-" * len(title) =20 - @staticmethod def rst_subsubsection(title: str) -> str: """Add a sub-sub-section to the document""" return f"{title}\n" + "~" * len(title) =20 - @staticmethod def rst_section(namespace: str, prefix: str, title: str) -> str: """Add a section to the document""" return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=3D" *= len(title) =20 - @staticmethod def rst_subtitle(title: str) -> str: """Add a subtitle to the document""" return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title)= + "\n\n" =20 - @staticmethod def rst_title(title: str) -> str: """Add a title to the document""" return "=3D" * len(title) + f"\n{title}\n" + "=3D" * len(title) + = "\n\n" =20 - def rst_list_inline(self, list_: List[str], level: int =3D 0) -> str: """Format a list using inlines""" return self.headroom(level) + "[" + ", ".join(self.inline(i) for i= in list_) + "]" =20 - @staticmethod def rst_ref(namespace: str, prefix: str, name: str) -> str: """Add a hyperlink to the document""" @@ -119,10 +100,9 @@ class RstFormatters: 'nested-attributes': 'attribute-set', 'struct': 'definition'} if prefix in mappings: - prefix =3D mappings[prefix] + prefix =3D mappings.get(prefix, "") return f":ref:`{namespace}-{prefix}-{name}`" =20 - def rst_header(self) -> str: """The headers for all the auto generated RST files""" lines =3D [] @@ -132,7 +112,6 @@ class RstFormatters: =20 return "\n".join(lines) =20 - @staticmethod def rst_toctree(maxdepth: int =3D 2) -> str: """Generate a toctree RST primitive""" @@ -143,16 +122,13 @@ class RstFormatters: =20 return "\n".join(lines) =20 - @staticmethod def rst_label(title: str) -> str: """Return a formatted label""" return f".. _{title}:\n\n" =20 -# =3D=3D=3D=3D=3D=3D=3D -# Parsers -# =3D=3D=3D=3D=3D=3D=3D class YnlDocGenerator: + """YAML Netlink specs Parser""" =20 fmt =3D RstFormatters() =20 @@ -164,7 +140,6 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - def parse_do(self, do_dict: Dict[str, Any], level: int =3D 0) -> str: """Parse 'do' section and return a formatted string""" lines =3D [] @@ -177,16 +152,16 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - def parse_do_attributes(self, attrs: Dict[str, Any], level: int =3D 0)= -> str: """Parse 'attributes' section""" if "attributes" not in attrs: return "" - lines =3D [self.fmt.rst_fields("attributes", self.fmt.rst_list_inl= ine(attrs["attributes"]), level + 1)] + lines =3D [self.fmt.rst_fields("attributes", + self.fmt.rst_list_inline(attrs["attri= butes"]), + level + 1)] =20 return "\n".join(lines) =20 - def parse_operations(self, operations: List[Dict[str, Any]], namespace= : str) -> str: """Parse operations block""" preprocessed =3D ["name", "doc", "title", "do", "dump", "flags"] @@ -194,7 +169,8 @@ class YnlDocGenerator: lines =3D [] =20 for operation in operations: - lines.append(self.fmt.rst_section(namespace, 'operation', oper= ation["name"])) + lines.append(self.fmt.rst_section(namespace, 'operation', + operation["name"])) lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") =20 for key in operation.keys(): @@ -206,7 +182,8 @@ class YnlDocGenerator: value =3D self.fmt.rst_ref(namespace, key, value) lines.append(self.fmt.rst_fields(key, value, 0)) if 'flags' in operation: - lines.append(self.fmt.rst_fields('flags', self.fmt.rst_lis= t_inline(operation['flags']))) + lines.append(self.fmt.rst_fields('flags', + self.fmt.rst_list_inline(= operation['flags']))) =20 if "do" in operation: lines.append(self.fmt.rst_paragraph(":do:", 0)) @@ -220,7 +197,6 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - def parse_entries(self, entries: List[Dict[str, Any]], level: int) -> = str: """Parse a list of entries""" ignored =3D ["pad"] @@ -235,17 +211,19 @@ class YnlDocGenerator: if type_: field_name +=3D f" ({self.fmt.inline(type_)})" lines.append( - self.fmt.rst_fields(field_name, self.fmt.sanitize(entr= y.get("doc", "")), level) + self.fmt.rst_fields(field_name, + self.fmt.sanitize(entry.get("doc",= "")), + level) ) elif isinstance(entry, list): lines.append(self.fmt.rst_list_inline(entry, level)) else: - lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.= sanitize(entry)), level)) + lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.= sanitize(entry)), + level)) =20 lines.append("\n") return "\n".join(lines) =20 - def parse_definitions(self, defs: Dict[str, Any], namespace: str) -> s= tr: """Parse definitions section""" preprocessed =3D ["name", "entries", "members"] @@ -270,7 +248,6 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - def parse_attr_sets(self, entries: List[Dict[str, Any]], namespace: st= r) -> str: """Parse attribute from attribute-set""" preprocessed =3D ["name", "type"] @@ -279,7 +256,8 @@ class YnlDocGenerator: lines =3D [] =20 for entry in entries: - lines.append(self.fmt.rst_section(namespace, 'attribute-set', = entry["name"])) + lines.append(self.fmt.rst_section(namespace, 'attribute-set', + entry["name"])) for attr in entry["attributes"]: type_ =3D attr.get("type") attr_line =3D attr["name"] @@ -301,13 +279,13 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - def parse_sub_messages(self, entries: List[Dict[str, Any]], namespace:= str) -> str: """Parse sub-message definitions""" lines =3D [] =20 for entry in entries: - lines.append(self.fmt.rst_section(namespace, 'sub-message', en= try["name"])) + lines.append(self.fmt.rst_section(namespace, 'sub-message', + entry["name"])) for fmt in entry["formats"]: value =3D fmt["value"] =20 @@ -315,13 +293,14 @@ class YnlDocGenerator: for attr in ['fixed-header', 'attribute-set']: if attr in fmt: lines.append(self.fmt.rst_fields(attr, - self.fmt.rst_ref(namespace= , attr, fmt[attr]), - 1)) + self.fmt.rst_ref(= namespace, + = attr, + = fmt[attr]), + 1)) lines.append("\n") =20 return "\n".join(lines) =20 - def parse_yaml(self, obj: Dict[str, Any]) -> str: """Format the whole YAML into a RST string""" lines =3D [] @@ -344,7 +323,8 @@ class YnlDocGenerator: # Operations if "operations" in obj: lines.append(self.fmt.rst_subtitle("Operations")) - lines.append(self.parse_operations(obj["operations"]["list"], = family)) + lines.append(self.parse_operations(obj["operations"]["list"], + family)) =20 # Multicast groups if "mcast-groups" in obj: @@ -368,11 +348,9 @@ class YnlDocGenerator: =20 return "\n".join(lines) =20 - # Main functions # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 - def parse_yaml_file(self, filename: str) -> str: """Transform the YAML specified by filename into an RST-formatted = string""" with open(filename, "r", encoding=3D"utf-8") as spec_file: @@ -380,30 +358,3 @@ class YnlDocGenerator: content =3D self.parse_yaml(yaml_data) =20 return content - - - def generate_main_index_rst(self, output: str, index_dir: str) -> None: - """Generate the `networking_spec/index` content and write to the f= ile""" - lines =3D [] - - lines.append(self.fmt.rst_header()) - lines.append(self.fmt.rst_label("specs")) - lines.append(self.fmt.rst_title("Netlink Family Specifications")) - lines.append(self.fmt.rst_toctree(1)) - - index_fname =3D os.path.basename(output) - base, ext =3D os.path.splitext(index_fname) - - if not index_dir: - index_dir =3D os.path.dirname(output) - - logging.debug(f"Looking for {ext} files in %s", index_dir) - for filename in sorted(os.listdir(index_dir)): - if not filename.endswith(ext) or filename =3D=3D index_fname: - continue - base, ext =3D os.path.splitext(filename) - lines.append(f" {base}\n") - - logging.debug("Writing an index file at %s", output) - - return "".join(lines) diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_g= en_rst.py index 624b0960476e..85e9e2520393 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -23,7 +23,7 @@ SRC_DIR =3D os.path.dirname(os.path.realpath(__file__)) =20 sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) =20 -from netlink_yml_parser import YnlDocGenerator +from netlink_yml_parser import YnlDocGenerator # pylint: disable=3D= C0413 =20 =20 def parse_arguments() -> argparse.Namespace: @@ -74,7 +74,31 @@ def write_to_rstfile(content: str, filename: str) -> Non= e: def write_index_rst(parser: YnlDocGenerator, output: str, index_dir: str) = -> None: """Generate the `networking_spec/index` content and write to the file"= "" =20 - msg =3D parser.generate_main_index_rst(output, index_dir) + lines =3D [] + + lines.append(parser.fmt.rst_header()) + lines.append(parser.fmt.rst_label("specs")) + lines.append(parser.fmt.rst_title("Netlink Family Specifications")) + lines.append(parser.fmt.rst_toctree(1)) + + index_fname =3D os.path.basename(output) + if not index_dir: + index_dir =3D os.path.dirname(output) + + exts =3D [ ".yaml", ".rst" ] + + logging.debug(f"Looking for files in %s", index_dir) + for filename in sorted(os.listdir(index_dir)): + if filename =3D=3D index_fname: + continue + + for ext in exts: + if not filename.endswith(ext): + continue + base, ext =3D os.path.splitext(filename) + lines.append(f" {base}\n") + + msg =3D "".join(lines) =20 logging.debug("Writing an index file at %s", output) write_to_rstfile(msg, output) --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F0C12980B4; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=sSpQmN3NuCwM77BCtx+yvAYpF4f4WtlMduJ8g9YHfCFX7xZTJH8ZTYaPD+cBCEoAagHZDx0WGU2iQUDa5X7iPkxg2hxlg9aGRRlZFt0Ba62Em2Fh7IohGgLejtIZfYPyZeNA85TSn3mawIiBoYOwDviXVg2QJBaw0IgRBwKktw0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=I8pUy88zBF77rSu49ytMSdMuCNGwN6+WLgN5avfuYxU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cyZWS6jnK2SLG3wJY4hmEj1U92padwxlBSMukh7llcJxiQYv6V3jb/dPm11s5KtNN8K5yKHcrg49qa2nc/n2qs/rQtXS5A8Evyn5oomHDmTnbeHu35gFAwHyJ4jUavO1XR7Vsu7Mt/wZbkgQi3SRiMQm6giS3RAtnHyusBVXOfs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HTG7J6SH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HTG7J6SH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 223EAC4CEFA; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=I8pUy88zBF77rSu49ytMSdMuCNGwN6+WLgN5avfuYxU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HTG7J6SH/h1/npYSqD2MKXtZuTixOUkwIZQ6lmqLSQ3J5aNz5L1gABzF7h0vUpW8n UMVtH3jE02TZm3H7Erbf2UjLQYDF2JtJmBNQ8qUdJNXOiYCdpVD5KJ1LUiRth78MWB gK5LBkeYIvapyhdht6NO7NWwDtTHV9EHthMTa74+VDlr/bL7RYxkHRXYGg3zimEgBQ Ih5k0Kkkl2CnHMj1EXLH1sRRSHzFwZzmzXA638Y9M+ECQMXBaA4ZiizxlMyRdHSjVT LiaKHPFfKCQPSppHB7EdBy7D2VCTz5mUwbdQew5RS6Uwmm174j649+cCbCt0WPDaLF HECI2U1/M9KFw== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064b9-1UUZ; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 08/14] docs: sphinx: add a parser for yaml files for Netlink specs Date: Sat, 14 Jun 2025 10:56:02 +0200 Message-ID: <4eb1691d75bedaf1317e5293bb09f4148288904a.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Add a simple sphinx.Parser to handle yaml files and add the the code to handle Netlink specs. All other yaml files are ignored. The code was written in a way that parsing yaml for different subsystems and even for different parts of Netlink are easy. All it takes to have a different parser is to add an import line similar to: from netlink_yml_parser import YnlDocGenerator adding the corresponding parser somewhere at the extension: netlink_parser =3D YnlDocGenerator() And then add a logic inside parse() to handle different doc outputs, depending on the file location, similar to: if "/netlink/specs/" in fname: msg =3D self.netlink_parser.parse_yaml_file(fname) Signed-off-by: Mauro Carvalho Chehab --- .pylintrc | 2 +- Documentation/sphinx/parser_yaml.py | 76 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100755 Documentation/sphinx/parser_yaml.py diff --git a/.pylintrc b/.pylintrc index 30b8ae1659f8..f1d21379254b 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,2 +1,2 @@ [MASTER] -init-hook=3D'import sys; sys.path +=3D ["scripts/lib/kdoc", "scripts/lib/a= bi"]' +init-hook=3D'import sys; sys.path +=3D ["scripts/lib", "scripts/lib/kdoc",= "scripts/lib/abi"]' diff --git a/Documentation/sphinx/parser_yaml.py b/Documentation/sphinx/par= ser_yaml.py new file mode 100755 index 000000000000..9083e102c9f3 --- /dev/null +++ b/Documentation/sphinx/parser_yaml.py @@ -0,0 +1,76 @@ +""" +Sphinx extension for processing YAML files +""" + +import os +import re +import sys + +from pprint import pformat + +from docutils.parsers.rst import Parser as RSTParser +from docutils.statemachine import ViewList + +from sphinx.util import logging +from sphinx.parsers import Parser + +srctree =3D os.path.abspath(os.environ["srctree"]) +sys.path.insert(0, os.path.join(srctree, "scripts/lib")) + +from netlink_yml_parser import YnlDocGenerator # pylint: disable=3D= C0413 + +logger =3D logging.getLogger(__name__) + +class YamlParser(Parser): + """Custom parser for YAML files.""" + + # Need at least two elements on this set + supported =3D ('yaml', 'yml') + + netlink_parser =3D YnlDocGenerator() + + def do_parse(self, inputstring, document, msg): + """Parse YAML and generate a document tree.""" + + self.setup_parse(inputstring, document) + + result =3D ViewList() + + try: + # Parse message with RSTParser + for i, line in enumerate(msg.split('\n')): + result.append(line, document.current_source, i) + + rst_parser =3D RSTParser() + rst_parser.parse('\n'.join(result), document) + + except Exception as e: + document.reporter.error("YAML parsing error: %s" % pformat(e)) + + self.finish_parse() + + # Overrides docutils.parsers.Parser. See sphinx.parsers.RSTParser + def parse(self, inputstring, document): + """Check if a YAML is meant to be parsed.""" + + fname =3D document.current_source + + # Handle netlink yaml specs + if "/netlink/specs/" in fname: + msg =3D self.netlink_parser.parse_yaml_file(fname) + self.do_parse(inputstring, document, msg) + + # All other yaml files are ignored + +def setup(app): + """Setup function for the Sphinx extension.""" + + # Add YAML parser + app.add_source_parser(YamlParser) + app.add_source_suffix('.yaml', 'yaml') + + return { + 'version': '1.0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B9FA129826D; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=XPWy4HSpBVbXk+JhQ0yjQmJjqRWCDwW/3gvjxv/9bjvhagDfeVfqP9xfEN9lOmJPEqtsL0AVNzw3XqmbDUrRLBuMWbMTrPg9o32+QtD4lPDIQVhPcs9QYcwWsMNFRx69FcjWS6qmRdFmE2nlnu/63A/S63dvX8RtFBsWalbVIUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=44HqA/nQN1h1x3sf65AL65NGoxtO1kKhCNfyxZijhTE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eMVuBOSC+dCeaqvckDhfxI4JJMIN170u8UlLNExuCiNgjCJASpu6VIclMWgdCfjqTWYN0wI1sQ1+SxSGYE7bZVVpkLIzBrnirPFcvcnREOdFOVEHr4nHUY1ziLN9qkvF84/XBNDkaHC3B6m0/cN/D/lCw5uGR+U6RUEM1D1DEu0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=u4ii6I/l; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="u4ii6I/l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3CD73C4CEFB; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=44HqA/nQN1h1x3sf65AL65NGoxtO1kKhCNfyxZijhTE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=u4ii6I/lIPIrGHquibOeNq+QkMf4FEblj3eI+8R96BXMdsXYt8kg3Yne4zYLBRdON z7qG9k3BYNuS2RCS4ZjV1/6PdaQFjQvLqxV2nnj1cSdGLprUv6y4/KgAFXLBI9C8Kr RDJq0gAcQLJyuHhBsbvPwn+FDryeJwlVyGRB1mjJs1m6FcI5FOyfvmG0NUHm/tUibJ wBysw2HDt1AbxY0gbVaySXhOj/uLqJHpdrjRlf8hkNF1L/uRD+abDHrVQ29HqUVYw8 akCOE3BSPvpBZzHQhrRBGl3BbBeaiNu+xn3PaBlCGhttzRxdPbn+hkgkrCqBGJPoAK B6EsHNzZD6uiQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bD-1ktO; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 09/14] docs: use parser_yaml extension to handle Netlink specs Date: Sat, 14 Jun 2025 10:56:03 +0200 Message-ID: <16e241d5c67adbec4a39524383d0058643f92b40.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Instead of manually calling ynl_gen_rst.py, use a Sphinx extension. This way, no .rst files would be written to the Kernel source directories. We are using here a toctree with :glob: property. This way, there is no need to touch the netlink/specs/index.rst file every time a new Netlink spec is added/renamed/removed. Signed-off-by: Mauro Carvalho Chehab --- Documentation/Makefile | 17 ----------------- Documentation/conf.py | 11 ++++++----- Documentation/netlink/specs/index.rst | 13 +++++++++++++ Documentation/networking/index.rst | 2 +- .../networking/netlink_spec/readme.txt | 4 ---- 5 files changed, 20 insertions(+), 27 deletions(-) create mode 100644 Documentation/netlink/specs/index.rst delete mode 100644 Documentation/networking/netlink_spec/readme.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index d30d66ddf1ad..9185680b1e86 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -102,22 +102,6 @@ quiet_cmd_sphinx =3D SPHINX $@ --> file://$(abspath $= (BUILDDIR)/$3/$4) cp $(if $(patsubst /%,,$(DOCS_CSS)),$(abspath $(srctree)/$(DOCS_CSS)),$(= DOCS_CSS)) $(BUILDDIR)/$3/_static/; \ fi =20 -YNL_INDEX:=3D$(srctree)/Documentation/networking/netlink_spec/index.rst -YNL_RST_DIR:=3D$(srctree)/Documentation/networking/netlink_spec -YNL_YAML_DIR:=3D$(srctree)/Documentation/netlink/specs -YNL_TOOL:=3D$(srctree)/tools/net/ynl/pyynl/ynl_gen_rst.py - -YNL_RST_FILES_TMP :=3D $(patsubst %.yaml,%.rst,$(wildcard $(YNL_YAML_DIR)/= *.yaml)) -YNL_RST_FILES :=3D $(patsubst $(YNL_YAML_DIR)%,$(YNL_RST_DIR)%, $(YNL_RST_= FILES_TMP)) - -$(YNL_INDEX): $(YNL_RST_FILES) - $(Q)$(YNL_TOOL) -o $@ -x - -$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL) - $(Q)$(YNL_TOOL) -i $< -o $@ - -htmldocs texinfodocs latexdocs epubdocs xmldocs: $(YNL_INDEX) - htmldocs: @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) @@ -184,7 +168,6 @@ refcheckdocs: $(Q)cd $(srctree);scripts/documentation-file-ref-check =20 cleandocs: - $(Q)rm -f $(YNL_INDEX) $(YNL_RST_FILES) $(Q)rm -rf $(BUILDDIR) $(Q)$(MAKE) BUILDDIR=3D$(abspath $(BUILDDIR)) $(build)=3DDocumentation/us= erspace-api/media clean =20 diff --git a/Documentation/conf.py b/Documentation/conf.py index 12de52a2b17e..add6ce78dd80 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -45,7 +45,7 @@ needs_sphinx =3D '3.4.3' extensions =3D ['kerneldoc', 'rstFlatTable', 'kernel_include', 'kfigure', 'sphinx.ext.ifconfig', 'automarkup', 'maintainers_include', 'sphinx.ext.autosectionlabel', - 'kernel_abi', 'kernel_feat', 'translations'] + 'kernel_abi', 'kernel_feat', 'translations', 'parser_yaml'] =20 # Since Sphinx version 3, the C function parser is more pedantic with rega= rds # to type checking. Due to that, having macros at c:function cause problem= s. @@ -143,10 +143,11 @@ else: # Add any paths that contain templates here, relative to this directory. templates_path =3D ['sphinx/templates'] =20 -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix =3D ['.rst', '.md'] -source_suffix =3D '.rst' +# The suffixes of source filenames that will be automatically parsed +source_suffix =3D { + '.rst': 'restructuredtext', + '.yaml': 'yaml', +} =20 # The encoding of source files. #source_encoding =3D 'utf-8-sig' diff --git a/Documentation/netlink/specs/index.rst b/Documentation/netlink/= specs/index.rst new file mode 100644 index 000000000000..7f7cf4a096f2 --- /dev/null +++ b/Documentation/netlink/specs/index.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _specs: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D +Netlink Family Specifications +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +.. toctree:: + :maxdepth: 1 + :glob: + + * diff --git a/Documentation/networking/index.rst b/Documentation/networking/= index.rst index ac90b82f3ce9..b7a4969e9bc9 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -57,7 +57,7 @@ Contents: filter generic-hdlc generic_netlink - netlink_spec/index + ../netlink/specs/index gen_stats gtp ila diff --git a/Documentation/networking/netlink_spec/readme.txt b/Documentati= on/networking/netlink_spec/readme.txt deleted file mode 100644 index 030b44aca4e6..000000000000 --- a/Documentation/networking/netlink_spec/readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -SPDX-License-Identifier: GPL-2.0 - -This file is populated during the build of the documentation (htmldocs) by= the -tools/net/ynl/pyynl/ynl_gen_rst.py script. --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F01A2980AC; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=ii2h5k8cgfi5iFmcp/2n3njJsaZw1+H1bcd4c+vPl0rO+3Ua/76aCpnLZkguah8HunA/T+apwIhIHt9+TDsC3EQG9MOltfl8+wXNSg8EeOBsFrTI/HC1aP1zcYsGk/JoaE64I4OYAvr08SsQNFR0sVSwFAFunIc/2R8JZH12WYo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=+6rtudJ73X+4ufoIvZc3v82fZGF4QvbxcviFruS5je8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=BO218lETKnonlHkapNyY+a6MxDysHSM31I+Qwx0tBQTvCEwSpr9v1bsGehqlmr2TwiP22r/O/yVvfS9RHsHLGsoWfq+4yok0CemfBBoJ8pqt7SEsgJ5Wo2Q0sLf7/J3RrL+zOB0XEl4lmKJXdzKgtAKNEg+1Qsekgvqt42jSXpM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kVadhsiF; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kVadhsiF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 41AA2C4CEFC; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=+6rtudJ73X+4ufoIvZc3v82fZGF4QvbxcviFruS5je8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kVadhsiFfw1MukiWOx/QmX9YxGaDXTanMWwIAtUR7A1moktENrB55UduqSiOGrpt3 bkmb2l1YKkJpqKC4KTUrFqr/cLfMhgKBiUYXgGteilOC/LAr3BA9+2pxP36LZfpRv3 pwfHUWbBHo19ig60DM05UFsVok0cE1SshPyi57ORIMkoCmr/2HVBj28ScfEK8VT/F4 rEfRXarDKsxqZ+7f8VOKybJB092lMV5NLccTW0ghJJLUzx+Yn1njsxQfKWfTkc0vat ER7BqIoootq6YyA+PYCNijJAGynwgFRHKaophMGth764KftTL+zbZFK8xn4BOj5N1g uyEbeFjDnKpOA== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bG-1zCZ; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 10/14] docs: conf.py: don't handle yaml files outside Netlink specs Date: Sat, 14 Jun 2025 10:56:04 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab The parser_yaml extension already has a logic to prevent handing all yaml documents. However, if we don't also exclude the patterns at conf.py, the build time would increase a lot, and warnings like those would be generated: Documentation/netlink/genetlink.yaml: WARNING: o documento n=C3=A3o est= =C3=A1 inclu=C3=ADdo em nenhum toctree Documentation/netlink/genetlink-c.yaml: WARNING: o documento n=C3=A3o e= st=C3=A1 inclu=C3=ADdo em nenhum toctree Documentation/netlink/genetlink-legacy.yaml: WARNING: o documento n=C3= =A3o est=C3=A1 inclu=C3=ADdo em nenhum toctree Documentation/netlink/index.rst: WARNING: o documento n=C3=A3o est=C3= =A1 inclu=C3=ADdo em nenhum toctree Documentation/netlink/netlink-raw.yaml: WARNING: o documento n=C3=A3o e= st=C3=A1 inclu=C3=ADdo em nenhum toctree Add some exclusion rules to prevent that. Signed-off-by: Mauro Carvalho Chehab --- Documentation/conf.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/conf.py b/Documentation/conf.py index add6ce78dd80..62a51ac64b95 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -221,8 +221,16 @@ language =3D 'en' #today_fmt =3D '%B %d, %Y' =20 # List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns =3D ['output'] +# directories. +include_patterns =3D [ + '**.rst', + 'netlink/specs/*.yaml', +] + +# patterns to ignore when looking for source files. +exclude_patterns =3D [ + 'output', +] =20 # The reST default role (used for this markup: `text`) to use for all # documents. --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7D6E299928; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891379; cv=none; b=U+MXT60eeLqxluGpt/ihoalF7UkjDaC5A31RAcOrSXfS9179uUZGfOeDF4o6I2uKSZlhHIHXvJmMqb7+UwigtEiB/UrCRK/FHxyEv+59XT846PvYukFG3NEypyF74aljSLJI3KCuvABzRnzakXljBGv9bJt9pz/2GLXDBR6hOmk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891379; c=relaxed/simple; bh=00F9KG3FuikbC/77I/aVEWzxRtC/68GGYQsrs3gqu00=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ud7aAwX/IHTstc5MesAawLTPL+Y2LypacaZZsec3evl+Ktn7huiNCSxN1raLryowpq5kVYrz2JcEq6Qmf0Aoeuzhm7jYu5x4Sc9XqWVHgplF2K7VGNG0CDfjcgYFSR1ugv4AX/TgMpyJoRxFaZOcHOsga/5vVxn6pzuKTscVvWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WrsOCRsq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WrsOCRsq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 55A8BC4CEFE; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=00F9KG3FuikbC/77I/aVEWzxRtC/68GGYQsrs3gqu00=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WrsOCRsq69wKZqzbM/v4hKRkiF6UJl4qiGVj1ejjEYSbVZjgDJ59mBRM/3knDFwKr wB5f4hi2a2j86U0ExnNWsZOn1GPDAF12SAx99jKz9Bc+VuB2RMR9/KopRFxyiN+hb3 z++8JFza65hM6EA7H22qSVa5eCE/PkyJ4D+xag+c87NqULs+gw0Q9H8XYiWckTiXm+ d1iMqSQ50AMTZqgNp7W86D6LNAhAt7P6h14Jwpz2rJoGpS7ghjiDFGq9zNleKAg2TG NijsY+UTSH1gJ1VGEuWiuYpBEmjR2FXAZE0qie7DYNJq+pnvdPENlyaFSzoeZb5bLI 4DWsDFgHQXbyQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bL-2EQ1; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , Jakub Kicinski , Simon Horman , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 11/14] docs: uapi: netlink: update netlink specs link Date: Sat, 14 Jun 2025 10:56:05 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" With the recent parser_yaml extension, and the removal of the auto-generated ReST source files, the location of netlink specs changed. Update uAPI accordingly. Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/netlink/index.rst | 2 +- Documentation/userspace-api/netlink/specs.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/netlink/index.rst b/Documentation/= userspace-api/netlink/index.rst index c1b6765cc963..83ae25066591 100644 --- a/Documentation/userspace-api/netlink/index.rst +++ b/Documentation/userspace-api/netlink/index.rst @@ -18,4 +18,4 @@ Netlink documentation for users. =20 See also: - :ref:`Documentation/core-api/netlink.rst ` - - :ref:`Documentation/networking/netlink_spec/index.rst ` + - :ref:`Documentation/netlink/specs/index.rst ` diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/= userspace-api/netlink/specs.rst index 1b50d97d8d7c..debb4bfca5c4 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -15,7 +15,7 @@ kernel headers directly. Internally kernel uses the YAML specs to generate: =20 - the C uAPI header - - documentation of the protocol as a ReST file - see :ref:`Documentation/= networking/netlink_spec/index.rst ` + - documentation of the protocol as a ReST file - see :ref:`Documentation/= netlink/specs/index.rst ` - policy tables for input attribute validation - operation tables =20 --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC295298275; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=Ze507UYmq8CCtPBC/plKBtp5QmhhDCp5ax+QBhUIfGM7Fp4bLlcJVIL5RFWpQE8HhohQj2Kf9OsVCnGb/xbo6udoMwdIxGGwtYZiArj152GoWo2VISXcmPX5W1Myb7RyN4xe0pse0Kx5O8Rr4MA+cjzVB33DrxcQ9dA9+pE5wXI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=qdx5eLFhJs3mwB2br6zWhdyUu0aQq9T5BmAjQqI3pSk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=T5TifL6uuVG8cjsfOqX2rUDUNrxMgrERQE/VxcV4T9uuKreLPoVBCKOmm4DZhFbWE/EEwk3H9I2d+pOIoCcI84bYtjxpkQ/8LOFlxpFFf2dqL8d8ujLoMTEZ+2HXhcm+shZrVrCoYoxhg2gQByiDnyxT8AGeQdO0aG9/Z4O3ZMQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fRRe4bib; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fRRe4bib" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5BCEBC4CEFF; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=qdx5eLFhJs3mwB2br6zWhdyUu0aQq9T5BmAjQqI3pSk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fRRe4bibDS/u9thmwGwVWeIq4dGZQmcY2oPfPsgNovEavyhOqG4K4X+ETeimzMBMJ 3oWMiJV/KOsDPul2jDHGT3QRPP5pFGerBigdb+rlkbk6pOmHqP6pm3hfGaTUGcJQDO ritD40S3MBMOQFsDzG4wG46AKF4dq7gkosgKvPNeABScGoX4/WM5eKXR/qc31WA4Fl R4o/8Vp2hhZmvlcRGy8uqLaZssbzLVX2ZwFalitHpADQYBHq3tzFMgQUNFWoYJCaQI gD8J/kVxtCMppRgFWmxYvWeLZdBqpKEOuETM2QewS7R3WVAjuh2ruznm7m7RDuINYF Ul8r2JOeqbTZw== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bP-2T2X; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 12/14] MAINTAINERS: add maintainers for netlink_yml_parser.py Date: Sat, 14 Jun 2025 10:56:06 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" The parsing code from tools/net/ynl/pyynl/ynl_gen_rst.py was moved to scripts/lib/netlink_yml_parser.py. Its maintainership is done by Netlink maintainers. Yet, as it is used by Sphinx build system, add it also to linux-doc maintainers, as changes there might affect documentation builds. So, linux-docs ML should ideally be C/C on changes to it. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..2c0b13e5d8fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7202,6 +7202,7 @@ F: scripts/get_abi.py F: scripts/kernel-doc* F: scripts/lib/abi/* F: scripts/lib/kdoc/* +F: scripts/lib/netlink_yml_parser.py F: scripts/sphinx-pre-install X: Documentation/ABI/ X: Documentation/admin-guide/media/ @@ -27314,6 +27315,7 @@ M: Jakub Kicinski F: Documentation/netlink/ F: Documentation/userspace-api/netlink/intro-specs.rst F: Documentation/userspace-api/netlink/specs.rst +F: scripts/lib/netlink_yml_parser.py F: tools/net/ynl/ =20 YEALINK PHONE DRIVER --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D24BB298CD2; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=OC6hx+Bm7OM6IqYkNxWKiuUgL3GMPI4vNe1q7139DxitXHKxzZqjH5+b/hBKmXr7HiV6UhRx6UO449l/IHZTntK/drjdtkX+7AWbK86orHzdljQBHqZaeq9Dz+gCvrc+5nNPDColTOTORnDen0D7YEgex2wmYHg34lSOKpqaDB8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=jazvmyYFMnGYOxxVZMEBOjTd9mMz+TrushWEPpOXIDU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PtPq5SeT+pWYBhOM88RCVbSfv5/leHdtcu3wemQ6EJdt8PIFq2FpM7jpHq0dqNW5PvDwRmlEUqsDhuRRpWwRnoZ1qS5xxdv6xmfna8m0IZpyu8IIIn08U2r9mGqzriFY1c3/77UckOfr97v4wijXpMG+42CuyWS96x2HnFMeQL4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ron2pf0w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ron2pf0w" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5EDA2C113D0; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=jazvmyYFMnGYOxxVZMEBOjTd9mMz+TrushWEPpOXIDU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ron2pf0wEzLlgOKo4jmBETCTLD/zzRde1B1blhmA9544cAqKpYlKO6zjy7IQ87L4m oIxcgKs0txHocJYfjic3d74DjoToEIPJOdhhLZkvXszxongHQHizoTbzDf2i3uVCWd 9D62wpxysFGCkZuNUc3fXwuukYKboCinO5aHe5WrEaYeJu8R95fv+bivZxEjNNjjTp tmKs9Y8a6X4Fnn25ln/4pJY4Mqaj/keRzemu5qDOsx/6uImiy1hSQmnZSpm7wCgv6E D5b5V+mz7N4d4ZicqPXqaq2n9U0tNa8tE9p065wR/WePMaMdCt0SiLHBeV39LxPvjJ tSbFGd0AIJsww== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bT-2hKl; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 13/14] docs: Makefile: disable check rules on make cleandocs Date: Sat, 14 Jun 2025 10:56:07 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" It doesn't make sense to check for missing ABI and documents when cleaning the tree. Signed-off-by: Mauro Carvalho Chehab --- Documentation/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/Makefile b/Documentation/Makefile index 9185680b1e86..820f07e0afe6 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -5,6 +5,7 @@ # for cleaning subdir- :=3D devicetree/bindings =20 +ifneq ($(MAKECMDGOALS),cleandocs) # Check for broken documentation file references ifeq ($(CONFIG_WARN_MISSING_DOCUMENTS),y) $(shell $(srctree)/scripts/documentation-file-ref-check --warn) @@ -14,6 +15,7 @@ endif ifeq ($(CONFIG_WARN_ABI_ERRORS),y) $(shell $(srctree)/scripts/get_abi.py --dir $(srctree)/Documentation/ABI v= alidate) endif +endif =20 # You can set these variables from the command line. SPHINXBUILD =3D sphinx-build --=20 2.49.0 From nobody Fri Oct 10 09:15:02 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D18AC298CD1; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; cv=none; b=OV9fKLXoU7xnTiyvxBhvVlm8yvDD6p49h0zfuGdsqTzMhLFVLn1W+U9oDtOVeJzikL7Zb95u2JlZwqamv2cRKcE6jtT3YaS++86K83fuMCghvlbqlnHNWgpW6Oo5y+bhkYJ4GBT/iRvjI+JRQrr5aRsvEnFGrmwaWtXt5D514k8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749891378; c=relaxed/simple; bh=JDTK8ds5rMEZTW9f7Wpcip/tbHM6fMKUON4aC7f9ZTc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CNgSSJ2D4Pa1wATKOEFlGZzGQMfaZ8bgvgiOClGSe5AsuB7aFlY2Q12vPMAqlG2nF1B+vSwgA4GEHlG9rvl1WobIJfJaVPEbjMv5xLNepdmtm14oMXZUP0bDRmQ8VsyOYQspj5buLrEI0jD3eSmdgKsmazL/0BV+5AjiD5ltGyo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Jnxo2kga; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Jnxo2kga" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 793A4C116C6; Sat, 14 Jun 2025 08:56:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749891378; bh=JDTK8ds5rMEZTW9f7Wpcip/tbHM6fMKUON4aC7f9ZTc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jnxo2kgabhDXzSpfzf0kdqlxjfXWeYV1fURoZiC0VQCicHOQ5U2te0gdTHk3o9Ghd +iaOdCab93EbQ3V3PMSsF26JYOTOuz0XqNDIWWCtBY/TUNc5jKw6qpZuOGOQYIMRXu WgVIcuqRmhvWPCYM7YxMpZ/vQGEUeFVuNz9fYIqCVfzUtzgn+DJ1rYFxGyX2v/NXcH hMZuoVBRB3SLs58H7PaZN3m1jNV+1FngQcfVKuR2stYZEzncKvEi6ViR6GDKApdm82 SjIMRWmXG5X7WRKZ+siT8E0DKGhWRiEcIvOzISR/vmarQaL7wzPOWiQKap07Ns03hx S3TvudT1JdLpg== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uQMgS-000000064bX-2vAc; Sat, 14 Jun 2025 10:56:16 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , "Breno Leitao" , "David S. Miller" , "Donald Hunter" , "Eric Dumazet" , "Ignacio Encinas Rubio" , "Jan Stancek" , "Marco Elver" , "Mauro Carvalho Chehab" , "Paolo Abeni" , "Ruben Wauters" , "Shuah Khan" , joel@joelfernandes.org, linux-kernel-mentees@lists.linux.dev, linux-kernel@vger.kernel.org, lkmm@lists.linux.dev, netdev@vger.kernel.org, peterz@infradead.org, stern@rowland.harvard.edu Subject: [PATCH v4 14/14] docs: conf.py: properly handle include and exclude patterns Date: Sat, 14 Jun 2025 10:56:08 +0200 Message-ID: <2238d93ac08f9e6d3e88e0edfc6f58d13f5f9b68.1749891128.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" When one does: make SPHINXDIRS=3D"netlink/specs" htmldocs the build would break because a statically-defined pattern like: include_patterns =3D [ ... 'netlink/specs/*.yaml', ] would be pointing to Documentation/netlink/specs/netlink/specs, as the path there is relative. Also, when SPHINXDIRS is used, the exclude_pattern =3D [ "output" ] is also wrong. Fix conf.py to generate relative include/exclude patterns, relative to the SOURCEDIR sphinx-dir parameter. Signed-off-by: Mauro Carvalho Chehab --- Documentation/conf.py | 58 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/Documentation/conf.py b/Documentation/conf.py index 62a51ac64b95..be678bdf95d4 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -17,6 +17,52 @@ import os import sphinx import shutil =20 +# Location of Documentation/ directory +doctree =3D os.path.abspath('.') + +# List of patterns that don't contain directory names, in glob format. +include_patterns =3D ['**.rst'] +exclude_patterns =3D [] + +# List of patterns that contain directory names in glob format. +dyn_include_patterns =3D ['netlink/specs/**.yaml'] +dyn_exclude_patterns =3D ['output'] + +def setup(app): + """ + On Sphinx, all directories are relative to what it is passed as + SOURCEDIR parameter for sphinx-build. Due to that, all patterns + that have directory names on it need to be dynamically set, after + converting them to a relative patch. + + As Sphinx doesn't include any patterns outside SOURCEDIR, we should + exclude relative patterns that start with "../". + """ + + sourcedir =3D app.srcdir # full path to the source directory + builddir =3D os.environ.get("BUILDDIR") + + # setup include_patterns dynamically + for p in dyn_include_patterns: + full =3D os.path.join(doctree, p) + + rel_path =3D os.path.relpath(full, start =3D app.srcdir) + if rel_path.startswith("../"): + continue + + app.config.include_patterns.append(rel_path) + + # setup exclude_patterns dynamically + for p in dyn_exclude_patterns: + full =3D os.path.join(doctree, p) + + rel_path =3D os.path.relpath(full, start =3D app.srcdir) + if rel_path.startswith("../"): + continue + + app.config.exclude_patterns.append(rel_path) + + # helper # ------ =20 @@ -220,18 +266,6 @@ language =3D 'en' # Else, today_fmt is used as the format for a strftime call. #today_fmt =3D '%B %d, %Y' =20 -# List of patterns, relative to source directory, that match files and -# directories. -include_patterns =3D [ - '**.rst', - 'netlink/specs/*.yaml', -] - -# patterns to ignore when looking for source files. -exclude_patterns =3D [ - 'output', -] - # The reST default role (used for this markup: `text`) to use for all # documents. #default_role =3D None --=20 2.49.0