Enhance shellcheck lint target (3 of 3 -- lint-shell target logic)

makefiles/lint/shell/help.mk
----------------------------
  o Top level include used to source all lint-shell library makefiles.
  o Loosely based on makefiles/{groovy,doc8}/*.
  o Currently library makefile makefiles/shell.mk deprecation pending.
  o Prefix yet-to-be-added makefile includes with hyphen to prevent errors.

makefiles/lint/shell/shellcheck.sh
----------------------------------
  o Enhance makefiles/shell.mk to support more lint targets.
  o Three targets are now supported:
    - lint-shell-all   current behavior, run shellcheck on all sources
    - lint-shell-mod   new: lint locally modified files (~git status)
    - lint-shell-src   new: run shellcheck on a list of files passed in.
  o Added helper function gen-lint-shell-deps:
    - generate a list of dependency based on makefile target.
    - dependency list is assigned to a variable named for the target.
    - avoids having to inline duplicate construction around targets.
  o Each target lint-shell-{all,mod,src} defines a list of
    dependencies/files to launch shellcheck on.
  o Target dependency lists allowed replacing "find | xargs shellcheck"
    commands with an explicit per-source-to-check target.
  o Structure will also allow supporting exclusion lists in the future.

unit-testing:
Helper script mcheck.sh will create a usable sandbox from shellcheck patches to evaluate targets.
shellcheck (make lint-shell*) will report problems in bin/setup.sh:
  o https://wiki.opennetworking.org/display/VOLTHA/repo%3Aonf-make

Change-Id: Id6ed1f66f80e63b4cc1c857f56c1fa342635df62
diff --git a/makefiles/lint/shell/include.mk b/makefiles/lint/shell/include.mk
new file mode 100644
index 0000000..63797d5
--- /dev/null
+++ b/makefiles/lint/shell/include.mk
@@ -0,0 +1,29 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022-2023 Open Networking Foundation (ONF) and the ONF Contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -----------------------------------------------------------------------
+
+$(if $(DEBUG),$(warning ENTER))
+
+##--------------------##
+##---]  INCLUDES  [---##
+##--------------------##
+-include $(ONF_MAKEDIR)/lint/shell/help.mk
+-include $(ONF_MAKEDIR)/lint/shell/install.mk
+include $(ONF_MAKEDIR)/lint/shell/shellcheck.mk
+
+$(if $(DEBUG),$(warning LEAVE))
+
+# [EOF]
diff --git a/makefiles/lint/shell/shellcheck.mk b/makefiles/lint/shell/shellcheck.mk
new file mode 100644
index 0000000..5f9a03a
--- /dev/null
+++ b/makefiles/lint/shell/shellcheck.mk
@@ -0,0 +1,152 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022-2023 Open Networking Foundation (ONF) and the ONF Contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -----------------------------------------------------------------------
+
+$(if $(DEBUG),$(warning ENTER))
+
+##-------------------##
+##---]  GLOBALS  [---##
+##-------------------##
+.PHONY: lint-shell lint-shell-all lint-shell-mod lint-shell-src
+
+# Gather sources to check
+shell-check-find := find .
+shell-check-find += -name 'vendor' -prune
+shell-check-find += -o \( -name '*.sh' -o -name '*.bash' \)
+shell-check-find += -type f -print0
+
+# shell-check    := $(env-clean) shellcheck
+shell-check      := shellcheck
+
+shell-check-args += --check-sourced
+
+##------------------##
+##---]  MACROS  [---##
+##------------------##
+
+## -----------------------------------------------------------------------
+## Intent: Derive a list of dependencies when make builds a target by name
+## -----------------------------------------------------------------------
+## Given:
+##   target  - Makefile target name to check if evaluating
+##   listref - An indirect make variable containing a list of file paths
+##
+## Return:
+##   target  - Variable assigned a list of target dependencies
+## -----------------------------------------------------------------------
+## Usage: $(gen-lint-shell-deps,lint-shell-mod,BY_GIT)
+##    lint-shell-mod := foo bar tans fans
+##    lint-shell-mod : $(lint-shell-mod)
+##    $(lint-shell-mod):
+##        perform-action-on-one-dependency $@
+## -----------------------------------------------------------------------
+gen-lint-shell-deps =\
+  $(strip \
+    $(foreach target,$(1),\
+      $(if $(findstring $(target),$(MAKECMDGOALS)),\
+      $(foreach listref,$(2),\
+      $(eval $(target) := $(null))\
+      $(foreach path,$($(listref)),\
+        $(if $(DEBUG),$(info ** $$(eval $(target) += $(addprefix $(target)--,$(path)))))\
+        $(eval $(target) += $(addprefix $(target)--,$(path)))\
+      )\
+    )\
+    )\
+  )\
+)# gen-lint-shell-deps()
+
+##-------------------##
+##---]  TARGETS  [---##
+##-------------------##
+ifndef NO-LINT-SHELL # enabled(?)
+  lint : lint-shell
+endif
+
+## -----------------------------------------------------------------------
+## Conditional target: lint all source or source by name
+## -----------------------------------------------------------------------
+ifdef SHELL_SRC
+  lint-shell : lint-shell-src
+else
+  lint-shell : lint-shell-all
+endif
+
+## -----------------------------------------------------------------------
+## Intent: Perform a lint check on available sources
+##   1) Display shellcheck version
+##   2) Invoke shellcheck on all files with an *.sh extension
+## -----------------------------------------------------------------------
+lint-shell-all: lint-shellcheck-cmd-version
+
+    # $(call banner-enter,(Target $@))
+	$(env-clean) $(shell-check-find) \
+	    | $(xargs-n1) $(shell-check) $(shell-check-args)
+    # $(call banner-leave,(Target $@))
+
+## -----------------------------------------------------------------------
+## Intent: Perform lint check on a named list of files passed in
+##   1) Display shellcheck version
+##   2) Iterate and run shellcheck on each given file path.
+## -----------------------------------------------------------------------
+SHELL_SRC ?= $(error $(MAKE) $@ SHELL_SRC= is required)
+$(call gen-lint-shell-deps,lint-shell-src,SHELL_SRC)
+
+lint-shell-src: \
+  lint-shellcheck-cmd-version \
+  $(lint-shell-src)
+
+## -----------------------------------------------------------------------
+## Intent: Perform lint check on locally modified files
+##   1) Display shellcheck version
+##   2) Gather a list of locally modified files (~git status)
+##   3) Iterate and run shellcheck on each gathered file.
+## -----------------------------------------------------------------------
+BY_GIT = $(shell git diff --name-only HEAD | grep -e '\.sh')
+$(call gen-lint-shell-deps,lint-shell-mod,BY_GIT)
+
+lint-shell-mod :\
+  lint-shellcheck-cmd-version \
+  $(lint-shell-mod)
+
+## -----------------------------------------------------------------------
+## Intent: Workhorse target:
+##    1) gen-lint-shell-deps used to create target specific dependency lists.
+##    2) These dependencies are used to invoke shellcheck against a single
+##       path from the list.
+##    3) lint-shell-mod : $(lint-shell-mod)
+##       Named targets are dependent on a list of file to check.
+##    4) make lint-shell-mod
+##       Building a named target will force iteration, running shellcheck
+##       against each file path in the dependency list.
+## -----------------------------------------------------------------------
+.PHONY: $(lint-shell-mod)
+.PHONY: $(lint-shell-src)
+$(lint-shell-mod) $(lint-shell-src):
+	$(env-clean) $(shell-check) $(shell-check-args) $(lastword $(subst --,$(space),$@))
+
+$(if $(DEBUG),$(warning LEAVE))
+
+# [TODO]
+# -----------------------------------------------------------------------
+# Implement exclusion lists by appling $(filter-out $(lint-shell-excl))
+# against the list of files passed to gen-lint-shell-deps.  Not definining
+# a target dependency will inhibit runnig shellcheck on a file.
+
+# Ignore vendor/ scripts but they really should be lintable
+# lint-shell-excl += 'vendor'
+# -----------------------------------------------------------------------
+
+# [EOF]