# Copyright (C) 2012-2018, 2024, 2026  Luke T. Shumaker <lukeshu@parabola.nu>
# Copyright (C) 2024  Bill Auger <bill-auger@programmer.net>
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This file is part of Parabola Libretools.
#
# Libretools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Libretools 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

include $(dir $(lastword $(MAKEFILE_LIST)))/config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk

libretools.out.mans =
libretools.out.bins =
libretools.out.libexecs =
libretools.out.libs =
libretools.out.docs =
libretools.out.confs =

files.src.gen += .srcversion-libretools.mk .srcversion-devtools.mk
nested.subdirs = src po

# 'check' ######################################################################

$(outdir)/check:
	cd $(@D)/test && ./testenv bats $(BATS_FLAGS) cases

# 'lint' #######################################################################

$(outdir)/lint:
	@$(MAKE) -k --no-print-directory $(addprefix $(outdir)/lint/,$(linters))
.PHONY: $(outdir)/lint
at.targets += $(outdir)/lint

linters  = editorconfig
linters += no-emacs-config
linters += no-vim-config
linters += trailing-ws
linters += indent
linters += shfmt
linters += copyright-headers
linters += license-headers
linters += authors

lint-should-be-empty = [[ -z "$$(tee /dev/stderr)" ]]

$(outdir)/lint/editorconfig:
	@for file in $(addprefix $(srcdir)/,$(_gitfiles.all)); do \
	  if editorconfig $$PWD/$$file | grep -q '^_mode=unknown'; then \
	    echo ".editorconfig: no section for $$file"; \
	  fi; \
	done | $(lint-should-be-empty)
$(outdir)/lint/no-emacs-config:
	@grep -an '[-][*][-]' -- $(addprefix $(srcdir)/,$(_gitfiles.all)) | \
	  sed -E 's/^([^:]+:[0-9]+:).*/\1 Emacs config line, use .editorconfig or .dir-locals.el instead/' | \
	  $(lint-should-be-empty)
$(outdir)/lint/no-vim-config:
	@grep -an '[v][i][m][:]' -- $(addprefix $(srcdir)/,$(_gitfiles.all)) | \
	  sed -E 's/^([^:]+:[0-9]+:).*/\1 Vim config line, use .editorconfig instead/' | \
	  $(lint-should-be-empty)
$(outdir)/lint/trailing-ws:
	@grep -an $$'[ \t]$$' -- $(addprefix $(srcdir)/,$(_gitfiles.all)) | \
	  sed -E 's/^([^:]+:[0-9]+:).*/\1 trailing whitespace/' | \
	  $(lint-should-be-empty)
$(outdir)/lint/indent:
	@for file in $(addprefix $(srcdir)/,$(_gitfiles.all)); do \
	  case "$$(editorconfig $$PWD/$$file | sed -n 's/^_mode=//p')" in \
	    make|tar) continue ;; \
	  esac; \
	  style="$$(editorconfig $$PWD/$$file | sed -n 's/^indent_style=//p')"; \
	  case "$$style" in \
	    space) grep -aHn $$'^\t' $$file | sed -E 's/^([^:]+:[0-9]+:).*/\1 has tab when it should have space/' ;; \
	    tab)   grep -aHn '^ '    $$file | sed -E 's/^([^:]+:[0-9]+:).*/\1 has space when it should have tab/' ;; \
	    *)     echo ".editorconfig: $$file: unknown indent_style=$${style@Q}" ;; \
	  esac; \
	done | $(lint-should-be-empty)
$(outdir)/lint/shfmt:
	@for file in $(addprefix $(srcdir)/,$(_gitfiles.all)); do \
	  if editorconfig "$$PWD/$$file" | grep -q -e ^shell_variant=; then \
	    echo "$$file"; \
	  fi; \
	done | \
	  xargs -r shfmt --list -- | \
	  sed 's/$$/: not formatted with shfmt/' | \
	  $(lint-should-be-empty)

non-copyright-globs  = COPYIN%
non-copyright-globs += AUTHORS.md
non-copyright-globs += test/fixtures/%
non-copyright-globs += %.conf
non-copyright-globs += %.conf.in
non-copyright-globs += config.mk
non-copyright-globs += po/header.po.head.in
non-copyright-globs += build-aux/license-headers/%.re

$(outdir)/build-aux/license-headers.re: $(srcdir)/build-aux/license-headers $(addprefix $(srcdir)/,$(filter build-aux/license-headers/%.re,$(_gitfiles.all)))
	for f in $(filter %.re,$^); do <"$$f" tr $$'\n' $$'\r' | sed -E -e $$'s/\r/\\\\n/g' -e 's/(\\n)*$$/|/'; done | sed 's/|$$//' >$@
at.targets += $(outdir)/build-aux/license-headers.re

$(outdir)/lint/copyright-headers: $(outdir)/build-aux/license-headers.re
	@grep -aL '^[#; ]*Copyright ([Cc]) [0-9]' -- $(addprefix $(srcdir)/,$(filter-out $(non-copyright-globs),$(_gitfiles.all))) | \
	  sed 's/$$/: does not have a copyright header/' | \
	  $(lint-should-be-empty)
	@grep -aHn '^[#; ]*Copyright ([Cc]) [0-9]' -- $(addprefix $(srcdir)/,$(filter-out $(non-copyright-globs),$(_gitfiles.all))) | \
	  grep -avE '^([^:]+:[0-9]+:)[#; ]*Copyright \(C\) [0-9]{4}(-[0-9]{4})?(, [0-9]{4}(-[0-9]{4})?)*  [^-0-9,\n ]' | \
	  sed -E 's/^([^:]+:[0-9]+:).*/\1 malformed copyright line/' | \
	  $(lint-should-be-empty)
	@for file in $(addprefix $(srcdir)/,$(filter-out $(non-copyright-globs),$(_gitfiles.all))); do \
	  diff=$$(diff -u \
	    <(grep -a '^[#; ]*Copyright (C) [0-9]' -- "$$file") \
	    <(grep -azPo -f $< -- "$$file" | grep -a Copyright) | \
	    sed 1,2d); \
	  if [[ -n "$$diff" ]]; then \
	    echo "$$file: has copyright statements separate from license statement:"; \
	    sed 's/^/  /' <<<"$$diff"; \
	  fi; \
	done | $(lint-should-be-empty)

$(outdir)/lint/license-headers: $(outdir)/build-aux/license-headers.re
	@grep -aLzP -f $< -- $(addprefix $(srcdir)/,$(filter-out $(non-copyright-globs),$(_gitfiles.all))) | \
	  sed 's/$$/: does not have a valid license header/' | \
	  $(lint-should-be-empty)

$(outdir)/lint/authors:
	@{ \
	  copyright_only=$$(comm -23 \
	    <(grep -ah '^[#; ]*Copyright (C) [0-9]' -- $(addprefix $(srcdir)/,$(filter-out $(non-copyright-globs),$(_gitfiles.all))) | sed 's/^[#; ]*Copyright (C) [-0-9, ]*//' | sort -u) \
	    <(sed -n 's/^- //p' AUTHORS.md | sort -u)); \
	  if [[ -n "$$copyright_only" ]]; then \
	    echo 'The following idents are mentioned in "Copyright (C)" statements, but not in AUTHORS.md:'; \
	    sed 's/^/  /' <<<"$$copyright_only"; \
	    exit 1; \
	  fi >&2; \
	}

.PHONY: $(addprefix $(outdir)/lint/,$(linters))
at.targets += $(addprefix $(outdir)/lint/,$(linters))

$(outdir)/shellcheck: private shellcheck.flags = --exclude=1090,1091,2016,2059,2064,2164,2191
$(outdir)/shellcheck: private shellcheck.prune = -false
$(outdir)/shellcheck: private shellcheck.prune += -o -type d -name doc
$(outdir)/shellcheck: private shellcheck.prune += -o -type d -name man
$(outdir)/shellcheck: private shellcheck.prune += -o -type f -name indent
$(outdir)/shellcheck: private shellcheck.prune += -o -type f -name Makefile
$(outdir)/shellcheck: private shellcheck.prune += -o -type f -name makepkg.gen
$(outdir)/shellcheck: private shellcheck.prune += -o -type f -name source.sh.gen
$(outdir)/shellcheck:
	cd $(@D)/test && ./testenv 'cd "$$TMPDIR/destdir" && find \( $(shellcheck.prune) \) -prune -o -not -type d -exec shellcheck $(shellcheck.flags) {} +'

# 'format' #####################################################################

$(outdir)/format: $(outdir)/format/shfmt .WAIT $(outdir)/msgmerge
.PHONY: $(outdir)/format
at.targets += $(outdir)/format

$(outdir)/format/shfmt:
	@for file in $(addprefix $(srcdir)/,$(_gitfiles.all)); do \
	  if editorconfig "$$PWD/$$file" | grep -q -e ^shell_variant=; then \
	    echo "$$file"; \
	  fi; \
	done | xargs -r -t shfmt --write --
.PHONY: $(outdir)/format/shfmt
at.targets += $(outdir)/format/shfmt

$(outdir)/msgmerge: $(call at.path,$(outdir)/po/msgmerge)
.PHONY: $(outdir)/msgmerge
at.targets += $(outdir)/msgmerge

# Footer #######################################################################

include $(topsrcdir)/build-aux/Makefile.tail.mk
