# HG changeset patch
# User Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>
# Date 1627998225 -7200
#      Tue Aug 03 15:43:45 2021 +0200
# Node ID 8ffb3e012ba702063757813a24b29a0c0ea27606
# Parent  e38cee9c00b722cbbea25ffd7878947d4657fffd
📚 add autotodo.py to generate autotodo (referenced in TODO.rst)

diff --git a/doc/Makefile b/doc/Makefile
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -3,11 +3,12 @@
 
 # You can set these variables from the command line, and also
 # from the environment for the first two.
-SPHINXOPTS    ?=
-SPHINXBUILD   ?= sphinx-build
-SOURCEDIR     = .
-BUILDDIR      = _build
-LANGUAGE      ?= en
+SPHINXOPTS     ?=
+SPHINXBUILD    ?= sphinx-build
+SOURCEDIR      = .
+BUILDDIR       = _build
+LANGUAGE       ?= en
+BUILDDIRSUFFIX =
 
 .PHONY: help Makefile gettext update_locale clean
 
@@ -17,15 +18,20 @@
 
 clean:
 	rm -rf $(BUILDDIR)/*
+	rm -f autotodo
+
+# depends on autotodo.py but that does not work well with the catch-all below
+autotodo:
+	@./autotodo.py ../ .py TODO,FIXME,XXX
 
 gettext: Makefile
 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)$(BUILDDIRSUFFIX)" $(SPHINXOPTS) $(O)
 
-# used to update *.po files
+# Use to update *.po files
 update_locale: Makefile gettext
 	@sphinx-intl update -p "$(BUILDDIR)$(BUILDDIRSUFFIX)/gettext" -l $(LANGUAGE)
 
 # Catch-all target: route all unknown targets to Sphinx using the new
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
+%: Makefile autotodo
 	@$(SPHINXBUILD) -b $@ "$(SOURCEDIR)" "$(BUILDDIR)/$@/$(LANGUAGE)$(BUILDDIRSUFFIX)" -d "$(BUILDDIR)$(BUILDDIRSUFFIX)/doctrees/$(LANGUAGE)" $(SPHINXOPTS) -D language=$(LANGUAGE) $(O)
diff --git a/doc/autotodo.py b/doc/autotodo.py
new file mode 100755
--- /dev/null
+++ b/doc/autotodo.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2014, 2018 XCG Consulting
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import os
+import os.path
+import sys
+
+
+def main():
+    if len(sys.argv) != 4:
+        print("usage: autotodo.py <folder> <exts> <tags>")
+        sys.exit(1)
+
+    folder = sys.argv[1]
+    exts = sys.argv[2].split(",")
+    tags = sys.argv[3].split(",")
+    todolist = {tag: [] for tag in tags}
+
+    for root, dirs, files in os.walk(folder):
+        scan_folder((exts, tags, todolist), root, files)
+    create_autotodo(folder, todolist)
+
+
+def write_info(f, infos, folder):
+    # Check sphinx version for lineno-start support
+
+    import sphinx
+
+    if sphinx.version_info < (1, 3):
+        lineno_start = False
+    else:
+        lineno_start = True
+
+    for i in infos:
+        path = i[0]
+        line = i[1]
+        lines = (line - 3, line + 4)
+        class_name = ":class:`%s`" % os.path.basename(
+            os.path.splitext(path)[0]
+        )
+        f.write(
+            "%s\n"
+            "%s\n\n"
+            "Line %s\n"
+            "\t.. literalinclude:: %s\n"
+            "\t\t:language: python\n"
+            "\t\t:lines: %s-%s\n"
+            "\t\t:emphasize-lines: %s\n"
+            % (
+                class_name,
+                "-" * len(class_name),
+                line,
+                path,
+                lines[0],
+                lines[1],
+                line,
+            )
+        )
+        if lineno_start:
+            f.write("\t\t:lineno-start: %s\n" % lines[0])
+        f.write("\n")
+
+
+def create_autotodo(folder, todolist):
+    with open("autotodo", "w+") as f:
+        for tag, info in list(todolist.items()):
+            f.write("%s\n%s\n\n" % (tag, "=" * len(tag)))
+            write_info(f, info, folder)
+
+
+def scan_folder(data_tuple, dirname, names):
+    (exts, tags, res) = data_tuple
+    file_info = {}
+    for name in names:
+        (root, ext) = os.path.splitext(name)
+        if ext in exts:
+            file_info = scan_file(os.path.join(dirname, name), tags)
+            for tag, info in list(file_info.items()):
+                if info:
+                    res[tag].extend(info)
+
+
+def scan_file(filename, tags):
+    res = {tag: [] for tag in tags}
+    with open(filename, "r") as f:
+        for line_num, line in enumerate(f):
+            for tag in tags:
+                if tag in line:
+                    res[tag].append((filename, line_num, line[:-1].strip()))
+    return res
+
+
+if __name__ == "__main__":
+    main()