Meta: Update makem.sh, Makefile, and pre-push
Use local .sandbox sandbox. (Assumes it is initialized.)
This commit is contained in:
parent
035c20fc28
commit
e23a026fe5
3 changed files with 320 additions and 78 deletions
14
Makefile
14
Makefile
|
|
@ -19,11 +19,11 @@ ifdef install-linters
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef sandbox
|
ifdef sandbox
|
||||||
SANDBOX = "--sandbox"
|
ifeq ($(sandbox), t)
|
||||||
|
SANDBOX = --sandbox
|
||||||
|
else
|
||||||
|
SANDBOX = --sandbox $(sandbox)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef sandbox-dir
|
|
||||||
SANDBOX_DIR = "--sandbox-dir" "$(sandbox-dir)"
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef debug
|
ifdef debug
|
||||||
|
|
@ -49,4 +49,8 @@ endif
|
||||||
# directory by that name exists, which can confuse Make.
|
# directory by that name exists, which can confuse Make.
|
||||||
|
|
||||||
%:
|
%:
|
||||||
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(SANDBOX_DIR) $(INSTALL_DEPS) $(INSTALL_LINTERS) $(@)
|
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS) $(@)
|
||||||
|
|
||||||
|
.DEFAULT: init
|
||||||
|
init:
|
||||||
|
@./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS)
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@ read local_ref local_sha remote_ref remote_sha
|
||||||
# cause remote code to be downloaded and executed (i.e. what would
|
# cause remote code to be downloaded and executed (i.e. what would
|
||||||
# happen by installing packages). It can be done manually when needed.
|
# happen by installing packages). It can be done manually when needed.
|
||||||
|
|
||||||
make test
|
make sandbox=.sandbox test
|
||||||
|
|
|
||||||
370
makem.sh
370
makem.sh
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# * makem.sh --- Script to aid building and testing Emacs Lisp packages
|
# * makem.sh --- Script to aid building and testing Emacs Lisp packages
|
||||||
|
|
||||||
|
|
@ -59,17 +59,20 @@ Rules:
|
||||||
lint Run all linters, ignoring unavailable ones.
|
lint Run all linters, ignoring unavailable ones.
|
||||||
lint-checkdoc Run checkdoc.
|
lint-checkdoc Run checkdoc.
|
||||||
lint-compile Byte-compile source files with warnings as errors.
|
lint-compile Byte-compile source files with warnings as errors.
|
||||||
lint-indent Run indent-lint.
|
lint-declare Run check-declare.
|
||||||
|
lint-indent Lint indentation.
|
||||||
lint-package Run package-lint.
|
lint-package Run package-lint.
|
||||||
|
lint-regexps Run relint.
|
||||||
|
|
||||||
test, tests Run all tests, ignoring missing test types.
|
test, tests Run all tests, ignoring missing test types.
|
||||||
test-buttercup Run Buttercup tests.
|
test-buttercup Run Buttercup tests.
|
||||||
test-ert Run ERT tests.
|
test-ert Run ERT tests.
|
||||||
|
test-ert-interactive Run ERT tests interactively.
|
||||||
|
|
||||||
batch Run Emacs in batch mode, loading project source and test files
|
batch Run Emacs in batch mode, loading project source and test files
|
||||||
automatically, with remaining args (after "--") passed to Emacs.
|
automatically, with remaining args (after "--") passed to Emacs.
|
||||||
interactive Run Emacs interactively, loading project source and test files
|
interactive Run Emacs interactively, loading project source and test files
|
||||||
automatically.
|
automatically, with remaining args (after "--") passed to Emacs.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d, --debug Print debug info.
|
-d, --debug Print debug info.
|
||||||
|
|
@ -78,23 +81,33 @@ Options:
|
||||||
|
|
||||||
--debug-load-path Print load-path from inside Emacs.
|
--debug-load-path Print load-path from inside Emacs.
|
||||||
|
|
||||||
-f FILE, --file FILE Check FILE in addition to discovered files.
|
-E, --emacs PATH Run Emacs at PATH.
|
||||||
|
|
||||||
|
-e, --exclude FILE Exclude FILE from linting and testing.
|
||||||
|
-f, --file FILE Check FILE in addition to discovered files.
|
||||||
|
|
||||||
--no-color Disable color output.
|
--no-color Disable color output.
|
||||||
-C, --no-compile Don't compile files automatically.
|
-C, --no-compile Don't compile files automatically.
|
||||||
|
|
||||||
Sandbox options:
|
Sandbox options:
|
||||||
-s, --sandbox Run Emacs with an empty config in a temporary
|
-s, --sandbox [DIR] Run Emacs with an empty config in a sandbox DIR.
|
||||||
directory (removing directory on exit).
|
If DIR does not exist, make it. If DIR is not
|
||||||
-S, --sandbox-dir DIR Use DIR for the sandbox directory (leaving it
|
specified, use a temporary sandbox directory and
|
||||||
on exit). Implies -s.
|
delete it afterward, implying --install-deps and
|
||||||
|
--install-linters.
|
||||||
--install-deps Automatically install package dependencies.
|
--install-deps Automatically install package dependencies.
|
||||||
--install-linters Automatically install linters.
|
--install-linters Automatically install linters.
|
||||||
-i, --install PACKAGE Install PACKAGE before running rules.
|
-i, --install PACKAGE Install PACKAGE before running rules.
|
||||||
|
|
||||||
|
An Emacs version-specific subdirectory is automatically made inside
|
||||||
|
the sandbox, allowing testing with multiple Emacs versions. When
|
||||||
|
specifying a sandbox directory, use options --install-deps and
|
||||||
|
--install-linters on first-run and omit them afterward to save time.
|
||||||
|
|
||||||
Source files are automatically discovered from git, or may be
|
Source files are automatically discovered from git, or may be
|
||||||
specified with options. Package dependencies are discovered from
|
specified with options. Package dependencies are discovered from
|
||||||
"Package-Requires" headers in source files and from a Cask file.
|
"Package-Requires" headers in source files, from -pkg.el files, and
|
||||||
|
from a Cask file.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,11 +155,69 @@ function elisp-checkdoc-file {
|
||||||
(when makem-checkdoc-errors-p
|
(when makem-checkdoc-errors-p
|
||||||
(kill-emacs 1))))
|
(kill-emacs 1))))
|
||||||
|
|
||||||
|
(setq checkdoc-spellcheck-documentation-flag t)
|
||||||
(makem-checkdoc-files-and-exit)
|
(makem-checkdoc-files-and-exit)
|
||||||
EOF
|
EOF
|
||||||
echo $file
|
echo $file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function elisp-check-declare-file {
|
||||||
|
# Since check-declare doesn't have a batch function that exits
|
||||||
|
# non-zero when errors are found, we make one.
|
||||||
|
local file=$(mktemp)
|
||||||
|
|
||||||
|
cat >$file <<EOF
|
||||||
|
(require 'check-declare)
|
||||||
|
|
||||||
|
(defun makem-check-declare-files-and-exit ()
|
||||||
|
"Run check-declare-files on files remaining on command line, exiting non-zero if there are warnings."
|
||||||
|
(let* ((files (mapcar #'expand-file-name command-line-args-left))
|
||||||
|
(errors (apply #'check-declare-files files)))
|
||||||
|
(when errors
|
||||||
|
(with-current-buffer check-declare-warning-buffer
|
||||||
|
(print (buffer-string)))
|
||||||
|
(kill-emacs 1))))
|
||||||
|
EOF
|
||||||
|
echo $file
|
||||||
|
}
|
||||||
|
|
||||||
|
function elisp-lint-indent-file {
|
||||||
|
# This function prints warnings for indentation errors and exits
|
||||||
|
# non-zero when errors are found.
|
||||||
|
local file=$(mktemp)
|
||||||
|
|
||||||
|
cat >"$file" <<EOF
|
||||||
|
(require 'cl-lib)
|
||||||
|
|
||||||
|
(defun makem-lint-indent-batch-and-exit ()
|
||||||
|
"Print warnings for files which are not indented properly, then exit.
|
||||||
|
Exits non-zero if mis-indented lines are found. Checks files in
|
||||||
|
'command-line-args-left'."
|
||||||
|
(let ((errors-p))
|
||||||
|
(cl-labels ((lint-file (file)
|
||||||
|
(find-file file)
|
||||||
|
(let ((tick (buffer-modified-tick)))
|
||||||
|
(let ((inhibit-message t))
|
||||||
|
(indent-region (point-min) (point-max)))
|
||||||
|
(when (/= tick (buffer-modified-tick))
|
||||||
|
;; Indentation changed: warn for each line.
|
||||||
|
(dolist (line (undo-lines buffer-undo-list))
|
||||||
|
(message "%s:%s: Indentation mismatch" (buffer-name) line))
|
||||||
|
(setf errors-p t))))
|
||||||
|
(undo-lines (undo-list)
|
||||||
|
;; Return list of lines changed in UNDO-LIST.
|
||||||
|
(nreverse (cl-loop for elt in undo-list
|
||||||
|
when (and (consp elt)
|
||||||
|
(numberp (car elt)))
|
||||||
|
collect (line-number-at-pos (car elt))))))
|
||||||
|
(mapc #'lint-file (mapcar #'expand-file-name command-line-args-left))
|
||||||
|
(when errors-p
|
||||||
|
(kill-emacs 1)))))
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "$file"
|
||||||
|
}
|
||||||
|
|
||||||
function elisp-package-initialize-file {
|
function elisp-package-initialize-file {
|
||||||
local file=$(mktemp)
|
local file=$(mktemp)
|
||||||
|
|
||||||
|
|
@ -170,10 +241,11 @@ function run_emacs {
|
||||||
local emacs_command=(
|
local emacs_command=(
|
||||||
"${emacs_command[@]}"
|
"${emacs_command[@]}"
|
||||||
-Q
|
-Q
|
||||||
|
"${args_debug[@]}"
|
||||||
"${args_sandbox[@]}"
|
"${args_sandbox[@]}"
|
||||||
-l $package_initialize_file
|
-l $package_initialize_file
|
||||||
$arg_batch
|
$arg_batch
|
||||||
-L "$load_path"
|
"${args_load_paths[@]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Show debug message with load-path from inside Emacs.
|
# Show debug message with load-path from inside Emacs.
|
||||||
|
|
@ -205,7 +277,7 @@ function run_emacs {
|
||||||
# ** Compilation
|
# ** Compilation
|
||||||
|
|
||||||
function batch-byte-compile {
|
function batch-byte-compile {
|
||||||
debug "batch-byte-compile: ERROR-ON-WARN:$compile_error_on_warn FILES:$@"
|
debug "batch-byte-compile: ERROR-ON-WARN:$compile_error_on_warn"
|
||||||
|
|
||||||
[[ $compile_error_on_warn ]] && local error_on_warn=(--eval "(setq byte-compile-error-on-warn t)")
|
[[ $compile_error_on_warn ]] && local error_on_warn=(--eval "(setq byte-compile-error-on-warn t)")
|
||||||
|
|
||||||
|
|
@ -217,14 +289,25 @@ function batch-byte-compile {
|
||||||
|
|
||||||
# ** Files
|
# ** Files
|
||||||
|
|
||||||
function files-project-elisp {
|
function dirs-project {
|
||||||
# Echo list of Elisp files in project.
|
# Echo list of directories to be used in load path.
|
||||||
git ls-files 2>/dev/null | egrep "\.el$" | filter-files-exclude
|
files-project-feature | dirnames
|
||||||
|
files-project-test | dirnames
|
||||||
}
|
}
|
||||||
|
|
||||||
function files-project-source {
|
function files-project-elisp {
|
||||||
# Echo list of Elisp files that are not tests.
|
# Echo list of Elisp files in project.
|
||||||
files-project-elisp | egrep -v "$test_files_regexp" | filter-files-feature
|
git ls-files 2>/dev/null \
|
||||||
|
| egrep "\.el$" \
|
||||||
|
| filter-files-exclude-default \
|
||||||
|
| filter-files-exclude-args
|
||||||
|
}
|
||||||
|
|
||||||
|
function files-project-feature {
|
||||||
|
# Echo list of Elisp files that are not tests and provide a feature.
|
||||||
|
files-project-elisp \
|
||||||
|
| egrep -v "$test_files_regexp" \
|
||||||
|
| filter-files-feature
|
||||||
}
|
}
|
||||||
|
|
||||||
function files-project-test {
|
function files-project-test {
|
||||||
|
|
@ -232,16 +315,42 @@ function files-project-test {
|
||||||
files-project-elisp | egrep "$test_files_regexp"
|
files-project-elisp | egrep "$test_files_regexp"
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter-files-exclude {
|
function dirnames {
|
||||||
|
# Echo directory names for files on STDIN.
|
||||||
|
while read file
|
||||||
|
do
|
||||||
|
dirname "$file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter-files-exclude-default {
|
||||||
# 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|.dir-locals)"
|
egrep -v "(/\.cask/|-autoloads.el|.dir-locals)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filter-files-exclude-args {
|
||||||
|
# Filter out paths (STDIN) which are excluded with --exclude.
|
||||||
|
if [[ ${files_exclude[@]} ]]
|
||||||
|
then
|
||||||
|
(
|
||||||
|
# We use a subshell to set IFS temporarily so we can send
|
||||||
|
# the list of files to grep -F. This is ugly but more
|
||||||
|
# correct than replacing spaces with line breaks. Note
|
||||||
|
# that, for some reason, using IFS="\n" or IFS='\n' doesn't
|
||||||
|
# work, and a literal line break seems to be required.
|
||||||
|
IFS="
|
||||||
|
"
|
||||||
|
grep -Fv "${files_exclude[*]}"
|
||||||
|
)
|
||||||
|
else
|
||||||
|
cat
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function filter-files-feature {
|
function filter-files-feature {
|
||||||
# Read paths on STDIN and echo ones that (provide 'a-feature).
|
# Read paths on STDIN and echo ones that (provide 'a-feature).
|
||||||
while read path
|
while read path
|
||||||
do
|
do
|
||||||
debug "PATH: $path"
|
|
||||||
egrep "^\\(provide '" "$path" &>/dev/null \
|
egrep "^\\(provide '" "$path" &>/dev/null \
|
||||||
&& echo "$path"
|
&& echo "$path"
|
||||||
done
|
done
|
||||||
|
|
@ -255,6 +364,14 @@ function args-load-files {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function args-load-path {
|
||||||
|
# Echo load-path arguments.
|
||||||
|
for path in $(dirs-project | sort -u)
|
||||||
|
do
|
||||||
|
printf -- '-L %q ' "$path"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
function test-files-p {
|
function test-files-p {
|
||||||
# Return 0 if $files_project_test is non-empty.
|
# Return 0 if $files_project_test is non-empty.
|
||||||
[[ "${files_project_test[@]}" ]]
|
[[ "${files_project_test[@]}" ]]
|
||||||
|
|
@ -283,7 +400,7 @@ function dependencies {
|
||||||
# Echo list of package dependencies.
|
# Echo list of package dependencies.
|
||||||
|
|
||||||
# Search package headers.
|
# Search package headers.
|
||||||
egrep '^;; Package-Requires: ' $(files-project-source) $(files-project-test) \
|
egrep '^;; Package-Requires: ' $(files-project-feature) $(files-project-test) \
|
||||||
| egrep -o '\([^([:space:]][^)]*\)' \
|
| egrep -o '\([^([:space:]][^)]*\)' \
|
||||||
| egrep -o '^[^[:space:])]+' \
|
| egrep -o '^[^[:space:])]+' \
|
||||||
| sed -r 's/\(//g' \
|
| sed -r 's/\(//g' \
|
||||||
|
|
@ -295,6 +412,12 @@ function dependencies {
|
||||||
egrep '\(depends-on "[^"]+"' Cask \
|
egrep '\(depends-on "[^"]+"' Cask \
|
||||||
| sed -r -e 's/\(depends-on "([^"]+)".*/\1/g'
|
| sed -r -e 's/\(depends-on "([^"]+)".*/\1/g'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Search -pkg.el file.
|
||||||
|
if [[ $(git ls-files ./*-pkg.el 2>/dev/null) ]]
|
||||||
|
then
|
||||||
|
sed -nr 's/.*\(([-[:alnum:]]+)[[:blank:]]+"[.[:digit:]]+"\).*/\1/p' $(git ls-files ./*-pkg.el 2>/dev/null)
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ** Sandbox
|
# ** Sandbox
|
||||||
|
|
@ -308,7 +431,18 @@ function sandbox {
|
||||||
if [[ $sandbox_dir ]]
|
if [[ $sandbox_dir ]]
|
||||||
then
|
then
|
||||||
# Directory given as argument: ensure it exists.
|
# Directory given as argument: ensure it exists.
|
||||||
[[ -d $sandbox_dir ]] || die "Directory doesn't exist: $sandbox_dir"
|
if ! [[ -d $sandbox_dir ]]
|
||||||
|
then
|
||||||
|
debug "Making sandbox directory: $sandbox_dir"
|
||||||
|
mkdir -p "$sandbox_dir" || die "Unable to make sandbox dir."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add Emacs version-specific subdirectory, creating if necessary.
|
||||||
|
sandbox_dir="$sandbox_dir/$(emacs-version)"
|
||||||
|
if ! [[ -d $sandbox_dir ]]
|
||||||
|
then
|
||||||
|
mkdir "$sandbox_dir" || die "Unable to make sandbox subdir: $sandbox_dir"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# Not given: make temp directory, and delete it on exit.
|
# Not given: make temp directory, and delete it on exit.
|
||||||
local sandbox_dir=$(mktemp -d) || die "Unable to make sandbox dir."
|
local sandbox_dir=$(mktemp -d) || die "Unable to make sandbox dir."
|
||||||
|
|
@ -322,6 +456,7 @@ function sandbox {
|
||||||
|
|
||||||
# Set sandbox args. This is a global variable used by the run_emacs function.
|
# Set sandbox args. This is a global variable used by the run_emacs function.
|
||||||
args_sandbox=(
|
args_sandbox=(
|
||||||
|
--title "makem.sh: $(basename $(pwd)) (sandbox: $sandbox_dir)"
|
||||||
--eval "(setq user-emacs-directory (file-truename \"$sandbox_dir\"))"
|
--eval "(setq user-emacs-directory (file-truename \"$sandbox_dir\"))"
|
||||||
--eval "(setq user-init-file (file-truename \"$init_file\"))"
|
--eval "(setq user-init-file (file-truename \"$init_file\"))"
|
||||||
"${args_load_init_file[@]}"
|
"${args_load_init_file[@]}"
|
||||||
|
|
@ -339,6 +474,15 @@ function sandbox {
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Add package-install arguments for linters.
|
||||||
|
if [[ $install_linters ]]
|
||||||
|
then
|
||||||
|
debug "Installing linters: package-lint relint"
|
||||||
|
|
||||||
|
args_sandbox_package_install+=(--eval "(package-install 'package-lint)"
|
||||||
|
--eval "(package-install 'relint)")
|
||||||
|
fi
|
||||||
|
|
||||||
# *** Install packages into sandbox
|
# *** Install packages into sandbox
|
||||||
|
|
||||||
if [[ ${args_sandbox_package_install[@]} ]]
|
if [[ ${args_sandbox_package_install[@]} ]]
|
||||||
|
|
@ -485,6 +629,21 @@ function ts {
|
||||||
date "+%Y-%m-%d %H:%M:%S"
|
date "+%Y-%m-%d %H:%M:%S"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function emacs-version {
|
||||||
|
# Echo Emacs version number.
|
||||||
|
|
||||||
|
# Don't use run_emacs function, which does more than we need.
|
||||||
|
"${emacs_command[@]}" -Q --batch --eval "(princ emacs-version)" \
|
||||||
|
|| die "Unable to get Emacs version."
|
||||||
|
}
|
||||||
|
|
||||||
|
function rule-p {
|
||||||
|
# Return 0 if $1 is a rule.
|
||||||
|
[[ $1 =~ ^(lint-?|tests?)$ ]] \
|
||||||
|
|| [[ $1 =~ ^(batch|interactive)$ ]] \
|
||||||
|
|| [[ $(type -t "$2" 2>/dev/null) =~ function ]]
|
||||||
|
}
|
||||||
|
|
||||||
# * Rules
|
# * Rules
|
||||||
|
|
||||||
# These functions are intended to be called as rules, like a Makefile.
|
# These functions are intended to be called as rules, like a Makefile.
|
||||||
|
|
@ -516,15 +675,16 @@ function batch {
|
||||||
verbose 1 "Executing Emacs with arguments: ${args_batch[@]}"
|
verbose 1 "Executing Emacs with arguments: ${args_batch[@]}"
|
||||||
|
|
||||||
run_emacs \
|
run_emacs \
|
||||||
$(args-load-files "${files_project_source[@]}" "${files_project_test[@]}") \
|
$(args-load-files "${files_project_feature[@]}" "${files_project_test[@]}") \
|
||||||
"${args_batch[@]}"
|
"${args_batch_interactive[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function interactive {
|
function interactive {
|
||||||
# Run Emacs interactively. Most useful with --sandbox and --install-deps.
|
# Run Emacs interactively. Most useful with --sandbox and --install-deps.
|
||||||
unset arg_batch
|
unset arg_batch
|
||||||
run_emacs \
|
run_emacs \
|
||||||
$(args-load-files "${files_project_source[@]}" "${files_project_test[@]}")
|
$(args-load-files "${files_project_feature[@]}" "${files_project_test[@]}") \
|
||||||
|
"${args_batch_interactive[@]}"
|
||||||
arg_batch="--batch"
|
arg_batch="--batch"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,8 +693,10 @@ function lint {
|
||||||
|
|
||||||
lint-checkdoc
|
lint-checkdoc
|
||||||
lint-compile
|
lint-compile
|
||||||
|
lint-declare
|
||||||
lint-indent
|
lint-indent
|
||||||
lint-package
|
lint-package
|
||||||
|
lint-regexps
|
||||||
}
|
}
|
||||||
|
|
||||||
function lint-checkdoc {
|
function lint-checkdoc {
|
||||||
|
|
@ -545,7 +707,7 @@ function lint-checkdoc {
|
||||||
|
|
||||||
run_emacs \
|
run_emacs \
|
||||||
--load="$checkdoc_file" \
|
--load="$checkdoc_file" \
|
||||||
"${files_project_source[@]}" \
|
"${files_project_feature[@]}" \
|
||||||
&& success "Linting checkdoc finished without errors." \
|
&& success "Linting checkdoc finished without errors." \
|
||||||
|| error "Linting checkdoc failed."
|
|| error "Linting checkdoc failed."
|
||||||
}
|
}
|
||||||
|
|
@ -560,29 +722,32 @@ function lint-compile {
|
||||||
unset compile_error_on_warn
|
unset compile_error_on_warn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lint-declare {
|
||||||
|
verbose 1 "Linting declarations..."
|
||||||
|
|
||||||
|
local check_declare_file="$(elisp-check-declare-file)"
|
||||||
|
paths_temp+=("$check_declare_file")
|
||||||
|
|
||||||
|
run_emacs \
|
||||||
|
--load "$check_declare_file" \
|
||||||
|
-f makem-check-declare-files-and-exit \
|
||||||
|
"${files_project_feature[@]}" \
|
||||||
|
&& success "Linting declarations finished without errors." \
|
||||||
|
|| error "Linting declarations failed."
|
||||||
|
}
|
||||||
|
|
||||||
function lint-indent {
|
function lint-indent {
|
||||||
ensure-package-available indent-lint $1 || return $(echo-unset-p $1)
|
|
||||||
|
|
||||||
verbose 1 "Linting indentation..."
|
verbose 1 "Linting indentation..."
|
||||||
|
|
||||||
# FIXME: indent-lint outputs a summary line like:
|
|
||||||
# Diff finished (has differences). Fri Jan 17 10:30:34 2020
|
|
||||||
# which is unnecessary for our use and clutters output.
|
|
||||||
|
|
||||||
# We load project source files as well, because they may contain
|
# We load project source files as well, because they may contain
|
||||||
# macros with (declare (indent)) rules which must be loaded to set
|
# macros with (declare (indent)) rules which must be loaded to set
|
||||||
# indentation. However...
|
# indentation.
|
||||||
|
|
||||||
# FIXME: This doesn't appear to actually work: macros that set
|
|
||||||
# indentation and are correctly indented in the source files are
|
|
||||||
# reported as having wrong indentation. Not sure if bug in
|
|
||||||
# indent-lint or here.
|
|
||||||
|
|
||||||
run_emacs \
|
run_emacs \
|
||||||
--load indent-lint \
|
--load "$(elisp-lint-indent-file)" \
|
||||||
$(args-load-files "${files_project_source[@]}" "${files_project_test[@]}") \
|
$(args-load-files "${files_project_feature[@]}" "${files_project_test[@]}") \
|
||||||
--funcall indent-lint-batch \
|
--funcall makem-lint-indent-batch-and-exit \
|
||||||
"${files_project_source[@]}" "${files_project_test[@]}" \
|
"${files_project_feature[@]}" "${files_project_test[@]}" \
|
||||||
&& success "Linting indentation finished without errors." \
|
&& success "Linting indentation finished without errors." \
|
||||||
|| error "Linting indentation failed."
|
|| error "Linting indentation failed."
|
||||||
}
|
}
|
||||||
|
|
@ -595,11 +760,24 @@ function lint-package {
|
||||||
run_emacs \
|
run_emacs \
|
||||||
--load package-lint \
|
--load package-lint \
|
||||||
--funcall package-lint-batch-and-exit \
|
--funcall package-lint-batch-and-exit \
|
||||||
"${files_project_source[@]}" \
|
"${files_project_feature[@]}" \
|
||||||
&& success "Linting package finished without errors." \
|
&& success "Linting package finished without errors." \
|
||||||
|| error "Linting package failed."
|
|| error "Linting package failed."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lint-regexps {
|
||||||
|
ensure-package-available relint $1 || return $(echo-unset-p $1)
|
||||||
|
|
||||||
|
verbose 1 "Linting regexps..."
|
||||||
|
|
||||||
|
run_emacs \
|
||||||
|
--load relint \
|
||||||
|
--funcall relint-batch \
|
||||||
|
"${files_project_source[@]}" \
|
||||||
|
&& success "Linting regexps finished without errors." \
|
||||||
|
|| error "Linting regexps failed."
|
||||||
|
}
|
||||||
|
|
||||||
function tests {
|
function tests {
|
||||||
verbose 1 "Running all tests..."
|
verbose 1 "Running all tests..."
|
||||||
|
|
||||||
|
|
@ -607,6 +785,16 @@ function tests {
|
||||||
test-buttercup
|
test-buttercup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test-ert-interactive {
|
||||||
|
verbose 1 "Running ERT tests interactively..."
|
||||||
|
|
||||||
|
unset arg_batch
|
||||||
|
run_emacs \
|
||||||
|
$(args-load-files "${files_project_test[@]}") \
|
||||||
|
--eval "(ert-run-tests-interactively t)"
|
||||||
|
arg_batch="--batch"
|
||||||
|
}
|
||||||
|
|
||||||
function test-buttercup {
|
function test-buttercup {
|
||||||
ensure-tests-available Buttercup $1 || return $(echo-unset-p $1)
|
ensure-tests-available Buttercup $1 || return $(echo-unset-p $1)
|
||||||
compile || die
|
compile || die
|
||||||
|
|
@ -617,9 +805,8 @@ function test-buttercup {
|
||||||
paths_temp+=("$buttercup_file")
|
paths_temp+=("$buttercup_file")
|
||||||
|
|
||||||
run_emacs \
|
run_emacs \
|
||||||
--load buttercup \
|
$(args-load-files "${files_project_test[@]}") \
|
||||||
--load "$buttercup_file" \
|
-f buttercup-run \
|
||||||
-f buttercup-run-discover \
|
|
||||||
&& success "Buttercup tests finished without errors." \
|
&& success "Buttercup tests finished without errors." \
|
||||||
|| error "Buttercup tests failed."
|
|| error "Buttercup tests failed."
|
||||||
}
|
}
|
||||||
|
|
@ -672,7 +859,6 @@ color=true
|
||||||
# something, which seems like getting too smart for our own good.
|
# 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.
|
# TODO: Emit a warning if .ELC files that don't match any .EL files are detected.
|
||||||
load_path="."
|
|
||||||
|
|
||||||
# ** Colors
|
# ** Colors
|
||||||
|
|
||||||
|
|
@ -703,19 +889,11 @@ args_package_init=(
|
||||||
|
|
||||||
elisp_org_package_archive="(add-to-list 'package-archives '(\"org\" . \"https://orgmode.org/elpa/\") t)"
|
elisp_org_package_archive="(add-to-list 'package-archives '(\"org\" . \"https://orgmode.org/elpa/\") t)"
|
||||||
|
|
||||||
# * 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.)
|
|
||||||
files_project_source=($(files-project-source))
|
|
||||||
files_project_test=($(files-project-test))
|
|
||||||
files_project_byte_compile=("${files_project_source[@]}" "${files_project_test[@]}")
|
|
||||||
|
|
||||||
# * Args
|
# * Args
|
||||||
|
|
||||||
args=$(getopt -n "$0" \
|
args=$(getopt -n "$0" \
|
||||||
-o dhi:sS:vf:CO \
|
-o dhe:E:i:s:vf:CO \
|
||||||
-l install-deps,install-linters,debug,debug-load-path,help,install:,verbose,file:,no-color,no-compile,no-org-repo,sandbox,sandbox-dir: \
|
-l exclude:,emacs:,install-deps,install-linters,debug,debug-load-path,help,install:,verbose,file:,no-color,no-compile,no-org-repo,sandbox: \
|
||||||
-- "$@") \
|
-- "$@") \
|
||||||
|| { usage; exit 1; }
|
|| { usage; exit 1; }
|
||||||
eval set -- "$args"
|
eval set -- "$args"
|
||||||
|
|
@ -727,12 +905,13 @@ do
|
||||||
install_deps=true
|
install_deps=true
|
||||||
;;
|
;;
|
||||||
--install-linters)
|
--install-linters)
|
||||||
args_sandbox_package_install+=(--eval "(package-install 'indent-lint)"
|
install_linters=true
|
||||||
--eval "(package-install 'package-lint)")
|
|
||||||
;;
|
;;
|
||||||
-d|--debug)
|
-d|--debug)
|
||||||
debug=true
|
debug=true
|
||||||
verbose=2
|
verbose=2
|
||||||
|
args_debug=(--eval "(setq init-file-debug t)"
|
||||||
|
--eval "(setq debug-on-error t)")
|
||||||
;;
|
;;
|
||||||
--debug-load-path)
|
--debug-load-path)
|
||||||
debug_load_path=true
|
debug_load_path=true
|
||||||
|
|
@ -741,21 +920,52 @@ do
|
||||||
usage
|
usage
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
|
-E|--emacs)
|
||||||
|
shift
|
||||||
|
emacs_command=($1)
|
||||||
|
;;
|
||||||
-i|--install)
|
-i|--install)
|
||||||
shift
|
shift
|
||||||
args_sandbox_package_install+=(--eval "(package-install '$1)")
|
args_sandbox_package_install+=(--eval "(package-install '$1)")
|
||||||
;;
|
;;
|
||||||
-s|--sandbox)
|
-s|--sandbox)
|
||||||
sandbox=true
|
sandbox=true
|
||||||
;;
|
# Check whether next argument is an option, rule, or a sandbox directory.
|
||||||
-S|--sandbox-dir)
|
if [[ $2 ]] && ! [[ $2 =~ ^-- ]] \
|
||||||
|
&& ! rule-p "$2"
|
||||||
|
then
|
||||||
|
debug "Sandbox dir: $1"
|
||||||
shift
|
shift
|
||||||
sandbox=true
|
|
||||||
sandbox_dir="$1"
|
sandbox_dir="$1"
|
||||||
|
else
|
||||||
|
debug "No sandbox dir: installing dependencies."
|
||||||
|
install_deps=true
|
||||||
|
# HACK: Next argument is another option, so prepend blank arg to the
|
||||||
|
# argument list so it will be processed by next loop iteration. getopts
|
||||||
|
# doesn't allow options to have optional arguments, so we do this manually.
|
||||||
|
if [[ $2 =~ ^- ]]
|
||||||
|
then
|
||||||
|
# Next argument is an option: process it next.
|
||||||
|
new_args=("" "$@")
|
||||||
|
else
|
||||||
|
# Next argument is not an option: put it on the end.
|
||||||
|
new_arg="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
new_args=("" "$@" "$new_arg")
|
||||||
|
fi
|
||||||
|
debug "Setting new args: ${new_args[@]}"
|
||||||
|
set -- "${new_args[@]}"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
-v|--verbose)
|
-v|--verbose)
|
||||||
((verbose++))
|
((verbose++))
|
||||||
;;
|
;;
|
||||||
|
-e|--exclude)
|
||||||
|
shift
|
||||||
|
debug "Excluding file: $1"
|
||||||
|
files_exclude+=("$1")
|
||||||
|
;;
|
||||||
-f|--file)
|
-f|--file)
|
||||||
shift
|
shift
|
||||||
project_source_files+=("$1")
|
project_source_files+=("$1")
|
||||||
|
|
@ -792,27 +1002,54 @@ paths_temp+=("$package_initialize_file")
|
||||||
|
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
if ! [[ ${files_project_source[@]} ]]
|
# Discover project files.
|
||||||
|
files_project_feature=($(files-project-feature))
|
||||||
|
files_project_test=($(files-project-test))
|
||||||
|
files_project_byte_compile=("${files_project_feature[@]}" "${files_project_test[@]}")
|
||||||
|
|
||||||
|
debug "EXCLUDING FILES: ${files_exclude[@]}"
|
||||||
|
debug "FEATURE FILES: ${files_project_feature[@]}"
|
||||||
|
debug "TEST FILES: ${files_project_test[@]}"
|
||||||
|
debug "BYTE-COMPILE FILES: ${files_project_byte_compile[@]}"
|
||||||
|
|
||||||
|
if ! [[ ${files_project_feature[@]} ]]
|
||||||
then
|
then
|
||||||
error "No files specified and not in a git repo."
|
error "No files specified and not in a git repo."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Set load path.
|
||||||
|
args_load_paths=($(args-load-path))
|
||||||
|
debug "LOAD PATH ARGS: ${args_load_paths[@]}"
|
||||||
|
|
||||||
|
# If rules include linters and sandbox-dir is unspecified, install
|
||||||
|
# linters automatically.
|
||||||
|
if [[ $sandbox && ! $sandbox_dir ]] && [[ "${rest[@]}" =~ lint ]]
|
||||||
|
then
|
||||||
|
debug "Installing linters automatically."
|
||||||
|
install_linters=true
|
||||||
|
fi
|
||||||
|
|
||||||
# Initialize sandbox.
|
# Initialize sandbox.
|
||||||
[[ $sandbox ]] && sandbox
|
[[ $sandbox ]] && sandbox
|
||||||
|
|
||||||
# Run rules.
|
# Run rules.
|
||||||
for rule in "${rest[@]}"
|
for rule in "${rest[@]}"
|
||||||
do
|
do
|
||||||
if [[ $batch ]]
|
if [[ $batch || $interactive ]]
|
||||||
then
|
then
|
||||||
debug "Adding batch argument: $rule"
|
debug "Adding batch/interactive argument: $rule"
|
||||||
args_batch+=("$rule")
|
args_batch_interactive+=("$rule")
|
||||||
|
|
||||||
elif [[ $rule = batch ]]
|
elif [[ $rule = batch ]]
|
||||||
then
|
then
|
||||||
# Remaining arguments are passed to Emacs.
|
# Remaining arguments are passed to Emacs.
|
||||||
batch=true
|
batch=true
|
||||||
|
elif [[ $rule = interactive ]]
|
||||||
|
then
|
||||||
|
# Remaining arguments are passed to Emacs.
|
||||||
|
interactive=true
|
||||||
|
|
||||||
elif type -t "$rule" 2>/dev/null | grep function &>/dev/null
|
elif type -t "$rule" 2>/dev/null | grep function &>/dev/null
|
||||||
then
|
then
|
||||||
# Pass called-directly as $1 to indicate that the rule is
|
# Pass called-directly as $1 to indicate that the rule is
|
||||||
|
|
@ -828,8 +1065,9 @@ do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# The batch rule.
|
# Batch/interactive rules.
|
||||||
[[ $batch ]] && batch
|
[[ $batch ]] && batch
|
||||||
|
[[ $interactive ]] && interactive
|
||||||
|
|
||||||
if [[ $errors -gt 0 ]]
|
if [[ $errors -gt 0 ]]
|
||||||
then
|
then
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue