emacs-elpa-diffs
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]