Meta: Update Makefile, makem.sh
This commit is contained in:
parent
6004ab98da
commit
b1d9fcf274
2 changed files with 116 additions and 88 deletions
19
Makefile
19
Makefile
|
|
@ -2,14 +2,27 @@
|
||||||
|
|
||||||
# For consistency, we use only var=val options, not hyphen-prefixed options.
|
# For consistency, we use only var=val options, not hyphen-prefixed options.
|
||||||
|
|
||||||
ifdef autoinstall
|
# NOTE: I don't like duplicating the arguments here and in makem.sh,
|
||||||
AUTOINSTALL = "--auto-install"
|
# 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
|
endif
|
||||||
|
|
||||||
ifdef sandbox
|
ifdef sandbox
|
||||||
SANDBOX = "--sandbox"
|
SANDBOX = "--sandbox"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef sandbox-dir
|
||||||
|
SANDBOX_DIR = "--sandbox-dir" "$(sandbox-dir)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef debug
|
||||||
|
DEBUG = "--debug"
|
||||||
|
endif
|
||||||
|
|
||||||
# ** Verbosity
|
# ** Verbosity
|
||||||
|
|
||||||
# Since the "-v" in "make -v" gets intercepted by Make itself, we have
|
# Since the "-v" in "make -v" gets intercepted by Make itself, we have
|
||||||
|
|
@ -29,4 +42,4 @@ endif
|
||||||
# directory by that name exists, which can confuse Make.
|
# directory by that name exists, which can confuse Make.
|
||||||
|
|
||||||
%:
|
%:
|
||||||
@./makem.sh $(VERBOSE) $(SANDBOX) $(AUTOINSTALL) $(@)
|
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(SANDBOX_DIR) $(AUTO_INSTALL) $(@)
|
||||||
|
|
|
||||||
185
makem.sh
185
makem.sh
|
|
@ -44,63 +44,9 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# * Safety
|
# * Functions
|
||||||
|
|
||||||
# NOTE: These are disabled by default in this template but should be
|
# ** Elisp
|
||||||
# enabled when feasible. Documentation is from the Bash man page.
|
|
||||||
|
|
||||||
# ** errexit
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# set -o errexit
|
|
||||||
|
|
||||||
# ** nounset
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# NOTE: When this is not enabled, individual variables can be required
|
|
||||||
# to be set by using "${var:?}" parameter expansion syntax.
|
|
||||||
|
|
||||||
# set -o nounset
|
|
||||||
|
|
||||||
# ** pipefail
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# set -o pipefail
|
|
||||||
|
|
||||||
# * Elisp
|
|
||||||
|
|
||||||
# These functions return a path to an elisp file which can be loaded
|
# These functions return a path to an elisp file which can be loaded
|
||||||
# by Emacs on the command line with -l or --load.
|
# by Emacs on the command line with -l or --load.
|
||||||
|
|
@ -164,8 +110,6 @@ EOF
|
||||||
echo $file
|
echo $file
|
||||||
}
|
}
|
||||||
|
|
||||||
# * Functions
|
|
||||||
|
|
||||||
# ** Emacs
|
# ** Emacs
|
||||||
|
|
||||||
function run_emacs {
|
function run_emacs {
|
||||||
|
|
@ -219,17 +163,27 @@ function project-elisp-files {
|
||||||
|
|
||||||
function project-source-files {
|
function project-source-files {
|
||||||
# Echo list of Elisp files that are not tests.
|
# 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 {
|
function project-test-files {
|
||||||
# Echo list of Elisp test files.
|
# Echo list of Elisp test files.
|
||||||
project-elisp-files | egrep '^tests?/test-?'
|
project-elisp-files | egrep "$test_files_regexp"
|
||||||
}
|
}
|
||||||
|
|
||||||
function exclude-files {
|
function exclude-files {
|
||||||
# Filter out paths (STDIN) which should be excluded by default.
|
# 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 {
|
function load-files-args {
|
||||||
|
|
@ -248,30 +202,46 @@ function files_args {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test-files-p {
|
||||||
|
# Return 0 if $project_test_files is non-empty.
|
||||||
|
[[ "${project_test_files[@]}" ]]
|
||||||
|
}
|
||||||
|
|
||||||
function buttercup-tests-p {
|
function buttercup-tests-p {
|
||||||
# Return 0 if Buttercup tests are found.
|
# Return 0 if Buttercup tests are found.
|
||||||
|
test-files-p || die "No tests found."
|
||||||
debug "Checking for Buttercup tests..."
|
debug "Checking for Buttercup tests..."
|
||||||
|
|
||||||
grep "(require 'buttercup)" $(project-test-files) &>/dev/null
|
grep "(require 'buttercup)" "${project_test_files[@]}" &>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function ert-tests-p {
|
function ert-tests-p {
|
||||||
# Return 0 if ERT tests are found.
|
# Return 0 if ERT tests are found.
|
||||||
|
test-files-p || die "No tests found."
|
||||||
debug "Checking for ERT tests..."
|
debug "Checking for ERT tests..."
|
||||||
|
|
||||||
# We check for this rather than "(require 'ert)", because ERT may
|
# We check for this rather than "(require 'ert)", because ERT may
|
||||||
# already be loaded in Emacs and might not be loaded with
|
# already be loaded in Emacs and might not be loaded with
|
||||||
# "require" in a test file.
|
# "require" in a test file.
|
||||||
grep "(ert-deftest" $(project-test-files) &>/dev/null
|
grep "(ert-deftest" "${project_test_files[@]}" &>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function dependencies {
|
function dependencies {
|
||||||
# Echo list of package dependencies.
|
# Echo list of package dependencies.
|
||||||
|
|
||||||
|
# Search package headers.
|
||||||
egrep '^;; Package-Requires: ' $(project-source-files) $(project-test-files) \
|
egrep '^;; Package-Requires: ' $(project-source-files) $(project-test-files) \
|
||||||
| egrep -o '\([^([:space:]][^)]*\)' \
|
| egrep -o '\([^([:space:]][^)]*\)' \
|
||||||
| egrep -o '^[^[:space:])]+' \
|
| egrep -o '^[^[:space:])]+' \
|
||||||
| sed -r 's/\(//g' \
|
| sed -r 's/\(//g' \
|
||||||
| egrep -v '^emacs$' # Ignore Emacs version requirement.
|
| 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
|
# ** Utility
|
||||||
|
|
@ -390,7 +360,10 @@ Sandbox options:
|
||||||
These require emacs-sandbox.sh to be on your PATH. Find it at
|
These require emacs-sandbox.sh to be on your PATH. Find it at
|
||||||
<https://github.com/alphapapa/emacs-sandbox.sh>.
|
<https://github.com/alphapapa/emacs-sandbox.sh>.
|
||||||
|
|
||||||
--sandbox Run Emacs with emacs-sandbox.sh.
|
-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.
|
--auto-install Automatically install package dependencies.
|
||||||
-i, --install PACKAGE Install PACKAGE before running rules.
|
-i, --install PACKAGE Install PACKAGE before running rules.
|
||||||
|
|
||||||
|
|
@ -398,7 +371,7 @@ Source files are automatically discovered from git, or may be
|
||||||
specified with options.
|
specified with options.
|
||||||
|
|
||||||
Package dependencies are discovered from "Package-Requires" headers in
|
Package dependencies are discovered from "Package-Requires" headers in
|
||||||
source files.
|
source files and from a Cask file.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,24 +480,38 @@ function test-ert {
|
||||||
|
|
||||||
# * Defaults
|
# * Defaults
|
||||||
|
|
||||||
|
test_files_regexp='^(tests?|t)/'
|
||||||
emacs_command="emacs"
|
emacs_command="emacs"
|
||||||
|
|
||||||
# TODO: Disable color if not outputting to a terminal.
|
|
||||||
color=true
|
|
||||||
errors=0
|
errors=0
|
||||||
verbose=0
|
verbose=0
|
||||||
|
|
||||||
compile=true
|
compile=true
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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="."
|
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))
|
|
||||||
|
|
||||||
package_initialize_file="$(elisp-package-initialize-file)"
|
|
||||||
temp_paths+=("$package_initialize_file")
|
|
||||||
|
|
||||||
# ** Colors
|
# ** Colors
|
||||||
|
|
||||||
COLOR_off='\e[0m'
|
COLOR_off='\e[0m'
|
||||||
|
|
@ -537,9 +524,24 @@ COLOR_purple='\e[0;35m'
|
||||||
COLOR_cyan='\e[0;36m'
|
COLOR_cyan='\e[0;36m'
|
||||||
COLOR_white='\e[0;37m'
|
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
|
||||||
|
|
||||||
args=$(getopt -n "$0" -o dhi:svf:C -l auto-install,debug,debug-load-path,help,install:,verbose,file:,no-color,no-compile,sandbox -- "$@") || { 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"
|
eval set -- "$args"
|
||||||
|
|
||||||
while true
|
while true
|
||||||
|
|
@ -566,6 +568,11 @@ do
|
||||||
-s|--sandbox)
|
-s|--sandbox)
|
||||||
sandbox=true
|
sandbox=true
|
||||||
;;
|
;;
|
||||||
|
-S|--sandbox-dir)
|
||||||
|
shift
|
||||||
|
sandbox=true
|
||||||
|
sandbox_dir="$1"
|
||||||
|
;;
|
||||||
-v|--verbose)
|
-v|--verbose)
|
||||||
((verbose++))
|
((verbose++))
|
||||||
;;
|
;;
|
||||||
|
|
@ -609,16 +616,21 @@ then
|
||||||
# Setup sandbox.
|
# Setup sandbox.
|
||||||
type emacs-sandbox.sh &>/dev/null || die "emacs-sandbox.sh not found."
|
type emacs-sandbox.sh &>/dev/null || die "emacs-sandbox.sh not found."
|
||||||
|
|
||||||
config_dir=$(mktemp -d) || die "Unable to make temp dir."
|
if ! [[ $sandbox_dir ]]
|
||||||
temp_paths+=("$config_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=(
|
sandbox_basic_args=(
|
||||||
-d "$config_dir"
|
-d "$sandbox_dir"
|
||||||
)
|
)
|
||||||
[[ $debug ]] && sandbox_basic_args+=(--debug)
|
[[ $debug ]] && sandbox_basic_args+=(--debug)
|
||||||
|
|
||||||
if [[ $auto_install ]]
|
if [[ $auto_install ]]
|
||||||
then
|
then
|
||||||
|
# Add dependencies to package install list.
|
||||||
deps=($(dependencies))
|
deps=($(dependencies))
|
||||||
debug "Installing dependencies: ${deps[@]}"
|
debug "Installing dependencies: ${deps[@]}"
|
||||||
|
|
||||||
|
|
@ -628,11 +640,14 @@ then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Initialize the sandbox (installs packages once rather than for every rule).
|
if [[ ${sandbox_install_packages_args[@]} ]]
|
||||||
emacs_command="emacs-sandbox.sh ${sandbox_basic_args[@]} ${sandbox_install_packages_args[@]} -- "
|
then
|
||||||
debug "Initializing sandbox..."
|
# 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."
|
run_emacs || die "Unable to initialize sandbox."
|
||||||
|
fi
|
||||||
|
|
||||||
# After the sandbox is initialized and packages are installed, set the command
|
# After the sandbox is initialized and packages are installed, set the command
|
||||||
# to prevent the package lists from being refreshed on each invocation.
|
# to prevent the package lists from being refreshed on each invocation.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue