Merge branch 'ab/coccicheck-incremental'
"make coccicheck" is time consuming. It has been made to run more incrementally. * ab/coccicheck-incremental: Makefile: don't create a ".build/.build/" for cocci, fix output spatchcache: add a ccache-alike for "spatch" cocci: run against a generated ALL.cocci cocci rules: remove <id>'s from rules that don't need them Makefile: copy contrib/coccinelle/*.cocci to build/ cocci: optimistically use COMPUTE_HEADER_DEPENDENCIES cocci: make "coccicheck" rule incremental cocci: split off "--all-includes" from SPATCH_FLAGS cocci: split off include-less "tests" from SPATCH_FLAGS Makefile: split off SPATCH_BATCH_SIZE comment from "cocci" heading Makefile: have "coccicheck" re-run if flags change Makefile: add ability to TAB-complete cocci *.patch rules cocci rules: remove unused "F" metavariable from pending rule Makefile + shared.mak: rename and indent $(QUIET_SPATCH_T)
This commit is contained in:
commit
4b76998ff0
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@
|
||||
/GIT-PERL-HEADER
|
||||
/GIT-PYTHON-VARS
|
||||
/GIT-SCRIPT-DEFINES
|
||||
/GIT-SPATCH-DEFINES
|
||||
/GIT-USER-AGENT
|
||||
/GIT-VERSION-FILE
|
||||
/bin-wrappers/
|
||||
|
177
Makefile
177
Makefile
@ -1367,11 +1367,53 @@ SP_EXTRA_FLAGS = -Wno-universal-initializer
|
||||
SANITIZE_LEAK =
|
||||
SANITIZE_ADDRESS =
|
||||
|
||||
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
|
||||
# usually result in less CPU usage at the cost of higher peak memory.
|
||||
# Setting it to 0 will feed all files in a single spatch invocation.
|
||||
SPATCH_FLAGS = --all-includes
|
||||
SPATCH_BATCH_SIZE = 1
|
||||
# For the 'coccicheck' target
|
||||
SPATCH_INCLUDE_FLAGS = --all-includes
|
||||
SPATCH_FLAGS =
|
||||
SPATCH_TEST_FLAGS =
|
||||
|
||||
# If *.o files are present, have "coccicheck" depend on them, with
|
||||
# COMPUTE_HEADER_DEPENDENCIES this will speed up the common-case of
|
||||
# only needing to re-generate coccicheck results for the users of a
|
||||
# given API if it's changed, and not all files in the project. If
|
||||
# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.
|
||||
SPATCH_USE_O_DEPENDENCIES = YesPlease
|
||||
|
||||
# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci
|
||||
# files into a single contrib/cocci/ALL.cocci before running
|
||||
# "coccicheck".
|
||||
#
|
||||
# Pros:
|
||||
#
|
||||
# - Speeds up a one-shot run of "make coccicheck", as we won't have to
|
||||
# parse *.[ch] files N times for the N *.cocci rules
|
||||
#
|
||||
# Cons:
|
||||
#
|
||||
# - Will make incremental development of *.cocci slower, as
|
||||
# e.g. changing strbuf.cocci will re-run all *.cocci.
|
||||
#
|
||||
# - Makes error and performance analysis harder, as rules will be
|
||||
# applied from a monolithic ALL.cocci, rather than
|
||||
# e.g. strbuf.cocci. To work around this either undefine this, or
|
||||
# generate a specific patch, e.g. this will always use strbuf.cocci,
|
||||
# not ALL.cocci:
|
||||
#
|
||||
# make contrib/coccinelle/strbuf.cocci.patch
|
||||
SPATCH_CONCAT_COCCI = YesPlease
|
||||
|
||||
# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
|
||||
TRACK_SPATCH_DEFINES =
|
||||
TRACK_SPATCH_DEFINES += $(SPATCH)
|
||||
TRACK_SPATCH_DEFINES += $(SPATCH_INCLUDE_FLAGS)
|
||||
TRACK_SPATCH_DEFINES += $(SPATCH_FLAGS)
|
||||
TRACK_SPATCH_DEFINES += $(SPATCH_TEST_FLAGS)
|
||||
GIT-SPATCH-DEFINES: FORCE
|
||||
@FLAGS='$(TRACK_SPATCH_DEFINES)'; \
|
||||
if test x"$$FLAGS" != x"`cat GIT-SPATCH-DEFINES 2>/dev/null`" ; then \
|
||||
echo >&2 " * new spatch flags"; \
|
||||
echo "$$FLAGS" >GIT-SPATCH-DEFINES; \
|
||||
fi
|
||||
|
||||
include config.mak.uname
|
||||
-include config.mak.autogen
|
||||
@ -3207,35 +3249,113 @@ check: $(GENERATED_H)
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci
|
||||
COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)
|
||||
COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)
|
||||
COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))
|
||||
COCCI_RULES =
|
||||
COCCI_RULES += $(COCCI_GEN_ALL)
|
||||
COCCI_RULES += $(COCCI_RULES_TRACKED)
|
||||
COCCI_NAMES =
|
||||
COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)
|
||||
|
||||
COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))
|
||||
COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))
|
||||
|
||||
COCCICHECK_PATCHES = $(COCCICHECK:%=%.patch)
|
||||
COCCICHECK_PATCHES_PENDING = $(COCCICHECK_PENDING:%=%.patch)
|
||||
|
||||
COCCICHECK_PATCHES_INTREE = $(COCCICHECK_PATCHES:.build/%=%)
|
||||
COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)
|
||||
|
||||
# It's expensive to compute the many=many rules below, only eval them
|
||||
# on $(MAKECMDGOALS) that match these $(COCCI_RULES)
|
||||
COCCI_RULES_GLOB =
|
||||
COCCI_RULES_GLOB += cocci%
|
||||
COCCI_RULES_GLOB += .build/contrib/coccinelle/%
|
||||
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)
|
||||
COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)
|
||||
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)
|
||||
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)
|
||||
COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))
|
||||
|
||||
COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
|
||||
|
||||
%.cocci.patch: %.cocci $(COCCI_SOURCES)
|
||||
$(QUIET_SPATCH) \
|
||||
if test $(SPATCH_BATCH_SIZE) = 0; then \
|
||||
limit=; \
|
||||
else \
|
||||
limit='-n $(SPATCH_BATCH_SIZE)'; \
|
||||
fi; \
|
||||
if ! echo $(COCCI_SOURCES) | xargs $$limit \
|
||||
$(SPATCH) $(SPATCH_FLAGS) \
|
||||
--sp-file $< --patch . \
|
||||
>$@+ 2>$@.log; \
|
||||
$(COCCI_RULES_TRACKED): .build/% : %
|
||||
$(call mkdir_p_parent_template)
|
||||
$(QUIET_CP)cp $< $@
|
||||
|
||||
.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)
|
||||
$(call mkdir_p_parent_template)
|
||||
$(QUIET_GEN) >$@
|
||||
|
||||
$(COCCI_GEN_ALL): $(COCCI_RULES_TRACKED_NO_PENDING)
|
||||
$(call mkdir_p_parent_template)
|
||||
$(QUIET_SPATCH_CAT)cat $^ >$@
|
||||
|
||||
ifeq ($(COMPUTE_HEADER_DEPENDENCIES),no)
|
||||
SPATCH_USE_O_DEPENDENCIES =
|
||||
endif
|
||||
define cocci-rule
|
||||
|
||||
## Rule for .build/$(1).patch/$(2); Params:
|
||||
# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"
|
||||
# $(2) = e.g. "grep.c"
|
||||
# $(3) = e.g. "grep.o"
|
||||
COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch
|
||||
$(1).d/$(2).patch: GIT-SPATCH-DEFINES
|
||||
$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)
|
||||
$(1).d/$(2).patch: $(1)
|
||||
$(1).d/$(2).patch: $(1).d/%.patch : %
|
||||
$$(call mkdir_p_parent_template)
|
||||
$$(QUIET_SPATCH)if ! $$(SPATCH) $$(SPATCH_FLAGS) \
|
||||
$$(SPATCH_INCLUDE_FLAGS) \
|
||||
--sp-file $(1) --patch . $$< \
|
||||
>$$@ 2>$$@.log; \
|
||||
then \
|
||||
cat $@.log; \
|
||||
echo "ERROR when applying '$(1)' to '$$<'; '$$@.log' follows:"; \
|
||||
cat $$@.log; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
mv $@+ $@; \
|
||||
if test -s $@; \
|
||||
then \
|
||||
echo ' ' SPATCH result: $@; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define cocci-matrix
|
||||
|
||||
$(foreach s,$(COCCI_SOURCES),$(call cocci-rule,$(c),$(s),$(s:%.c=%.o)))
|
||||
endef
|
||||
|
||||
ifdef COCCI_GOALS
|
||||
$(eval $(foreach c,$(COCCI_RULES),$(call cocci-matrix,$(c))))
|
||||
endif
|
||||
|
||||
define spatch-rule
|
||||
|
||||
.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))
|
||||
$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \
|
||||
if test -s $$@; \
|
||||
then \
|
||||
echo ' ' SPATCH result: $$@; \
|
||||
fi
|
||||
contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch
|
||||
$$(QUIET_CP)cp $$< $$@
|
||||
|
||||
endef
|
||||
|
||||
ifdef COCCI_GOALS
|
||||
$(eval $(foreach n,$(COCCI_NAMES),$(call spatch-rule,$(n))))
|
||||
endif
|
||||
|
||||
COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
|
||||
$(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES
|
||||
$(COCCI_TEST_RES_GEN): .build/%.res : %.c
|
||||
$(COCCI_TEST_RES_GEN): .build/%.res : %.res
|
||||
ifdef SPATCH_CONCAT_COCCI
|
||||
$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)
|
||||
else
|
||||
$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
|
||||
endif
|
||||
$(call mkdir_p_parent_template)
|
||||
$(QUIET_SPATCH_T)$(SPATCH) $(SPATCH_FLAGS) \
|
||||
$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \
|
||||
--very-quiet --no-show-diff \
|
||||
--sp-file $< -o $@ \
|
||||
$(@:.build/%.res=%.c) && \
|
||||
@ -3246,11 +3366,15 @@ $(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinell
|
||||
coccicheck-test: $(COCCI_TEST_RES_GEN)
|
||||
|
||||
coccicheck: coccicheck-test
|
||||
coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci)))
|
||||
ifdef SPATCH_CONCAT_COCCI
|
||||
coccicheck: contrib/coccinelle/ALL.cocci.patch
|
||||
else
|
||||
coccicheck: $(COCCICHECK_PATCHES_INTREE)
|
||||
endif
|
||||
|
||||
# See contrib/coccinelle/README
|
||||
coccicheck-pending: coccicheck-test
|
||||
coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci))
|
||||
coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)
|
||||
|
||||
.PHONY: coccicheck coccicheck-pending
|
||||
|
||||
@ -3517,8 +3641,9 @@ profile-clean:
|
||||
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
|
||||
|
||||
cocciclean:
|
||||
$(RM) GIT-SPATCH-DEFINES
|
||||
$(RM) -r .build/contrib/coccinelle
|
||||
$(RM) contrib/coccinelle/*.cocci.patch*
|
||||
$(RM) contrib/coccinelle/*.cocci.patch
|
||||
|
||||
clean: profile-clean coverage-clean cocciclean
|
||||
$(RM) -r .build
|
||||
|
2
contrib/coccinelle/.gitignore
vendored
2
contrib/coccinelle/.gitignore
vendored
@ -1 +1 @@
|
||||
*.patch*
|
||||
*.patch
|
||||
|
@ -41,3 +41,52 @@ There are two types of semantic patches:
|
||||
|
||||
This allows to expose plans of pending large scale refactorings without
|
||||
impacting the bad pattern checks.
|
||||
|
||||
Git-specific tips & things to know about how we run "spatch":
|
||||
|
||||
* The "make coccicheck" will piggy-back on
|
||||
"COMPUTE_HEADER_DEPENDENCIES". If you've built a given object file
|
||||
the "coccicheck" target will consider its depednency to decide if
|
||||
it needs to re-run on the corresponding source file.
|
||||
|
||||
This means that a "make coccicheck" will re-compile object files
|
||||
before running. This might be unexpected, but speeds up the run in
|
||||
the common case, as e.g. a change to "column.h" won't require all
|
||||
coccinelle rules to be re-run against "grep.c" (or another file
|
||||
that happens not to use "column.h").
|
||||
|
||||
To disable this behavior use the "SPATCH_USE_O_DEPENDENCIES=NoThanks"
|
||||
flag.
|
||||
|
||||
* To speed up our rules the "make coccicheck" target will by default
|
||||
concatenate all of the *.cocci files here into an "ALL.cocci", and
|
||||
apply it to each source file.
|
||||
|
||||
This makes the run faster, as we don't need to run each rule
|
||||
against each source file. See the Makefile for further discussion,
|
||||
this behavior can be disabled with "SPATCH_CONCAT_COCCI=".
|
||||
|
||||
But since they're concatenated any <id> in the <rulname> (e.g. "@
|
||||
my_name", v.s. anonymous "@@") needs to be unique across all our
|
||||
*.cocci files. You should only need to name rules if other rules
|
||||
depend on them (currently only one rule is named).
|
||||
|
||||
* To speed up incremental runs even more use the "spatchcache" tool
|
||||
in this directory as your "SPATCH". It aimns to be a "ccache" for
|
||||
coccinelle, and piggy-backs on "COMPUTE_HEADER_DEPENDENCIES".
|
||||
|
||||
It caches in Redis by default, see it source for a how-to.
|
||||
|
||||
In one setup with a primed cache "make coccicheck" followed by a
|
||||
"make clean && make" takes around 10s to run, but 2m30s with the
|
||||
default of "SPATCH_CONCAT_COCCI=Y".
|
||||
|
||||
With "SPATCH_CONCAT_COCCI=" the total runtime is around ~6m, sped
|
||||
up to ~1m with "spatchcache".
|
||||
|
||||
Most of the 10s (or ~1m) being spent on re-running "spatch" on
|
||||
files we couldn't cache, as we didn't compile them (in contrib/*
|
||||
and compat/* mostly).
|
||||
|
||||
The absolute times will differ for you, but the relative speedup
|
||||
from caching should be on that order.
|
||||
|
@ -1,4 +1,4 @@
|
||||
@ hashmap_entry_init_usage @
|
||||
@@
|
||||
expression E;
|
||||
struct hashmap_entry HME;
|
||||
@@
|
||||
|
@ -1,4 +1,4 @@
|
||||
@ preincrement @
|
||||
@@
|
||||
identifier i;
|
||||
@@
|
||||
- ++i > 1
|
||||
|
304
contrib/coccinelle/spatchcache
Executable file
304
contrib/coccinelle/spatchcache
Executable file
@ -0,0 +1,304 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# spatchcache: a poor-man's "ccache"-alike for "spatch" in git.git
|
||||
#
|
||||
# This caching command relies on the peculiarities of the Makefile
|
||||
# driving "spatch" in git.git, in particular if we invoke:
|
||||
#
|
||||
# make
|
||||
# # See "spatchCache.cacheWhenStderr" for why "--very-quiet" is
|
||||
# # used
|
||||
# make coccicheck SPATCH_FLAGS=--very-quiet
|
||||
#
|
||||
# We can with COMPUTE_HEADER_DEPENDENCIES (auto-detected as true with
|
||||
# "gcc" and "clang") write e.g. a .depend/grep.o.d for grep.c, when we
|
||||
# compile grep.o.
|
||||
#
|
||||
# The .depend/grep.o.d will have the full header dependency tree of
|
||||
# grep.c, and we can thus cache the output of "spatch" by:
|
||||
#
|
||||
# 1. Hashing all of those files
|
||||
# 2. Hashing our source file, and the *.cocci rule we're
|
||||
# applying
|
||||
# 3. Running spatch, if suggests no changes (by far the common
|
||||
# case) we invoke "spatchCache.getCmd" and
|
||||
# "spatchCache.setCmd" with a hash SHA-256 to ask "does this
|
||||
# ID have no changes" or "say that ID had no changes>
|
||||
# 4. If no "spatchCache.{set,get}Cmd" is specified we'll use
|
||||
# "redis-cli" and maintain a SET called "spatch-cache". Set
|
||||
# appropriate redis memory policies to keep it from growing
|
||||
# out of control.
|
||||
#
|
||||
# This along with the general incremental "make" support for
|
||||
# "contrib/coccinelle" makes it viable to (re-)run coccicheck
|
||||
# e.g. when merging integration branches.
|
||||
#
|
||||
# Note that the "--very-quiet" flag is currently critical. The cache
|
||||
# will refuse to cache anything that has output on STDERR (which might
|
||||
# be errors from spatch), but see spatchCache.cacheWhenStderr below.
|
||||
#
|
||||
# The STDERR (and exit code) could in principle be cached (as with
|
||||
# ccache), but then the simple structure in the Redis cache would need
|
||||
# to change, so just supply "--very-quiet" for now.
|
||||
#
|
||||
# To use this, simply set SPATCH to
|
||||
# contrib/coccinelle/spatchcache. Then optionally set:
|
||||
#
|
||||
# [spatchCache]
|
||||
# # Optional: path to a custom spatch
|
||||
# spatch = ~/g/coccicheck/spatch.opt
|
||||
#
|
||||
# As well as this trace config (debug implies trace):
|
||||
#
|
||||
# cacheWhenStderr = true
|
||||
# trace = false
|
||||
# debug = false
|
||||
#
|
||||
# The ".depend/grep.o.d" can also be customized, as a string that will
|
||||
# be eval'd, it has access to a "$dirname" and "$basename":
|
||||
#
|
||||
# [spatchCache]
|
||||
# dependFormat = "$dirname/.depend/${basename%.c}.o.d"
|
||||
#
|
||||
# Setting "trace" to "true" allows for seeing when we have a cache HIT
|
||||
# or MISS. To debug whether the cache is working do that, and run e.g.:
|
||||
#
|
||||
# redis-cli FLUSHALL
|
||||
# <make && make coccicheck, as above>
|
||||
# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c
|
||||
# 600 CANTCACHE
|
||||
# 7365 MISS
|
||||
# 7365 SET
|
||||
#
|
||||
# A subsequent "make cocciclean && make coccicheck" should then have
|
||||
# all "HIT"'s and "CANTCACHE"'s.
|
||||
#
|
||||
# The "spatchCache.cacheWhenStderr" option is critical when using
|
||||
# spatchCache.{trace,debug} to debug whether something is set in the
|
||||
# cache, as we'll write to the spatch logs in .build/* we'd otherwise
|
||||
# always emit a NOCACHE.
|
||||
#
|
||||
# Reading the config can make the command much slower, to work around
|
||||
# this the config can be set in the environment, with environment
|
||||
# variable name corresponding to the config key. "default" can be used
|
||||
# to use whatever's the script default, e.g. setting
|
||||
# spatchCache.cacheWhenStderr=true and deferring to the defaults for
|
||||
# the rest is:
|
||||
#
|
||||
# export GIT_CONTRIB_SPATCHCACHE_DEBUG=default
|
||||
# export GIT_CONTRIB_SPATCHCACHE_TRACE=default
|
||||
# export GIT_CONTRIB_SPATCHCACHE_CACHEWHENSTDERR=true
|
||||
# export GIT_CONTRIB_SPATCHCACHE_SPATCH=default
|
||||
# export GIT_CONTRIB_SPATCHCACHE_DEPENDFORMAT=default
|
||||
# export GIT_CONTRIB_SPATCHCACHE_SETCMD=default
|
||||
# export GIT_CONTRIB_SPATCHCACHE_GETCMD=default
|
||||
|
||||
set -e
|
||||
|
||||
env_or_config () {
|
||||
env="$1"
|
||||
shift
|
||||
if test "$env" = "default"
|
||||
then
|
||||
# Avoid expensive "git config" invocation
|
||||
return
|
||||
elif test -n "$env"
|
||||
then
|
||||
echo "$env"
|
||||
else
|
||||
git config $@ || :
|
||||
fi
|
||||
}
|
||||
|
||||
## Our own configuration & options
|
||||
debug=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_DEBUG" --bool "spatchCache.debug")
|
||||
if test "$debug" != "true"
|
||||
then
|
||||
debug=
|
||||
fi
|
||||
if test -n "$debug"
|
||||
then
|
||||
set -x
|
||||
fi
|
||||
|
||||
trace=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_TRACE" --bool "spatchCache.trace")
|
||||
if test "$trace" != "true"
|
||||
then
|
||||
trace=
|
||||
fi
|
||||
if test -n "$debug"
|
||||
then
|
||||
# debug implies trace
|
||||
trace=true
|
||||
fi
|
||||
|
||||
cacheWhenStderr=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_CACHEWHENSTDERR" --bool "spatchCache.cacheWhenStderr")
|
||||
if test "$cacheWhenStderr" != "true"
|
||||
then
|
||||
cacheWhenStderr=
|
||||
fi
|
||||
|
||||
trace_it () {
|
||||
if test -z "$trace"
|
||||
then
|
||||
return
|
||||
fi
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
spatch=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_SPATCH" --path "spatchCache.spatch")
|
||||
if test -n "$spatch"
|
||||
then
|
||||
if test -n "$debug"
|
||||
then
|
||||
trace_it "custom spatchCache.spatch='$spatch'"
|
||||
fi
|
||||
else
|
||||
spatch=spatch
|
||||
fi
|
||||
|
||||
dependFormat='$dirname/.depend/${basename%.c}.o.d'
|
||||
dependFormatCfg=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_DEPENDFORMAT" "spatchCache.dependFormat")
|
||||
if test -n "$dependFormatCfg"
|
||||
then
|
||||
dependFormat="$dependFormatCfg"
|
||||
fi
|
||||
|
||||
set=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_SETCMD" "spatchCache.setCmd")
|
||||
get=$(env_or_config "$GIT_CONTRIB_SPATCHCACHE_GETCMD" "spatchCache.getCmd")
|
||||
|
||||
## Parse spatch()-like command-line for caching info
|
||||
arg_sp=
|
||||
arg_file=
|
||||
args="$@"
|
||||
spatch_opts() {
|
||||
while test $# != 0
|
||||
do
|
||||
arg_file="$1"
|
||||
case "$1" in
|
||||
--sp-file)
|
||||
arg_sp="$2"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
spatch_opts "$@"
|
||||
if ! test -f "$arg_file"
|
||||
then
|
||||
arg_file=
|
||||
fi
|
||||
|
||||
hash_for_cache() {
|
||||
# Parameters that should affect the cache
|
||||
echo "args=$args"
|
||||
echo "config spatchCache.spatch=$spatch"
|
||||
echo "config spatchCache.debug=$debug"
|
||||
echo "config spatchCache.trace=$trace"
|
||||
echo "config spatchCache.cacheWhenStderr=$cacheWhenStderr"
|
||||
echo
|
||||
|
||||
# Our target file and its dependencies
|
||||
git hash-object "$1" "$2" $(grep -E -o '^[^:]+:$' "$3" | tr -d ':')
|
||||
}
|
||||
|
||||
# Sanity checks
|
||||
if ! test -f "$arg_sp" && ! test -f "$arg_file"
|
||||
then
|
||||
echo $0: no idea how to cache "$@" >&2
|
||||
exit 128
|
||||
fi
|
||||
|
||||
# Main logic
|
||||
dirname=$(dirname "$arg_file")
|
||||
basename=$(basename "$arg_file")
|
||||
eval "dep=$dependFormat"
|
||||
|
||||
if ! test -f "$dep"
|
||||
then
|
||||
trace_it "$0: CANTCACHE have no '$dep' for '$arg_file'!"
|
||||
exec "$spatch" "$@"
|
||||
fi
|
||||
|
||||
if test -n "$debug"
|
||||
then
|
||||
trace_it "$0: The full cache input for '$arg_sp' '$arg_file' '$dep'"
|
||||
hash_for_cache "$arg_sp" "$arg_file" "$dep" >&2
|
||||
fi
|
||||
sum=$(hash_for_cache "$arg_sp" "$arg_file" "$dep" | git hash-object --stdin)
|
||||
|
||||
trace_it "$0: processing '$arg_file' with '$arg_sp' rule, and got hash '$sum' for it + '$dep'"
|
||||
|
||||
getret=
|
||||
if test -z "$get"
|
||||
then
|
||||
if test $(redis-cli SISMEMBER spatch-cache "$sum") = 1
|
||||
then
|
||||
getret=0
|
||||
else
|
||||
getret=1
|
||||
fi
|
||||
else
|
||||
$set "$sum"
|
||||
getret=$?
|
||||
fi
|
||||
|
||||
if test "$getret" = 0
|
||||
then
|
||||
trace_it "$0: HIT for '$arg_file' with '$arg_sp'"
|
||||
exit 0
|
||||
else
|
||||
trace_it "$0: MISS: for '$arg_file' with '$arg_sp'"
|
||||
fi
|
||||
|
||||
out="$(mktemp)"
|
||||
err="$(mktemp)"
|
||||
|
||||
set +e
|
||||
"$spatch" "$@" >"$out" 2>>"$err"
|
||||
ret=$?
|
||||
cat "$out"
|
||||
cat "$err" >&2
|
||||
set -e
|
||||
|
||||
nocache=
|
||||
if test $ret != 0
|
||||
then
|
||||
nocache="exited non-zero: $ret"
|
||||
elif test -s "$out"
|
||||
then
|
||||
nocache="had patch output"
|
||||
elif test -z "$cacheWhenStderr" && test -s "$err"
|
||||
then
|
||||
nocache="had stderr (use --very-quiet or spatchCache.cacheWhenStderr=true?)"
|
||||
fi
|
||||
|
||||
if test -n "$nocache"
|
||||
then
|
||||
trace_it "$0: NOCACHE ($nocache): for '$arg_file' with '$arg_sp'"
|
||||
exit "$ret"
|
||||
fi
|
||||
|
||||
trace_it "$0: SET: for '$arg_file' with '$arg_sp'"
|
||||
|
||||
setret=
|
||||
if test -z "$set"
|
||||
then
|
||||
if test $(redis-cli SADD spatch-cache "$sum") = 1
|
||||
then
|
||||
setret=0
|
||||
else
|
||||
setret=1
|
||||
fi
|
||||
else
|
||||
"$set" "$sum"
|
||||
setret=$?
|
||||
fi
|
||||
|
||||
if test "$setret" != 0
|
||||
then
|
||||
echo "FAILED to set '$sum' in cache!" >&2
|
||||
exit 128
|
||||
fi
|
||||
|
||||
exit "$ret"
|
@ -1,4 +1,4 @@
|
||||
@ strbuf_addf_with_format_only @
|
||||
@@
|
||||
expression E;
|
||||
constant fmt !~ "%";
|
||||
@@
|
||||
|
@ -1,4 +1,4 @@
|
||||
@ swap_with_declaration @
|
||||
@@
|
||||
type T;
|
||||
identifier tmp;
|
||||
T a, b;
|
||||
|
@ -20,7 +20,6 @@ expression E;
|
||||
|
||||
@@
|
||||
expression E;
|
||||
expression F;
|
||||
@@
|
||||
- has_object_file_with_flags(
|
||||
+ repo_has_object_file_with_flags(the_repository,
|
||||
|
@ -60,6 +60,7 @@ ifndef V
|
||||
QUIET_AR = @echo ' ' AR $@;
|
||||
QUIET_LINK = @echo ' ' LINK $@;
|
||||
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
|
||||
QUIET_CP = @echo ' ' CP $< $@;
|
||||
QUIET_LNCP = @echo ' ' LN/CP $@;
|
||||
QUIET_XGETTEXT = @echo ' ' XGETTEXT $@;
|
||||
QUIET_MSGINIT = @echo ' ' MSGINIT $@;
|
||||
@ -69,8 +70,11 @@ ifndef V
|
||||
QUIET_SP = @echo ' ' SP $<;
|
||||
QUIET_HDR = @echo ' ' HDR $(<:hcc=h);
|
||||
QUIET_RC = @echo ' ' RC $@;
|
||||
QUIET_SPATCH = @echo ' ' SPATCH $<;
|
||||
QUIET_SPATCH_T = @echo ' ' SPATCH TEST $(@:.build/%=%);
|
||||
|
||||
## Used in "Makefile": SPATCH
|
||||
QUIET_SPATCH = @echo ' ' SPATCH $< \>$@;
|
||||
QUIET_SPATCH_TEST = @echo ' ' SPATCH TEST $(@:.build/%=%);
|
||||
QUIET_SPATCH_CAT = @echo ' ' SPATCH CAT $(@:%.patch=%.d/)\*\*.patch \>$@;
|
||||
|
||||
## Used in "Documentation/Makefile"
|
||||
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
|
||||
|
Loading…
Reference in New Issue
Block a user