From a81d3c0ac01e622a81a41ffb8d9b053ce23f92ac Mon Sep 17 00:00:00 2001
From: Patrick Baudin <patrick.baudin@cea.fr>
Date: Mon, 13 Jun 2022 10:49:53 +0200
Subject: [PATCH] [Lint] using .gitattributes for lint target

---
 .git-blame-ignore-revs |   1 +
 .gitattributes         |  11 +++
 share/Makefile.linting | 193 ++++++++++++++++++++---------------------
 3 files changed, 107 insertions(+), 98 deletions(-)

diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index ba943a12c94..59694ae9ee4 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -33,3 +33,4 @@ a767fdcb7adda81a5ef192733ef7c62fd56b30e2
 4130bab7a8b59d0c94a22d792b2a7d5a26d3484d
 237d1bc71eb5efb7c5f32a097aacb90f90e0ff73
 6cc1a6f2036b75c6b2451518ffbfbe025eb1a1f8
+1b7754fe7325a59ddbba62842a4bd907b0af6036
diff --git a/.gitattributes b/.gitattributes
index ed8149fe409..e5a0c4bfdff 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -15,6 +15,17 @@ Changelog merge=union
 
 *.pdf binary
 
+##################################
+# CHECK-SYNTAX/INDENT: set/unset #
+##################################
+
+# SET
+*.ml check-syntax check-indent
+*.mli check-syntax check-indent
+
+# UNSET
+/doc/**/*.ml* -check-syntax -check-indent
+
 #########################
 # HEADER_SPEC: CEA_LGPL #
 #########################
diff --git a/share/Makefile.linting b/share/Makefile.linting
index 163f4a5f743..2ffa4583a86 100644
--- a/share/Makefile.linting
+++ b/share/Makefile.linting
@@ -20,124 +20,129 @@
 #                                                                        #
 ##########################################################################
 
+.PHONY: check-ocp-indent-version
+check-ocp-indent-version:
+	if command -v ocp-indent >/dev/null; then \
+		if [ -z "$(shell ocp-indent --version)" ]; then echo "warning: ocp-indent returned an empty string, assuming it is the correct version"; \
+		else \
+			$(eval ocp_version_major := $(shell ocp-indent --version | $(SED) -E "s/^([0-9]+)\.[0-9]+\..*/\1/")) \
+			$(eval ocp_version_minor := $(shell ocp-indent --version | $(SED) -E "s/^[0-9]+\.([0-9]+)\..*/\1/")) \
+			if [ "$(ocp_version_major)" -lt 1 -o "$(ocp_version_minor)" -lt 7 ]; then \
+				echo "error: ocp-indent 1.7.0 required for linting (got $(ocp_version_major).$(ocp_version_minor))"; \
+			exit 1; \
+			fi; \
+		fi; \
+	else \
+		exit 1; \
+	fi;
+
 ################################
 # Code prettyfication and lint #
 ################################
 
-# We're interested by any .ml[i]? file in src, except for scripts in test
-# directories, and generated files (in particular lexers and parsers)
-# Note: the find command below is *very* ugly, but it should be POSIX-compliant.
+LINT.HAS_GIT:=$(wildcard .git)
+ifeq ($(LINT.HAS_GIT),)
 
-ALL_ML_FILES:=$(shell find src -name '*.ml' -print -o -name '*.mli' -print -o -path '*/tests' -prune '!' -name '*')
-ALL_ML_FILES+=ptests/ptests.ml ptests/wtests.ml
+.PHONY:
+lint:
+	echo "lint target requires git"
 
-ifeq ($(origin MANUAL_ML_FILES),undefined)
-MANUAL_ML_FILES:=$(ALL_ML_FILES)
-endif
 
-MANUAL_ML_FILES:=\
-  $(filter-out $(GENERATED) $(PLUGIN_GENERATED_LIST), $(MANUAL_ML_FILES))
+.PHONY: stats-lint
+stats-lint:
+	echo "stats-lint: deprecated target"
 
-# Allow control of files to be linted/fixed by external sources
-# (e.g. pre-commit hook that will concentrate on files which have changed)
+else
 
-sinclude .Makefile.lint
+.PHONY:
+lint:
+	git ls-files -z | git check-attr --stdin -z check-syntax \
+        | sed -zne 'x;n;n;s/^set$$//;t print;b;:print;x;p' \
+        | xargs --null -IXX sh -c 'make LINT_FILE="XX" check-syntax || exit 255'
+	git ls-files -z | git check-attr --stdin -z check-indent \
+        | sed -zne 'x;n;n;s/^set$$//;t print;b;:print;x;p' \
+        | xargs --null -IXX sh -c 'make LINT_FILE="XX" check-indent || exit 255'
 
-HAS_GIT_FILE:=$(wildcard .git/HEAD)
+.PHONY: stats-lint
+stats-lint:
+	echo "stats-lint: deprecated target"
 
-ifeq ("$(HAS_GIT_FILE)","")
-LINT_OTHER_SOURCES:=
-else
-LINT_OTHER_SOURCES:=\
-  $(filter-out \
-    $(shell git ls-tree --name-only HEAD src/plugins/*), \
-    $(wildcard src/plugins/*))
 endif
 
-$(foreach dir,$(LINT_OTHER_SOURCES),$(eval sinclude $(dir)/.Makefile.lint))
+##############################################################
 
-ML_LINT_MISSING:=$(filter-out $(MANUAL_ML_FILES), $(ML_LINT_KO))
+LINT_FILE.list=$(wildcard $(LINT_FILE))
+LINT_FILE.target=$(join $(dir $(LINT_FILE.list)),$(addprefix .lint/.%,$(notdir $(LINT_FILE.list))))
 
-# By default, also checks files with unknown status:
-# this requires new files to pass lint checker from the beginning
+define fix_indent_rule
+$(dir $(1)).fix-indent/.$(notdir $(1)).lint-test: $(1)
+	mkdir -p $$(dir $$@)
+	touch $$@
+endef
 
-ML_LINT_CHECK?=$(filter-out $(ML_LINT_KO), $(MANUAL_ML_FILES))
+$(foreach file,$(LINT_FILE.list),$(eval $(call fix_indent_rule,$(file))))
 
-# this NEWLINE variable containing a literal newline character is used to avoid
-# the error "argument list too long", in some instances of "foreach".
-# For details, see https://stackoverflow.com/questions/7039811
-define NEWLINE
 
+LINT_FILE.lint-test= $(addsuffix .lint-test,$(LINT_FILE.list))
+.PHONY: lint-test
+lint-test: $(LINT_FILE.lint-test)
 
-endef
+xxx:
+	echo "list=$(LINT_FILE.list)"
+	echo "lint-test=$(LINT_FILE.lint-test)"
 
-# pre-requisite intentionally left blank: this target should only be used
-# if the file is not present to generate it once and forall,
-# and be edited manually afterwards
-# double colon here tells make not to attempt updating the .Makefile.lint
-# if it does not exist, but just to ignore it.
-.Makefile.lint::
-	echo "ML_LINT_KO:=" >> $@
-	$(foreach file,$(sort $(MANUAL_ML_FILES)), \
-            if ! $(MAKE) ML_LINT_CHECK=$(file) lint; \
-            then echo "ML_LINT_KO+=$(file)" >> $@; fi;$(NEWLINE) )
-
-$(foreach dir,$(LINT_OTHER_SOURCES),\
-  $(eval $(dir)/.Makefile.lint:: ; \
-     $(foreach file, $(sort $(filter $(dir)/%, $(MANUAL_ML_FILES))), \
-            if ! $$(MAKE) ML_LINT_CHECK=$(file) lint; \
-            then echo "ML_LINT_KO+=$(file)" >> $$@; fi; )))
+########################
 
-.PHONY: stats-lint
-stats-lint:
-	echo \
-         "scale = 2; bad = $(words $(ML_LINT_MISSING)); \
-          all = $(words $(sort $(MANUAL_ML_FILES))); \
-	  fail = $(words $(ML_LINT_KO)); \
-          \"lint coverage: \"; \
-          ((all - fail) * 100) / all; " | bc
-	echo "number of files supposed to pass lint: $(words $(ML_LINT_CHECK))"
-	echo "number of files supposed to fail lint: $(words $(ML_LINT_KO))"
-ifneq ($(strip $(ML_LINT_MISSING)),)
-	echo "number of files missing from src/ : $(words $(ML_LINT_MISSING))"
-	$(foreach file, $(ML_LINT_MISSING), echo $(file);)
-	exit 1
-endif
 
-INDENT_TARGET= $(patsubst %,%.indent,$(ML_LINT_CHECK))
 
-LINT_TARGET= $(patsubst %,%.lint,$(ML_LINT_CHECK))
+LINT_FILE.check-syntax= $(addsuffix .check-syntax,$(LINT_FILE.list))
+LINT_FILE.check-indent= $(addsuffix .check-indent,$(LINT_FILE.list))
 
-FIX_SYNTAX_TARGET=$(patsubst %,%.fix-syntax,$(ML_LINT_CHECK))
+LINT_FILE.fix-syntax= $(addsuffix .fix-syntax,$(LINT_FILE.list))
+LINT_FILE.fix-indent= $(addsuffix .fix-indent,$(LINT_FILE.list))
 
-.PHONY: $(INDENT_TARGET) $(LINT_TARGET) $(FIX_SYNTAX_TARGET) \
-        indent lint fix-syntax
 
-indent: $(INDENT_TARGET)
+lint.info:
+	echo "LINT.HAS_GIT='$(LINT.HAS_GIT)'"
+	echo "LINT_FILE.list='$(LINT_FILE.list)'"
 
-lint:: $(LINT_TARGET)
+###############################
 
-check-ocp-indent-version:
-	if command -v ocp-indent >/dev/null; then \
-		if [ -z "$(shell ocp-indent --version)" ]; then echo "warning: ocp-indent returned an empty string, assuming it is the correct version"; \
-		else \
-			$(eval ocp_version_major := $(shell ocp-indent --version | $(SED) -E "s/^([0-9]+)\.[0-9]+\..*/\1/")) \
-			$(eval ocp_version_minor := $(shell ocp-indent --version | $(SED) -E "s/^[0-9]+\.([0-9]+)\..*/\1/")) \
-			if [ "$(ocp_version_major)" -lt 1 -o "$(ocp_version_minor)" -lt 7 ]; then \
-				echo "error: ocp-indent 1.7.0 required for linting (got $(ocp_version_major).$(ocp_version_minor))"; \
-			exit 1; \
-			fi; \
-		fi; \
-	else \
-		exit 1; \
-	fi;
+.PHONY: check-syntax $(LINT_FILE.check-syntax)
+check-syntax: $(LINT_FILE.check-syntax)
+
+.PHONY: fix-syntax $(LINT_FILE.fix-syntax)
+fix-syntax: $(LINT_FILE.fix-syntax)
+
+.PHONY: check-indent $(LINT_FILE.check-indent)
+check-indent: $(LINT_FILE.check-indent)
 
-fix-syntax: $(FIX_SYNTAX_TARGET)
+.PHONY: fix-indent $(LINT_FILE.fix-indent)
+fix-indent: $(LINT_FILE.fix-indent)
 
-$(INDENT_TARGET): %.indent: % check-ocp-indent-version
+###############################
+## INDENTATION ASPECT
+
+$(LINT_FILE.check-indent): %.check-indent: % check-ocp-indent-version
+	ocp-indent $< > $<.tmp
+	if cmp -s $< $<.tmp; \
+        then rm -f $<.tmp; \
+        else \
+          echo "File $< is not indented correctly."; \
+          echo "Please run: make LINT_FILE=$< fix-indent";\
+          rm $<.tmp; \
+          exit 1; \
+        fi
+
+$(LINT_FILE.fix-indent): %.fix-indent: % check-ocp-indent-version
+	echo "Fixes indent: $<"
 	ocp-indent -i $<
 
-$(LINT_TARGET): %.lint: % check-ocp-indent-version
+
+###############################
+## SYNTACTICAL ASPECT
+
+$(LINT_FILE.check-syntax): %.check-syntax: %
 	# See SO 1825552 on mixing grep and \t (and cry)
 	# For OK_NL, we have three cases:
 	# - for empty files, the computation boils down to 0 - 0 == 0
@@ -154,20 +159,12 @@ $(LINT_TARGET): %.lint: % check-ocp-indent-version
           echo "$$OK_SPACE lines with spaces at end of line"; \
           test $$OK_NL -eq 0 || echo "No newline at end of file"; \
           test $$OK_EMPTY -eq 0 || echo "Empty line(s) at end of file"; \
-          echo "Please run make ML_LINT_CHECK=$< fix-syntax"; \
+          echo "Please run: make LINT_FILE=$< fix-syntax"; \
           exit 1 ; \
         fi
-	ocp-indent $< > $<.tmp;
-	if cmp -s $< $<.tmp; \
-        then rm -f $<.tmp; \
-        else \
-          echo "File $< is not indented correctly."; \
-          echo "Please run make ML_LINT_CHECK=$< indent";\
-          rm $<.tmp; \
-          exit 1; \
-        fi
-
-$(FIX_SYNTAX_TARGET): %.fix-syntax: %
+ 
+$(LINT_FILE.fix-syntax): %.fix-syntax: %
+	echo "Fixes syntax: $<"
 	$(ISED) -e 's/^ *\t\+/ /' $<
 	$(ISED) -e 's/\(.*[^[:blank:]]\)[[:blank:]]\+$$/\1/' $<
 	$(ISED) -e 's/^[ \t]\+$$//' $<
-- 
GitLab