]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1602] add tools/print-generated-files.sh
authorAndrei Pavel <andrei@isc.org>
Wed, 30 Dec 2020 10:35:31 +0000 (12:35 +0200)
committerAndrei Pavel <andrei@isc.org>
Wed, 30 Dec 2020 13:55:05 +0000 (15:55 +0200)
.gitlab-ci.yml
tools/print-generated-files.sh [new file with mode: 0755]

index f1bc0e6e29cfbe7bc7945101d6959cc6b4236bd4..daf5506072b66cfcc513e6e6f0ba2a1e00fb24bf 100644 (file)
@@ -90,6 +90,7 @@ shellcheck:
     - SCRIPTS+="tools/cql_config "
     - SCRIPTS+="tools/mk_cfgrpt.sh "
     - SCRIPTS+="tools/path_replacer.sh.in "
+    - SCRIPTS+="tools/print-generated-files.sh "
     - SCRIPTS+="tools/shellcheck-all.sh "
     - SCRIPTS+="tools/sysrepo_config "
     - SCRIPTS+="tools/tests_in_valgrind.sh "
@@ -131,3 +132,14 @@ missing-config-h-include:
     - FILES=$(tools/add-config-h.sh -n)
     - printf '%s\n' "${FILES}"
     - test -z "${FILES}"
+
+missing-git-attribute:
+  stage: test
+  image: "$CI_REGISTRY_IMAGE:latest"
+  tags:
+    - linux
+    - amd64
+  script:
+    - test -z $(git diff)
+    - ./tools/print-generated-files -a
+    - test -z $(git diff)
diff --git a/tools/print-generated-files.sh b/tools/print-generated-files.sh
new file mode 100755 (executable)
index 0000000..da0de42
--- /dev/null
@@ -0,0 +1,191 @@
+#!/bin/sh
+
+# Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Usage:
+#
+# ./tools/print-generated-files.sh [-d|--debug] [-h|--help] [-a|--amend]
+#
+# Run from the root of the repository to get the list of generated files. They
+# may or may not be part of the repository. These consist of messages, parser
+# files and built sources (as called in Makefile.am files). While messages and
+# parser files are included with the source files, the built sources are only
+# created when building or some of them included in the Kea installation.
+
+# shellcheck disable=SC2039
+# SC2039: In POSIX sh, 'local' is undefined.
+
+# shellcheck disable=SC2013
+# SC2013: To read lines rather than words, pipe/redirect to a 'while read' loop.
+# reason: `while read` reads lines, we need to read words
+
+# shellcheck disable=SC2044
+# SC2044: For loops over find output are fragile. Use find -exec or a while read loop.
+# reason: I need to embed complicated logic inside the for, avoiding SC2044
+# makes us run into other problems.
+
+# Exit with error if commands exit with non-zero and if undefined variables are
+# used.
+set -eu
+
+# Print usage.
+print_usage() {
+  printf \
+'Usage: %s {{options}}
+Options:
+  [-d|--debug]                 enable debug mode, showing every executed command
+  [-h|--help]                  print usage (this text)
+  [-a|--amend]                 amend tools/.generated-files.txt and .gitattributes
+' \
+    "$(basename "${0}")"
+}
+
+# Define some ANSI color codes.
+if test -t 1; then
+  red='\033[91m'
+  reset='\033[0m'
+else
+  red=
+  reset=
+fi
+
+# Parse parameters.
+while test ${#} -gt 0; do
+  case "${1}" in
+    # [-d|--debug]             enable debug mode, showing every executed command
+    '-d'|'--debug') set -vx ;;
+
+    # [-h|--help]              print usage (this text).
+    '-h'|'--help') print_usage ;;
+
+    # [-a|--amend]                 amend tools/.generated-files.txt and .gitattributes
+    '-a'|'--amend') amend=true ;;
+
+    # Unrecognized argument
+    *)
+    printf "${red}ERROR: Unrecognized argument '%s'${reset}\\n" "${1}" 1>&2; print_usage; exit 1 ;;
+  esac; shift
+done
+
+# Default parameters
+test -z "${amend+x}" && amend=false
+
+# Change directory to root path.
+root_path=$(cd "$(dirname "${0}")/.." && pwd)
+cd "${root_path}"
+
+# Check if given commands are available and if not, then warn the user that they
+# need to be installed for the script to work and then exit with error code.
+mandatory_commands() {
+  while test ${#} -gt 0; do
+    if ! command -v "${1}" > /dev/null 2>&1; then
+      printf "${red}%s${reset} is mandatory.\\n" "${1}" >&2
+      exit 3
+    fi
+    shift
+  done
+}
+
+# Print the lines between two matching regex patterns from a file. Excludes the
+# lines that contain the patterns themselves. Matches only the first occurence.
+print_lines_between_matching_patterns() {
+  mandatory_commands sed
+
+  local start_pattern=${1}; shift
+  local end_pattern=${1}; shift
+  local file=${1}; shift
+
+  # Escape all slashes.
+  start_pattern=$(printf '%s' "${start_pattern}" | sed 's#\/#\\\/#g')
+  end_pattern=$(printf '%s' "${end_pattern}" | sed 's#\/#\\\/#g')
+
+  # Print with sed.
+  sed -n "/${start_pattern}/,/${end_pattern}/p;/${end_pattern}/q" "${file}" \
+    | sed '$d' | tail -n +2
+}
+
+# Print file name if a file with that name exists.
+print_file_name() {
+  local file_name=${1}
+  if test -f "${file_name}"; then
+    printf '%s\n' "${file_name}" | cut -d '/' -f '2-'
+  fi
+}
+
+# Generated messages
+print_generated_messages() {
+  local makefile_am=${1}; shift
+  local directory=${1}; shift
+
+  # shellcheck disable=SC1003
+  # SC1003: Want to escape a single quote? echo 'This is how it'\''s done'
+  # reason: No, we don't want to escape a single quote, we want a backslash.
+  for j in $(grep -F 'messages:' "${makefile_am}" | cut -d ':' -f '2-' | \
+    cut -d '\' -f 1); do
+    print_file_name "${directory}/${j}"
+  done
+
+  # Include message files that span multiple lines in the Makefile.am.
+  for j in $(print_lines_between_matching_patterns 'messages:' '@echo' "${makefile_am}" | \
+    cut -d ':' -f '2-' | cut -d '\' -f 1); do
+    print_file_name "${directory}/${j}"
+  done
+}
+
+# Generated parsers
+print_generated_parsers() {
+  local makefile_am=${1}; shift
+  local directory=${1}; shift
+
+  for j in $(grep -F 'parser:' "${makefile_am}" | cut -d ':' -f '2-'); do
+    print_file_name "${directory}/${j}"
+  done
+}
+
+# Other generated files
+print_built_sources() {
+  local makefile_am=${1}; shift
+  local directory=${1}; shift
+
+  for j in $(grep -E 'BUILT_SOURCES (=|\+=)' "${makefile_am}" | cut -d '=' -f '2-'); do
+    print_file_name "${directory}/${j}"
+  done
+}
+
+# Print all files of interest sorted alphabetically.
+print_all_sorted() {
+  local built_sources=${1-true}
+
+  for i in $(find . -type f -name 'Makefile.am'); do
+    directory=$(dirname "${i}")
+    print_generated_messages "${i}" "${directory}"
+    print_generated_parsers "${i}" "${directory}"
+    if ${built_sources}; then
+      print_built_sources "${i}" "${directory}"
+    fi
+  done | sort -uV
+}
+
+mandatory_commands cut find grep sort
+
+if "${amend}"; then
+  # Write to tools/.generated-files.txt
+  print_all_sorted > ./tools/.generated-files.txt
+
+  # Write to .gitattributes.
+  find . -type f -name '.gitattributes' -exec rm -f {} \;
+  for i in $(print_all_sorted false); do
+    # Align to 32 characters.
+    name="/$(basename "${i}")"
+    length=$(( 32 - ${#name} ))
+
+    printf "%s%${length}s -diff merge=ours\\n" "${name}" ' ' >> \
+      "$(dirname "${i}")/.gitattributes"
+  done
+else
+  print_all_sorted
+fi