1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 22:30:04 +08:00
SpaceVim/bundle/neomake/Makefile
2020-06-13 14:06:35 +08:00

414 lines
15 KiB
Makefile

# Do not let mess "cd" with user-defined paths.
CDPATH:=
TEST_SHELL:=$(shell command -v bash 2>/dev/null)
ifeq ($(TEST_SHELL),)
$(error Could not determine TEST_SHELL (defaults to bash))
endif
# This is expected in tests.
TEST_VIM_PREFIX:=SHELL=$(TEST_SHELL)
SHELL:=$(TEST_SHELL) -o pipefail
# Use nvim if it is installed, otherwise vim.
ifeq ($(TEST_VIM),)
ifeq ($(shell command -v nvim 2>/dev/null),)
TEST_VIM:=vim
else
TEST_VIM:=nvim
endif
endif
IS_NEOVIM=$(findstring nvim,$(TEST_VIM))$(findstring neovim,$(TEST_VIM))
test: $(if $(IS_NEOVIM),testnvim,testvim)
test_interactive: $(if $(TEST_VIM),$(if $(IS_NEOVIM),testnvim_interactive,testvim_interactive),testnvim_interactive testvim_interactive)
VADER:=Vader!
VADER_OPTIONS:=-q
VADER_ARGS=tests/all.vader
VIM_ARGS='+$(VADER) $(VADER_OPTIONS) $(VADER_ARGS)'
NEOMAKE_TESTS_DEP_PLUGINS_DIR?=build/vim/plugins
TESTS_VADER_DIR:=$(NEOMAKE_TESTS_DEP_PLUGINS_DIR)/vader
$(TESTS_VADER_DIR):
mkdir -p $(dir $@)
git clone -q --depth=1 -b display-source-with-exceptions https://github.com/blueyed/vader.vim $@
TESTS_FUGITIVE_DIR:=$(NEOMAKE_TESTS_DEP_PLUGINS_DIR)/vim-fugitive
$(TESTS_FUGITIVE_DIR):
mkdir -p $(dir $@)
git clone -q --depth=1 https://github.com/tpope/vim-fugitive $@
DEP_PLUGINS=$(TESTS_VADER_DIR) $(TESTS_FUGITIVE_DIR)
TEST_VIMRC:=tests/vim/vimrc
testwatch: override export VADER_OPTIONS+=-q
testwatch:
contrib/run-tests-watch
testwatchx: override export VADER_OPTIONS+=-x
testwatchx: testwatch
testx: override VADER_OPTIONS+=-x
testx: test
testnvimx: override VADER_OPTIONS+=-x
testnvimx: testnvim
testvimx: override VADER_OPTIONS+=-x
testvimx: testvim
# Set Neovim logfile destination to prevent `.nvimlog` being created.
testnvim: export NVIM_LOG_FILE:=/dev/stderr
testnvim: TEST_VIM:=nvim
testnvim: TEST_VIM_PREFIX+=VADER_OUTPUT_FILE=/dev/stderr
testnvim: | build/vim-test-home $(DEP_PLUGINS)
$(call func-run-vim)
testvim: TEST_VIM:=vim
testvim: | build/vim-test-home $(DEP_PLUGINS)
$(call func-run-vim)
# Add coloring to Vader's output:
# 1. failures (includes pending) in red "(X)"
# 2. test case header in bold "(2/2)"
# 3. Neomake's debug log messages in less intense grey
# 4. non-Neomake log lines (e.g. from :Log) in bold/bright yellow.
_SED_HIGHLIGHT_ERRORS:=| contrib/highlight-log --compact vader
# Need to close stdin to fix spurious 'sed: couldn't write X items to stdout: Resource temporarily unavailable'.
# NOTE: uses </dev/null instead of <&-, because Vim behaves different then:
# - test "Automake restarts if popup menu is visible" hangs (https://github.com/vim/vim/issues/1320)
# - running the command from "make testvim" directly (i.e. without "make")
# triggers half the screen to be cleared in the end
# Vim requires stdin to be closed for feedkeys to stay in insert mode, at
# least in Docker on CircleCI.
_REDIR_STDOUT:=2>&1 >/dev/null </dev/null
# Neovim needs a valid HOME (https://github.com/neovim/neovim/issues/5277).
# Vim hangs with /dev/null on Windows (native Vim via MSYS2).
TEST_VIM_PREFIX+=HOME=$(CURDIR)/build/vim-test-home
# Neovim might quit after ~5s with stdin being closed. Use --headless mode to
# work around this.
# > Vim: Error reading input, exiting...
# > Vim: Finished.
# For Vim `-s /dev/null` is used to skip the 2s delay with warning
# "Vim: Warning: Output is not to a terminal".
COVERAGE_FILE:=.coverage_covimerage
_COVIMERAGE=$(if $(filter-out 0,$(NEOMAKE_DO_COVERAGE)),covimerage run --data-file $(COVERAGE_FILE) --append --no-report ,)
define func-run-vim
$(info Using: $(shell $(TEST_VIM_PREFIX) "$(TEST_VIM)" --version | head -n2))
($(_COVIMERAGE)$(if $(TEST_VIM_PREFIX),env $(TEST_VIM_PREFIX) ,)"$(TEST_VIM)" \
$(if $(IS_NEOVIM),$(if $(_REDIR_STDOUT),--headless,),-X $(if $(_REDIR_STDOUT),-s /dev/null,)) \
--noplugin -Nu $(TEST_VIMRC) -i NONE $(VIM_ARGS) $(_REDIR_STDOUT)) $(_SED_HIGHLIGHT_ERRORS)
endef
# Interactive tests, keep Vader open.
_run_interactive: VADER:=Vader
_run_interactive: _REDIR_STDOUT:=
_run_interactive:
$(call func-run-vim)
testvim_interactive: TEST_VIM:=vim -X
testvim_interactive: _run_interactive
testnvim_interactive: TEST_VIM:=nvim
testnvim_interactive: _run_interactive
# Manually invoke Vim, using the test setup. This helps with building tests.
runvim: VIM_ARGS:=
runvim: testvim_interactive
runnvim: VIM_ARGS:=
runnvim: testnvim_interactive
# Add targets for .vader files, absolute and relative.
# This can be used with `b:dispatch = ':Make %'` in Vim.
TESTS:=$(wildcard tests/*.vader tests/*/*.vader)
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
_TESTS_REL_AND_ABS:=$(call uniq,$(abspath $(TESTS)) $(TESTS))
FILE_TEST_TARGET=$(if $(IS_NEOVIM),testnvim,testvim)
$(_TESTS_REL_AND_ABS):
$(MAKE) --no-print-directory $(FILE_TEST_TARGET) VADER_ARGS='$@'
.PHONY: $(_TESTS_REL_AND_ABS)
testcoverage: COVERAGE_VADER_ARGS:=tests/main.vader $(wildcard tests/isolated/*.vader)
testcoverage:
$(RM) $(COVERAGE_FILE)
@ret=0; \
for testfile in $(COVERAGE_VADER_ARGS); do \
$(MAKE) --no-print-directory test VADER_ARGS=$$testfile NEOMAKE_DO_COVERAGE=1 || (( ++ret )); \
done; \
exit $$ret
tags:
ctags -R --langmap=vim:+.vader
.PHONY: tags
# Linters, called from .travis.yml.
LINT_ARGS:=./plugin ./autoload
# Vint.
VINT_BIN=$(shell command -v vint 2>/dev/null || echo build/vint/bin/vint)
build/vint: | build
$(shell command -v virtualenv 2>/dev/null || echo python3 -m venv) $@
build/vint/bin/vint: | build/vint
build/vint/bin/pip install --quiet vim-vint
vint: | $(VINT_BIN)
$| --color $(LINT_ARGS)
vint-errors: | $(VINT_BIN)
$| --color --error $(LINT_ARGS)
# vimlint
VIMLINT_BIN=$(shell command -v vimlint 2>/dev/null || echo build/vimlint/bin/vimlint.sh -l build/vimlint -p build/vimlparser)
build/vimlint/bin/vimlint.sh: build/vimlint build/vimlparser
build/vimlint: | build
git clone -q --depth=1 https://github.com/syngan/vim-vimlint $@
build/vimlparser: | build
git clone -q --depth=1 https://github.com/ynkdir/vim-vimlparser $@
VIMLINT_OPTIONS=-u -e EVL102.l:_=1 -e 'EVL103.a:_.*=1'
vimlint: | $(firstword $(VIMLINT_BIN))
$(VIMLINT_BIN) $(VIMLINT_OPTIONS) $(LINT_ARGS)
vimlint-errors: | $(firstword VIMLINT_BIN)
$(VIMLINT_BIN) $(VIMLINT_OPTIONS) -E $(LINT_ARGS)
build build/vim-test-home:
mkdir $@
build/vim-test-home: | build
build/vimhelplint: | build
cd build \
&& wget -O- https://github.com/machakann/vim-vimhelplint/archive/master.tar.gz \
| tar xz \
&& mv vim-vimhelplint-master vimhelplint
vimhelplint: | $(if $(VIMHELPLINT_DIR),,build/vimhelplint)
contrib/vimhelplint doc/neomake.txt
# Run tests in dockerized Vims.
DOCKER_REPO:=neomake/vims-for-tests
DOCKER_TAG:=50
NEOMAKE_DOCKER_IMAGE?=
DOCKER_IMAGE:=$(if $(NEOMAKE_DOCKER_IMAGE),$(NEOMAKE_DOCKER_IMAGE),$(DOCKER_REPO):$(DOCKER_TAG))
DOCKER_STREAMS:=-ti
DOCKER_ARGS:=
DOCKER=docker run $(DOCKER_STREAMS) --rm \
-v $(PWD):/testplugin \
-w /testplugin \
-e NEOMAKE_TEST_NO_COLORSCHEME \
$(DOCKER_ARGS) $(DOCKER_IMAGE)
docker_image:
docker build -f Dockerfile.tests -t $(DOCKER_REPO):$(DOCKER_TAG) .
docker_push:
docker push $(DOCKER_REPO):$(DOCKER_TAG)
docker_update_latest:
docker tag $(DOCKER_REPO):$(DOCKER_TAG) $(DOCKER_REPO):latest
docker push $(DOCKER_REPO):latest
docker_update_image:
@git diff --cached --exit-code >/dev/null || { echo "WARN: git index is not clean."; }
@if git diff --exit-code -- Makefile >/dev/null; then \
sed -i '/^DOCKER_TAG:=/s/:=.*/:=$(shell echo $$(($(DOCKER_TAG)+1)))/' Makefile; \
else \
echo "WARN: Makefile is not clean. Not updating."; \
fi
@if git diff --exit-code -- Dockerfile.tests >/dev/null; then \
sed -i '/^ENV NEOMAKE_DOCKERFILE_UPDATE=/s/=.*/=$(shell date +%Y-%m-%d)/' Dockerfile.tests; \
else \
echo "WARN: Dockerfile.tests is not clean. Not updating."; \
fi
make docker_image
make docker_test DOCKER_VIM=vim81
@echo "Done. Use 'make docker_push' to push it, and then update .circleci/config.yml."
DOCKER_VIMS:=vim73 vim74-trusty vim74-xenial vim80 vim81 \
neovim-v0.1.7 neovim-v0.3.8 neovim-master vim-master
_DOCKER_VIM_TARGETS:=$(addprefix docker_test-,$(DOCKER_VIMS))
docker_test_all: $(_DOCKER_VIM_TARGETS)
$(_DOCKER_VIM_TARGETS):
$(MAKE) docker_test DOCKER_VIM=$(patsubst docker_test-%,%,$@)
_docker_test: DOCKER_VIM:=vim81
_docker_test: DOCKER_MAKE_TARGET=$(DOCKER_MAKE_TEST_TARGET) \
TEST_VIM='/vim-build/bin/$(DOCKER_VIM)' \
VADER_OPTIONS="$(VADER_OPTIONS)" VADER_ARGS="$(VADER_ARGS)" \
_REDIR_STDOUT="$(_REDIR_STDOUT)" \
$(DOCKER_MAKE_TEST_ARGS)
_docker_test: docker_make
docker_test: DOCKER_MAKE_TEST_TARGET:=test
docker_test: DOCKER_STREAMS:=-t
docker_test: _docker_test
docker_test_interactive: DOCKER_MAKE_TEST_TARGET:=test_interactive
docker_test_interactive: DOCKER_STREAMS:=-ti
docker_test_interactive: _docker_test
docker_testcoverage: DOCKER_MAKE_TEST_TARGET:=testcoverage
# Pick up VADER_ARGS from command line for COVERAGE_VADER_ARGS.
docker_testcoverage: DOCKER_MAKE_TEST_ARGS:=$(if $(filter command line,$(origin COVERAGE_VADER_ARGS)),COVERAGE_VADER_ARGS="$(COVERAGE_VADER_ARGS)",$(if $(filter command line,$(origin VADER_ARGS)),COVERAGE_VADER_ARGS="$(VADER_ARGS)",))
docker_testcoverage: DOCKER_STREAMS:=-t
docker_testcoverage: _docker_test
sed -i 's~/testplugin/~$(CURDIR)/~g' $(COVERAGE_FILE)
coverage report -m
docker_run: DOCKER_ARGS:=-e PATH=/vim-build/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
docker_run: $(DEP_PLUGINS)
docker_run:
$(DOCKER) $(if $(DOCKER_RUN),$(DOCKER_RUN),bash)
# Pass down/through MAKEFLAGS explicitly (not available in Docker env).
docker_make: DOCKER_RUN=$(MAKE) -$(MAKEFLAGS) $(DOCKER_MAKE_TARGET)
docker_make: docker_run
docker_check: DOCKER_MAKE_TARGET=check_docker
docker_check: docker_make
docker_vimhelplint:
$(MAKE) docker_make DOCKER_MAKE_TARGET=vimhelplint
_ECHO_DOCKER_VIMS:=ls /vim-build/bin | grep vim | sort
docker_list_vims:
docker run --rm $(DOCKER_IMAGE) $(_ECHO_DOCKER_VIMS)
check_lint_diff:
@# NOTE: does not see changed files for builds on master.
@set -e; \
echo "Looking for changed files (to origin/master)."; \
CHANGED_VIM_FILES=($$(git diff-tree --no-commit-id --name-only --diff-filter=AM -r origin/master.. \
| grep '\.vim$$' | grep -v '^tests/fixtures')) || true; \
ret=0; \
if [ "$${#CHANGED_VIM_FILES[@]}" -eq 0 ]; then \
echo 'No .vim files changed.'; \
else \
MAKE_ARGS="LINT_ARGS=$${CHANGED_VIM_FILES[*]}"; \
echo "== Running \"make vimlint $$MAKE_ARGS\" =="; \
$(MAKE) --no-print-directory vimlint "$$MAKE_ARGS" || (( ret+=1 )); \
echo "== Running \"make vint $$MAKE_ARGS\" =="; \
$(MAKE) --no-print-directory vint "$$MAKE_ARGS" || (( ret+=2 )); \
fi; \
if ! git diff-tree --quiet --exit-code --diff-filter=AM -r origin/master.. -- doc/neomake.txt; then \
echo "== Running \"make vimhelplint\" for changed doc/neomake.txt =="; \
$(MAKE) --no-print-directory vimhelplint || (( ret+=4 )); \
fi; \
exit $$ret
check_lint: vimlint vint vimhelplint
# Checks to be run within the Docker image.
check_docker:
@:; set -e; ret=0; \
echo '== Checking for DOCKER_VIMS to be in sync'; \
vims=$$($(_ECHO_DOCKER_VIMS)); \
docker_vims="$$(printf '%s\n' $(DOCKER_VIMS) | sort)"; \
if ! [ "$$vims" = "$$docker_vims" ]; then \
echo "DOCKER_VIMS is out of sync with Vims in image."; \
diff <(echo "$$vims") <(echo "$$docker_vims"); \
(( ret+=8 )); \
fi; \
exit $$ret
# Like CircleCI runs them.
check_in_docker: DOCKER_MAKE_TARGET=checkqa
check_in_docker: docker_make
# Run in CircleCI.
checkqa:
$(MAKE) -k check check_docker check_lint_diff
check:
@:; set -e; ret=0; \
[ $$TERM = dumb ] && export TERM=xterm; \
echo_bold() { tput bold; echo "$$@"; tput sgr0; }; \
echo '== Checking that all tests are included'; \
for f in $(filter-out all.vader main.vader isolated.vader,$(notdir $(shell git ls-files tests/*.vader))); do \
if ! grep -q "^Include.*: $$f" tests/main.vader; then \
echo_bold "Test not included in main.vader: $$f" >&2; ret=1; \
fi; \
done; \
for f in $(notdir $(shell git ls-files tests/isolated/*.vader)); do \
if ! grep -q "^Include.*: isolated/$$f" tests/isolated.vader; then \
echo_bold "Test not included in isolated.vader: $$f" >&2; ret=1; \
fi; \
done; \
echo '== Checking for absent Before sections in tests'; \
if grep '^Before:' tests/*.vader; then \
echo_bold "Before: should not be used in tests itself, because it overrides the global one."; \
(( ret+=2 )); \
fi; \
echo '== Checking for absent :Log calls'; \
if git --no-pager grep --line-number --color --perl-regexp '^(\s*au.*\b)?\s*Log\b' \
-- :^tests/include/init.vim :^tests/include/setup.vader; then \
echo_bold "Found Log commands."; \
(( ret+=4 )); \
fi; \
echo '== Checking tests'; \
output="$$(grep --line-number --color AssertThrows -A1 tests/*.vader)"; \
output="$(echo "$$output" \
| grep -E '^[^[:space:]]+- ' \
| grep -v g:vader_exception | sed -e s/-/:/ -e s/-// || true)"; \
if [[ -n "$$output" ]]; then \
echo_bold 'AssertThrows used without checking g:vader_exception:' >&2; \
echo "$$output" >&2; \
(( ret+=16 )); \
fi; \
echo '== Running custom checks'; \
tput bold; \
contrib/vim-checks $(LINT_ARGS) || (( ret+= 16 )); \
tput sgr0; \
exit $$ret
NEOMAKE_LOG:=/tmp/neomake.log
tail_log:
fifo=$(shell mktemp -u); \
mkfifo $$fifo; \
tail -f $(NEOMAKE_LOG) \
| $(CURDIR)/contrib/highlight-log >> $$fifo & \
less --force --chop-long-lines +F $$fifo
clean:
$(RM) -r build
.PHONY: clean
# Fixtures {{{
# A function to define targets/rules for fixture generation.
# Args:
# 1: the tool (bin) and input/output dir.
# 2: arguments for the tool
# NOTE: uses "sed -i.bak" for MacOS's default sed.
define func-generate-fixture
tests/fixtures/output/$1:
mkdir -p $$@
tests/fixtures/output/$1/%.stderr tests/fixtures/output/$1/%.stdout tests/fixtures/output/$1/%.exitcode: tests/fixtures/input/$1/% | tests/fixtures/output/$1
@baseout=tests/fixtures/output/$1/$$*; \
echo "Generating $$$$baseout"; \
$1 $2 $$< >$$$$baseout.stdout 2>$$$$baseout.stderr; \
ret=$$$$?; \
printf $$$$ret > $$$$baseout.exitcode; \
if ! [ -f $$$$baseout.stdout ]; then \
echo "Missing output: $$$$baseout.stdout." >&2; exit 1; \
fi; \
sed -i.bak -e "s~$(CURDIR)/~/tmp/neomake-tests/~g" \
$$$$baseout.stdout $$$$baseout.stderr; \
$(RM) $$$$baseout.stdout.bak $$$$baseout.stderr.bak
endef
# Call and eval the above function to generate rules for different tools.
$(eval $(call func-generate-fixture,puppet,parser validate --color=false))
$(eval $(call func-generate-fixture,puppet-lint,--log-format "%{path}:%{line}:%{column}:%{kind}:[%{check}] %{message}"))
$(eval $(call func-generate-fixture,xmllint,--xinclude --postvalid --noout))
$(eval $(call func-generate-fixture,zsh,-n))
_FIXTURES_INPUT:=$(wildcard tests/fixtures/input/*/*)
_FIXTURES_OUTPUT:=$(patsubst tests/fixtures/input/%,tests/fixtures/output/%,$(addsuffix .stdout,$(_FIXTURES_INPUT)) $(addsuffix .stderr,$(_FIXTURES_INPUT)))
fixtures: $(_FIXTURES_OUTPUT)
.PHONY: fixtures
fixtures-rebuild:
$(RM) tests/fixtures/output/*/*.stdout tests/fixtures/output/*/*.stderr
$(MAKE) --keep-going fixtures
.PHONY: fixtures-rebuild
# }}}
.PHONY: vint vint-errors vimlint vimlint-errors
.PHONY: test testnvim testvim testnvim_interactive testvim_interactive
.PHONY: runvim runnvim tags _run_tests