[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/plz 05f93b0b6b 25/81: Meta: Update Makefile, makem.sh
From: |
ELPA Syncer |
Subject: |
[elpa] externals/plz 05f93b0b6b 25/81: Meta: Update Makefile, makem.sh |
Date: |
Wed, 11 May 2022 17:57:59 -0400 (EDT) |
branch: externals/plz
commit 05f93b0b6bcbb865aa6f8d2254c360c47e82b353
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>
Meta: Update Makefile, makem.sh
---
Makefile | 32 +++++-
makem.sh | 340 +++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 264 insertions(+), 108 deletions(-)
diff --git a/Makefile b/Makefile
index 9be2568ad1..5000738761 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,29 @@
-# * Verbosity
+# * Arguments
+
+# For consistency, we use only var=val options, not hyphen-prefixed options.
+
+# NOTE: I don't like duplicating the arguments here and in makem.sh,
+# but I haven't been able to find a way to pass arguments which
+# conflict with Make's own arguments through Make to the script.
+# Using -- doesn't seem to do it.
+
+ifdef auto-install
+ AUTO_INSTALL = "--auto-install"
+endif
+
+ifdef sandbox
+ SANDBOX = "--sandbox"
+endif
+
+ifdef sandbox-dir
+ SANDBOX_DIR = "--sandbox-dir" "$(sandbox-dir)"
+endif
+
+ifdef debug
+ DEBUG = "--debug"
+endif
+
+# ** Verbosity
# Since the "-v" in "make -v" gets intercepted by Make itself, we have
# to use a variable.
@@ -13,5 +38,8 @@ endif
# * Rules
+# TODO: Handle cases in which "test" or "tests" are called and a
+# directory by that name exists, which can confuse Make.
+
%:
- @./makem.sh $(VERBOSE) $(@)
+ @./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(SANDBOX_DIR)
$(AUTO_INSTALL) $(@)
diff --git a/makem.sh b/makem.sh
index 67a92dbd5b..40c49c5a2b 100755
--- a/makem.sh
+++ b/makem.sh
@@ -2,8 +2,32 @@
# * makem.sh --- Script to aid building and testing Emacs Lisp packages
+# https://github.com/alphapapa/makem.sh
+
# * Commentary:
+# makem.sh is a script helps to build, lint, and test Emacs Lisp
+# packages. It aims to make linting and testing as simple as possible
+# without requiring per-package configuration.
+
+# It works similarly to a Makefile in that "rules" are called to
+# perform actions such as byte-compiling, linting, testing, etc.
+
+# Source and test files are discovered automatically from the
+# project's Git repo, and package dependencies within them are parsed
+# automatically.
+
+# Output is simple: by default, there is no output unless errors
+# occur. With increasing verbosity levels, more detail gives positive
+# feedback. Output is colored by default to make reading easy.
+
+# When desired, emacs-sandbox.sh can be used as a backend, which
+# allows package dependencies to be installed automatically into a
+# clean Emacs "sandbox" configuration without affecting the
+# developer's personal configuration. This is especially helpful when
+# upstream dependencies may have released new versions that differ
+# from those installed in the developer's personal configuration. See
+# <https://github.com/alphapapa/emacs-sandbox.sh>.
# * License:
@@ -20,63 +44,56 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
-# * Safety
-
-# NOTE: These are disabled by default in this template but should be
-# enabled when feasible. Documentation is from the Bash man page.
+# * Functions
-# ** errexit
+function usage {
+ cat <<EOF
+$0 [OPTIONS] RULES...
-# Exit immediately if a pipeline (which may consist of a single simple
-# command), a list, or a compound command (see SHELL GRAMMAR above),
-# exits with a non-zero status. The shell does not exit if the
-# command that fails is part of the command list immediately following
-# a while or until keyword, part of the test following the if or elif
-# reserved words, part of any command executed in a && or || list
-# except the command follow‐ ing the final && or ||, any command in a
-# pipeline but the last, or if the command's return value is being
-# inverted with !. If a compound command other than a subshell
-# returns a non-zero status because a command failed while -e was
-# being ignored, the shell does not exit. A trap on ERR, if set, is
-# executed before the shell exits. This option applies to the shell
-# environment and each subshell environment separately (see COMMAND
-# EXECUTION ENVIRONMENT above), and may cause subshells to exit before
-# executing all the commands in the subshell.
+Rules:
+ all Run all lints and tests.
+ compile Byte-compile source files.
-# If a compound command or shell function executes in a context where
-# -e is being ignored, none of the commands executed within the
-# compound command or function body will be affected by the -e
-# setting, even if -e is set and a command returns a failure status.
-# If a compound command or shell function sets -e while executing in a
-# context where -e is ignored, that setting will not have any effect
-# until the compound command or the command containing the function
-# call completes.
+ lint Run all lints.
+ lint-checkdoc Run checkdoc.
+ lint-compile Byte-compile source files with warnings as errors.
+ lint-package Run package-lint.
-# set -o errexit
+ test, tests Run all tests.
+ test-buttercup Run Buttercup tests.
+ test-ert Run ERT tests.
-# ** nounset
+Options:
+ -d, --debug Print debug info.
+ -h, --help I need somebody!
+ -v, --verbose Increase verbosity, up to -vv.
+ --debug-load-path Print load-path.
-# Treat unset variables and parameters other than the special
-# parameters "@" and "*" as an error when performing parameter
-# expansion. If expansion is attempted on an unset variable or
-# parameter, the shell prints an error message, and, if not
-# interactive, exits with a non-zero status.
+ -f FILE, --file FILE Check FILE in addition to discovered files.
-# NOTE: When this is not enabled, individual variables can be required
-# to be set by using "${var:?}" parameter expansion syntax.
+ --no-color Disable color output.
+ -C, --no-compile Don't compile files automatically.
-# set -o nounset
+Sandbox options:
+ These require emacs-sandbox.sh to be on your PATH. Find it at
+ <https://github.com/alphapapa/emacs-sandbox.sh>.
-# ** pipefail
+ -s, --sandbox Run Emacs with emacs-sandbox.sh in a temporary
+ directory (removing directory on exit).
+ -S, --sandbox-dir DIR Use DIR for the sandbox directory (leaving it
+ on exit). Implies -s.
+ --auto-install Automatically install package dependencies.
+ -i, --install PACKAGE Install PACKAGE before running rules.
-# If set, the return value of a pipeline is the value of the last
-# (rightmost) command to exit with a non-zero status, or zero if all
-# commands in the pipeline exit successfully. This option is disabled
-# by default.
+Source files are automatically discovered from git, or may be
+specified with options.
-# set -o pipefail
+Package dependencies are discovered from "Package-Requires" headers in
+source files and from a Cask file.
+EOF
+}
-# * Elisp
+# ** Elisp
# These functions return a path to an elisp file which can be loaded
# by Emacs on the command line with -l or --load.
@@ -140,26 +157,24 @@ EOF
echo $file
}
-# * Functions
-
# ** Emacs
function run_emacs {
- debug "run_emacs: emacs -Q --batch --load=$package_initialize_file -L
\"$load_path\" $@"
+ debug "run_emacs: $emacs_command -Q --batch
--load=$package_initialize_file -L \"$load_path\" $@"
if [[ $debug_load_path ]]
then
- debug $(emacs -Q --batch \
- --load=$package_initialize_file \
- -L "$load_path" \
- --eval "(message \"LOAD-PATH: %s\" load-path)" \
- 2>&1)
+ debug $($emacs_command -Q --batch \
+ --load=$package_initialize_file \
+ -L "$load_path" \
+ --eval "(message \"LOAD-PATH: %s\" load-path)" \
+ 2>&1)
fi
output_file=$(mktemp)
- emacs -Q --batch \
- --load=$package_initialize_file \
- -L "$load_path" \
- "$@" \
+ $emacs_command -Q --batch \
+ --load=$package_initialize_file \
+ -L "$load_path" \
+ "$@" \
&>$output_file
exit=$?
@@ -195,17 +210,27 @@ function project-elisp-files {
function project-source-files {
# Echo list of Elisp files that are not tests.
- project-elisp-files | egrep -v '^tests?/test-?'
+ project-elisp-files | egrep -v "$test_files_regexp" | feature-files
}
function project-test-files {
# Echo list of Elisp test files.
- project-elisp-files | egrep '^tests?/test-?'
+ project-elisp-files | egrep "$test_files_regexp"
}
function exclude-files {
# Filter out paths (STDIN) which should be excluded by default.
- egrep -v "(/\.cask/|-autoloads.el)"
+ egrep -v "(/\.cask/|-autoloads.el|.dir-locals)"
+}
+
+function feature-files {
+ # Read paths on STDIN and echo ones that (provide 'a-feature).
+ while read path
+ do
+ debug "PATH: $path"
+ egrep "^\\(provide '" "$path" &>/dev/null \
+ && echo "$path"
+ done
}
function load-files-args {
@@ -224,6 +249,48 @@ function files_args {
done
}
+function test-files-p {
+ # Return 0 if $project_test_files is non-empty.
+ [[ "${project_test_files[@]}" ]]
+}
+
+function buttercup-tests-p {
+ # Return 0 if Buttercup tests are found.
+ test-files-p || die "No tests found."
+ debug "Checking for Buttercup tests..."
+
+ grep "(require 'buttercup)" "${project_test_files[@]}" &>/dev/null
+}
+
+function ert-tests-p {
+ # Return 0 if ERT tests are found.
+ test-files-p || die "No tests found."
+ debug "Checking for ERT tests..."
+
+ # We check for this rather than "(require 'ert)", because ERT may
+ # already be loaded in Emacs and might not be loaded with
+ # "require" in a test file.
+ grep "(ert-deftest" "${project_test_files[@]}" &>/dev/null
+}
+
+function dependencies {
+ # Echo list of package dependencies.
+
+ # Search package headers.
+ egrep '^;; Package-Requires: ' $(project-source-files)
$(project-test-files) \
+ | egrep -o '\([^([:space:]][^)]*\)' \
+ | egrep -o '^[^[:space:])]+' \
+ | sed -r 's/\(//g' \
+ | egrep -v '^emacs$' # Ignore Emacs version requirement.
+
+ # Search Cask file.
+ if [[ -r Cask ]]
+ then
+ egrep '\(depends-on "[^"]+"' Cask \
+ | sed -r -e 's/\(depends-on "([^"]+)".*/\1/g'
+ fi
+}
+
# ** Utility
function cleanup {
@@ -308,40 +375,6 @@ function ts {
date "+%Y-%m-%d %H:%M:%S"
}
-function usage {
- cat <<EOF
-$0 [OPTIONS] RULES...
-
-Rules:
- all Run all lints and tests.
- compile Byte-compile source files.
-
- lint Run all lints.
- lint-checkdoc Run checkdoc.
- lint-compile Byte-compile source files with warnings as errors.
- lint-package Run package-lint.
-
- test, tests Run all tests.
- test-buttercup Run Buttercup tests.
- test-ert Run ERT tests.
-
-Options:
- -d, --debug Print debug info.
- -h, --help I need somebody!
- -v, --verbose Increase verbosity, up to -vv.
-
- --debug-load-path Print load-path.
-
- -f FILE, --file FILE Check FILE in addition to discovered files.
-
- --no-color Disable color output.
- -C, --no-compile Don't compile files automatically.
-
-Source files are automatically discovered from git, or may be
-specified with options.
-EOF
-}
-
# * Rules
# These functions are intended to be called as rules, like a Makefile.
@@ -408,12 +441,14 @@ function lint-package {
}
function tests {
- # Run tests.
+ verbose 1 "Running all tests..."
+
test-ert
test-buttercup
}
function test-buttercup {
+ buttercup-tests-p || return 0
compile || die
verbose 1 "Running Buttercup tests..."
@@ -430,6 +465,7 @@ function test-buttercup {
}
function test-ert {
+ ert-tests-p || return 0
compile || die
verbose 1 "Running ERT tests..."
@@ -444,21 +480,37 @@ function test-ert {
# * Defaults
-# TODO: Disable color if not outputting to a terminal.
-color=true
+test_files_regexp='^(tests?|t)/'
+emacs_command="emacs"
errors=0
verbose=0
-
compile=true
-load_path="."
-# TODO: Option to not byte-compile test files.
-project_byte_compile_files=($(project-elisp-files))
-project_source_files=($(project-source-files))
-project_test_files=($(project-test-files))
+# MAYBE: Disable color if not outputting to a terminal. (OTOH, the
+# colorized output is helpful in CI logs, and I don't know if,
+# e.g. GitHub Actions logging pretends to be a terminal.)
+color=true
-package_initialize_file="$(elisp-package-initialize-file)"
-temp_paths+=("$package_initialize_file")
+# TODO: Using the current directory (i.e. a package's repo root directory) in
+# load-path can cause weird errors in case of--you guessed it--stale .ELC
files,
+# the zombie problem that just won't die. It's incredible how many different
ways
+# this problem presents itself. In this latest example, an old .ELC file, for
a
+# .EL file that had since been renamed, was present on my local system, which
meant
+# that an example .EL file that hadn't been updated was able to "require" that
.ELC
+# file's feature without error. But on another system (in this case, trying to
+# setup CI using GitHub Actions), the old .ELC was not present, so the example
.EL
+# file was not able to load the feature, which caused a byte-compilation error.
+
+# In this case, I will prevent such example files from being compiled. But in
+# general, this can cause weird problems that are tedious to debug. I guess
+# the best way to fix it would be to actually install the repo's code as a
+# package into the sandbox, but doing that would require additional tooling,
+# pulling in something like Quelpa or package-build--and if the default recipe
+# weren't being used, the actual recipe would have to be fetched off MELPA or
+# something, which seems like getting too smart for our own good.
+
+# TODO: Emit a warning if .ELC files that don't match any .EL files are
detected.
+load_path="."
# ** Colors
@@ -472,14 +524,32 @@ COLOR_purple='\e[0;35m'
COLOR_cyan='\e[0;36m'
COLOR_white='\e[0;37m'
+# * Project files
+
+# MAYBE: Option to not byte-compile test files. (OTOH, byte-compiling reveals
many
+# errors that would otherwise go unnoticed, so it's worth it to fix the
warnings.)
+project_source_files=($(project-source-files))
+project_test_files=($(project-test-files))
+project_byte_compile_files=("${project_source_files[@]}"
"${project_test_files[@]}")
+
+package_initialize_file="$(elisp-package-initialize-file)"
+temp_paths+=("$package_initialize_file")
+
# * Args
-args=$(getopt -n "$0" -o dhvf:C -l
debug,debug-load-path,help,verbose,file:,no-color,no-compile -- "$@") || {
usage; exit 1; }
+args=$(getopt -n "$0" \
+ -o dhi:sS:vf:C \
+ -l
auto-install,debug,debug-load-path,help,install:,verbose,file:,no-color,no-compile,sandbox,sandbox-dir:
\
+ -- "$@") \
+ || { usage; exit 1; }
eval set -- "$args"
while true
do
case "$1" in
+ --auto-install)
+ auto_install=true
+ ;;
-d|--debug)
debug=true
verbose=2
@@ -491,6 +561,18 @@ do
usage
exit
;;
+ -i|--install)
+ shift
+ sandbox_install_packages_args+=(--install "$1")
+ ;;
+ -s|--sandbox)
+ sandbox=true
+ ;;
+ -S|--sandbox-dir)
+ shift
+ sandbox=true
+ sandbox_dir="$1"
+ ;;
-v|--verbose)
((verbose++))
;;
@@ -529,6 +611,52 @@ then
exit 1
fi
+if [[ $sandbox ]]
+then
+ # Setup sandbox.
+ type emacs-sandbox.sh &>/dev/null || die "emacs-sandbox.sh not found."
+
+ if ! [[ $sandbox_dir ]]
+ then
+ # No sandbox dir specified: make temp dir and remove it on exit.
+ sandbox_dir=$(mktemp -d) || die "Unable to make temp dir."
+ temp_paths+=("$sandbox_dir")
+ fi
+
+ sandbox_basic_args=(
+ -d "$sandbox_dir"
+ )
+ [[ $debug ]] && sandbox_basic_args+=(--debug)
+
+ if [[ $auto_install ]]
+ then
+ # Add dependencies to package install list.
+ deps=($(dependencies))
+ debug "Installing dependencies: ${deps[@]}"
+
+ for package in "${deps[@]}"
+ do
+ sandbox_install_packages_args+=(--install $package)
+ done
+ fi
+
+ if [[ ${sandbox_install_packages_args[@]} ]]
+ then
+ # Initialize the sandbox (installs packages once rather than for every
rule).
+ emacs_command="emacs-sandbox.sh ${sandbox_basic_args[@]}
${sandbox_install_packages_args[@]} -- "
+ debug "Initializing sandbox..."
+
+ run_emacs || die "Unable to initialize sandbox."
+ fi
+
+ # After the sandbox is initialized and packages are installed, set the
command
+ # to prevent the package lists from being refreshed on each invocation.
+ emacs_command="emacs-sandbox.sh ${sandbox_basic_args[@]}
--no-refresh-packages -- "
+
+ debug "Sandbox initialized."
+fi
+
+# Run rules.
for rule in "${rest[@]}"
do
if type "$rule" 2>/dev/null | grep "$rule is a function" &>/dev/null
- [elpa] externals/plz 2b51ecd6be 27/81: Meta: Add test.yml for GitHub Actions, (continued)
- [elpa] externals/plz 2b51ecd6be 27/81: Meta: Add test.yml for GitHub Actions, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 4f74be6565 30/81: Notes: Add idea, ELPA Syncer, 2022/05/11
- [elpa] externals/plz fbdcd69950 09/81: Changes, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 4588884c11 10/81: Changes, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 2c19b7f11d 11/81: Changes, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 6a21c7e809 12/81: Significant changes, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 5b00a61ce3 15/81: Rename functions, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 370d0bbc1a 21/81: Tidy, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 971077e1d3 23/81: Tests, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 30e48b1e6a 22/81: Tidy, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 05f93b0b6b 25/81: Meta: Update Makefile, makem.sh,
ELPA Syncer <=
- [elpa] externals/plz 19a0110109 33/81: Notes: Add ToC, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 9a1b119eff 38/81: Meta: Ignore sandbox/, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 0301272d8d 40/81: Add: plz-put, ELPA Syncer, 2022/05/11
- [elpa] externals/plz a5f22b23e1 42/81: Add: (plz), ELPA Syncer, 2022/05/11
- [elpa] externals/plz 430ceffd1d 43/81: Change: Handle killed processes, ELPA Syncer, 2022/05/11
- [elpa] externals/plz f40d3ecbdd 47/81: Add/Change: :noquery argument for make-process, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 1884d038ae 46/81: Notes: Add note about Lars Ingebrigtsen's with-url macro, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 7478d43668 51/81: Revert "Add/Change: Handle LF-only HTTP responses", ELPA Syncer, 2022/05/11
- [elpa] externals/plz 8d2654bba7 49/81: Add/Change: Handle LF-only HTTP responses, ELPA Syncer, 2022/05/11
- [elpa] externals/plz 220f882ee4 53/81: Tests: (plz-post-jpeg-string) Add, ELPA Syncer, 2022/05/11