Merge pull request #54372 from thockin/make-genfiles-cleanup

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Overhaul Makefile for generated code

Calculate all go dependencies in a single Go program, rather than a complicated series of `go list` invocations and `Makefile` logic.  This simplifies the
Makefile dramatically.

Also adds tests to ensure the dependencies stay correct.  This test is pretty slow, though.

Also fixes a few anomalies found by the test.

Fixes #54371

```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2018-06-19 18:43:43 -07:00 committed by GitHub
commit 8bc2fb0207
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1103 additions and 557 deletions

View File

@ -124,7 +124,7 @@ ifeq ($(PRINT_HELP),y)
verify: verify:
@echo "$$VERIFY_HELP_INFO" @echo "$$VERIFY_HELP_INFO"
else else
verify: verify_generated_files verify:
KUBE_VERIFY_GIT_BRANCH=$(BRANCH) hack/make-rules/verify.sh KUBE_VERIFY_GIT_BRANCH=$(BRANCH) hack/make-rules/verify.sh
endif endif
@ -139,7 +139,7 @@ ifeq ($(PRINT_HELP),y)
quick-verify: quick-verify:
@echo "$$QUICK_VERIFY_HELP_INFO" @echo "$$QUICK_VERIFY_HELP_INFO"
else else
quick-verify: verify_generated_files quick-verify:
QUICK=true SILENT=false hack/make-rules/verify.sh QUICK=true SILENT=false hack/make-rules/verify.sh
endif endif
@ -483,21 +483,6 @@ generated_files:
$(MAKE) -f Makefile.generated_files $@ CALLED_FROM_MAIN_MAKEFILE=1 $(MAKE) -f Makefile.generated_files $@ CALLED_FROM_MAIN_MAKEFILE=1
endif endif
define VERIFY_GENERATED_FILES_HELP_INFO
# Verify auto-generated files needed for the build.
#
# Example:
# make verify_generated_files
endef
.PHONY: verify_generated_files
ifeq ($(PRINT_HELP),y)
verify_generated_files:
@echo "$$VERIFY_GENERATED_FILES_HELP_INFO"
else
verify_generated_files:
$(MAKE) -f Makefile.generated_files $@ CALLED_FROM_MAIN_MAKEFILE=1
endif
define HELP_INFO define HELP_INFO
# Print make targets and help info # Print make targets and help info
# #

View File

@ -37,81 +37,54 @@ SHELL := /bin/bash
.PHONY: generated_files .PHONY: generated_files
generated_files: gen_deepcopy gen_defaulter gen_conversion gen_openapi gen_bindata generated_files: gen_deepcopy gen_defaulter gen_conversion gen_openapi gen_bindata
.PHONY: verify_generated_files #
verify_generated_files: verify_gen_deepcopy \ # Helper logic to calculate Go's dependency DAG ourselves.
verify_gen_defaulter \ #
verify_gen_conversion
# This is a file that will be emitted by the go2make tool, containing a
# variable for each Go package in the project (including deps) which lists all
# of the transitive deps of that package. Each variable is named the same as
# the package - for example the variable for `k8s.io/kubernetes/pkg/api` is
# $(k8s.io/kubernetes/pkg/api). This is roughly the same DAG that the Go
# compiler uses. These variables can be used to figure out if, for example,
# generated code needs to be regenerated.
GO_PKGDEPS_FILE = go-pkgdeps.mk
# Include the Go package dependencies file. This will cause the rule of
# the same name to be considered and if it is updated, make will restart and
# reload the updated deps.
sinclude $(META_DIR)/$(GO_PKGDEPS_FILE)
# Update the set of Go deps for our project. This will let us determine if
# we really need to do expensive codegen. We use FORCE because it is not a
# PHONY file, but we do want it to be re-evaluated every time make is run. The
# file will only be touched if it actually changes.
$(META_DIR)/$(GO_PKGDEPS_FILE): FORCE
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: calculating Go dependencies"; \
fi
hack/run-in-gopath.sh go install ./hack/make-rules/helpers/go2make
hack/run-in-gopath.sh go2make \
k8s.io/kubernetes/... \
--prune k8s.io/kubernetes/staging \
--prune k8s.io/kubernetes/vendor \
k8s.io/kubernetes/vendor/k8s.io/... \
github.com/jteeuwen/go-bindata/go-bindata/... \
> $@.tmp
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(GO_PKGDEPS_FILE) changed"; \
fi; \
cat $@.tmp > $@; \
fi
rm -f $@.tmp
.PHONY: FORCE
FORCE:
# Code-generation logic.
# #
# This stuff can be pretty tricky, and there's probably some corner cases that # Helper logic to find which directories need codegen as quickly as possible.
# we don't handle well. That said, here's a straightforward test to prove that
# the most common cases work. Sadly, it is manual.
# #
# make clean
# find . -name .make\* | xargs rm -f
# find . -name zz_generated\* | xargs rm -f
# # verify `find . -name zz_generated.deepcopy.go | wc -l` is 0
# # verify `find . -name .make | wc -l` is 0
#
# make nonexistent
# # expect "No rule to make target"
# # verify `find .make/ -type f | wc -l` has many files
#
# make gen_deepcopy
# # expect deepcopy-gen is built exactly once
# # expect many files to be regenerated
# # verify `find . -name zz_generated.deepcopy.go | wc -l` has files
# make gen_deepcopy
# # expect nothing to be rebuilt, finish in O(seconds)
# touch pkg/api/types.go
# make gen_deepcopy
# # expect one file to be regenerated
# make gen_deepcopy
# # expect nothing to be rebuilt, finish in O(seconds)
# touch vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go
# make gen_deepcopy
# # expect deepcopy-gen is built exactly once
# # expect many files to be regenerated
# # verify `find . -name zz_generated.deepcopy.go | wc -l` has files
# make gen_deepcopy
# # expect nothing to be rebuilt, finish in O(seconds)
#
# make gen_conversion
# # expect conversion-gen is built exactly once
# # expect many files to be regenerated
# # verify `find . -name zz_generated.conversion.go | wc -l` has files
# make gen_conversion
# # expect nothing to be rebuilt, finish in O(seconds)
# touch pkg/api/types.go
# make gen_conversion
# # expect one file to be regenerated
# make gen_conversion
# # expect nothing to be rebuilt, finish in O(seconds)
# touch vendor/k8s.io/code-generator/cmd/conversion-gen/main.go
# make gen_conversion
# # expect conversion-gen is built exactly once
# # expect many files to be regenerated
# # verify `find . -name zz_generated.conversion.go | wc -l` has files
# make gen_conversion
# # expect nothing to be rebuilt, finish in O(seconds)
#
# make all
# # expect it to build
#
# make test
# # expect it to pass
#
# make clean
# # verify `find . -name zz_generated.deepcopy.go | wc -l` is 0
# # verify `find . -name .make | wc -l` is 0
#
# make all WHAT=cmd/kube-proxy
# # expect it to build
#
# make clean
# make test WHAT=cmd/kube-proxy
# # expect it to pass
# This variable holds a list of every directory that contains Go files in this # This variable holds a list of every directory that contains Go files in this
# project. Other rules and variables can use this as a starting point to # project. Other rules and variables can use this as a starting point to
@ -123,63 +96,6 @@ ALL_GO_DIRS := $(shell \
hack/make-rules/helpers/cache_go_dirs.sh $(META_DIR)/all_go_dirs.mk \ hack/make-rules/helpers/cache_go_dirs.sh $(META_DIR)/all_go_dirs.mk \
) )
# The name of the metadata file which lists *.go files in each pkg.
GOFILES_META := gofiles.mk
# Establish a dependency between the deps file and the dir. Whenever a dir
# changes (files added or removed) the deps file will be considered stale.
#
# The variable value was set in $(GOFILES_META) and included as part of the
# dependency management logic.
#
# This is looser than we really need (e.g. we don't really care about non *.go
# files or even *_test.go files), but this is much easier to represent.
#
# Because we 'sinclude' the deps file, it is considered for rebuilding, as part
# of make's normal evaluation. If it gets rebuilt, make will restart.
#
# The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse.
$(foreach dir, $(ALL_GO_DIRS), $(eval \
$(META_DIR)/$(dir)/$(GOFILES_META): $(dir) \
))
# How to rebuild a deps file. When make determines that the deps file is stale
# (see above), it executes this rule, and then re-loads the deps file.
#
# This is looser than we really need (e.g. we don't really care about test
# files), but this is MUCH faster than calling `go list`.
#
# We regenerate the output file in order to satisfy make's "newer than" rules,
# but we only need to rebuild targets if the contents actually changed. That
# is what the .stamp file represents.
$(foreach dir, $(ALL_GO_DIRS), \
$(META_DIR)/$(dir)/$(GOFILES_META)):
FILES=$$(ls $</*.go | grep --color=never -v $(GENERATED_FILE_PREFIX)); \
mkdir -p $(@D); \
echo "gofiles__$< := $$(echo $${FILES})" >$@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: gofiles changed for $@"; \
fi; \
touch $@.stamp; \
fi; \
mv $@.tmp $@
# This is required to fill in the DAG, since some cases (e.g. 'make clean all')
# will reference the .stamp file when it doesn't exist. We don't need to
# rebuild it in that case, just keep make happy.
$(foreach dir, $(ALL_GO_DIRS), \
$(META_DIR)/$(dir)/$(GOFILES_META).stamp):
# Include any deps files as additional Makefile rules. This triggers make to
# consider the deps files for rebuild, which makes the whole
# dependency-management logic work. 'sinclude' is "silent include" which does
# not fail if the file does not exist.
$(foreach dir, $(ALL_GO_DIRS), $(eval \
sinclude $(META_DIR)/$(dir)/$(GOFILES_META) \
))
# Generate a list of all files that have a `+k8s:` comment-tag. This will be # Generate a list of all files that have a `+k8s:` comment-tag. This will be
# used to derive lists of files/dirs for generation tools. # used to derive lists of files/dirs for generation tools.
ifeq ($(DBG_MAKEFILE),1) ifeq ($(DBG_MAKEFILE),1)
@ -190,7 +106,12 @@ ALL_K8S_TAG_FILES := $(shell \
| xargs grep --color=never -l '^// *+k8s:' \ | xargs grep --color=never -l '^// *+k8s:' \
) )
# #
# Code generation logic.
#
# Deep-copy generation # Deep-copy generation
# #
# Any package that wants deep-copy functions generated must include a # Any package that wants deep-copy functions generated must include a
@ -220,34 +141,27 @@ DEEPCOPY_DIRS := $(shell \
) )
DEEPCOPY_FILES := $(addsuffix /$(DEEPCOPY_FILENAME), $(DEEPCOPY_DIRS)) DEEPCOPY_FILES := $(addsuffix /$(DEEPCOPY_FILENAME), $(DEEPCOPY_DIRS))
# Shell function for reuse in rules. # Reset the list of packages that need generation.
RUN_GEN_DEEPCOPY = \ $(shell mkdir -p $$(dirname $(META_DIR)/$(DEEPCOPY_GEN)))
function run_gen_deepcopy() { \ $(shell rm -f $(META_DIR)/$(DEEPCOPY_GEN).todo)
if [[ -f $(META_DIR)/$(DEEPCOPY_GEN).todo ]]; then \
pkgs=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | paste -sd, -); \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: running $(DEEPCOPY_GEN) for $$pkgs"; \
fi; \
./hack/run-in-gopath.sh $(DEEPCOPY_GEN) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
--bounding-dirs $(PRJ_SRC_PATH),"k8s.io/api" \
-O $(DEEPCOPY_BASENAME) \
"$$@"; \
fi \
}; \
run_gen_deepcopy
# This rule aggregates the set of files to generate and then generates them all # This rule aggregates the set of files to generate and then generates them all
# in a single run of the tool. # in a single run of the tool.
.PHONY: gen_deepcopy .PHONY: gen_deepcopy
gen_deepcopy: $(DEEPCOPY_FILES) $(DEEPCOPY_GEN) gen_deepcopy: $(DEEPCOPY_GEN) $(META_DIR)/$(DEEPCOPY_GEN).todo
$(RUN_GEN_DEEPCOPY) if [[ -s $(META_DIR)/$(DEEPCOPY_GEN).todo ]]; then \
pkgs=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | paste -sd, -); \
.PHONY: verify_gen_deepcopy if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
verify_gen_deepcopy: $(DEEPCOPY_GEN) echo "DBG: running $(DEEPCOPY_GEN) for $$pkgs"; \
$(RUN_GEN_DEEPCOPY) --verify-only fi; \
./hack/run-in-gopath.sh $(DEEPCOPY_GEN) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
--bounding-dirs $(PRJ_SRC_PATH),"k8s.io/api" \
-O $(DEEPCOPY_BASENAME) \
"$$@"; \
fi \
# For each dir in DEEPCOPY_DIRS, this establishes a dependency between the # For each dir in DEEPCOPY_DIRS, this establishes a dependency between the
# output file and the input files that should trigger a rebuild. # output file and the input files that should trigger a rebuild.
@ -258,71 +172,35 @@ verify_gen_deepcopy: $(DEEPCOPY_GEN)
# #
# The '$(eval)' is needed because this has a different RHS for each LHS, and # The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse. # would otherwise produce results that make can't parse.
# $(foreach dir, $(DEEPCOPY_DIRS), $(eval \
# We depend on the $(GOFILES_META).stamp to detect when the set of input files $(dir)/$(DEEPCOPY_FILENAME): $($(PRJ_SRC_PATH)/$(dir)) \
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(DEEPCOPY_DIRS), $(eval \
$(dir)/$(DEEPCOPY_FILENAME): $(META_DIR)/$(dir)/$(GOFILES_META).stamp \
$(gofiles__$(dir)) \
)) ))
# Unilaterally remove any leftovers from previous runs.
$(shell rm -f $(META_DIR)/$(DEEPCOPY_GEN)*.todo)
# How to regenerate deep-copy code. This is a little slow to run, so we batch # How to regenerate deep-copy code. This is a little slow to run, so we batch
# it up and trigger the batch from the 'generated_files' target. # it up and trigger the batch from the 'generated_files' target.
$(META_DIR)/$(DEEPCOPY_GEN).todo: $(DEEPCOPY_FILES)
$(DEEPCOPY_FILES): $(DEEPCOPY_GEN) $(DEEPCOPY_FILES): $(DEEPCOPY_GEN)
mkdir -p $$(dirname $(META_DIR)/$(DEEPCOPY_GEN))
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \ if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: deepcopy needed $(@D): $?"; \ echo "DBG: deepcopy needed $(@D): $?"; \
ls -lf --full-time $@ $? || true; \ ls -lf --full-time $@ $? || true; \
fi fi
echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEEPCOPY_GEN).todo echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEEPCOPY_GEN).todo
# This calculates the dependencies for the generator tool, so we only rebuild
# it when needed. It is PHONY so that it always runs, but it only updates the
# file if the contents have actually changed. We 'sinclude' this later.
.PHONY: $(META_DIR)/$(DEEPCOPY_GEN).mk
$(META_DIR)/$(DEEPCOPY_GEN).mk:
mkdir -p $(@D); \
(echo -n "$(DEEPCOPY_GEN): "; \
./hack/run-in-gopath.sh go list \
-f '{{.ImportPath}}{{"\n"}}{{range .Deps}}{{.}}{{"\n"}}{{end}}' \
./vendor/k8s.io/code-generator/cmd/deepcopy-gen \
| grep --color=never "^$(PRJ_SRC_PATH)/" \
| xargs ./hack/run-in-gopath.sh go list \
-f '{{$$d := .Dir}}{{$$d}}{{"\n"}}{{range .GoFiles}}{{$$d}}/{{.}}{{"\n"}}{{end}}' \
| paste -sd' ' - \
| sed 's/ / \\=,/g' \
| tr '=,' '\n\t' \
| sed "s|$$(pwd -P)/||"; \
) > $@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(DEEPCOPY_GEN).mk changed"; \
fi; \
cat $@.tmp > $@; \
rm -f $@.tmp; \
fi
# Include dependency info for the generator tool. This will cause the rule of
# the same name to be considered and if it is updated, make will restart.
sinclude $(META_DIR)/$(DEEPCOPY_GEN).mk
# How to build the generator tool. The deps for this are defined in # How to build the generator tool. The deps for this are defined in
# the $(DEEPCOPY_GEN).mk, above. # the $(GO_PKGDEPS_FILE), above.
# #
# A word on the need to touch: This rule might trigger if, for example, a # A word on the need to touch: This rule might trigger if, for example, a
# non-Go file was added or deleted from a directory on which this depends. # non-Go file was added or deleted from a directory on which this depends.
# This target needs to be reconsidered, but Go realizes it doesn't actually # This target needs to be reconsidered, but Go realizes it doesn't actually
# have to be rebuilt. In that case, make will forever see the dependency as # have to be rebuilt. In that case, make will forever see the dependency as
# newer than the binary, and try to rebuild it over and over. So we touch it, # newer than the binary, and try to "rebuild" it over and over. So we touch
# and make is happy. # it, and make is happy.
$(DEEPCOPY_GEN): $(DEEPCOPY_GEN): $(k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/deepcopy-gen)
hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/deepcopy-gen hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/deepcopy-gen
touch $@ touch $@
#
# Defaulter generation # Defaulter generation
# #
# Any package that wants defaulter functions generated must include a # Any package that wants defaulter functions generated must include a
@ -359,134 +237,64 @@ DEFAULTER_DIRS := $(shell \
DEFAULTER_FILES := $(addsuffix /$(DEFAULTER_FILENAME), $(DEFAULTER_DIRS)) DEFAULTER_FILES := $(addsuffix /$(DEFAULTER_FILENAME), $(DEFAULTER_DIRS))
RUN_GEN_DEFAULTER := \ # Reset the list of packages that need generation.
function run_gen_defaulter() { \ $(shell mkdir -p $$(dirname $(META_DIR)/$(DEFAULTER_GEN)))
if [[ -f $(META_DIR)/$(DEFAULTER_GEN).todo ]]; then \ $(shell rm -f $(META_DIR)/$(DEFAULTER_GEN).todo)
pkgs=$$(cat $(META_DIR)/$(DEFAULTER_GEN).todo | paste -sd, -); \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: running $(DEFAULTER_GEN) for $$pkgs"; \
fi; \
./hack/run-in-gopath.sh $(DEFAULTER_GEN) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
--extra-peer-dirs $$(echo $(addprefix $(PRJ_SRC_PATH)/, $(DEFAULTER_DIRS)) | sed 's/ /,/g') \
-O $(DEFAULTER_BASENAME) \
"$$@"; \
fi \
}; \
run_gen_defaulter
# This rule aggregates the set of files to generate and then generates them all # This rule aggregates the set of files to generate and then generates them all
# in a single run of the tool. # in a single run of the tool.
.PHONY: gen_defaulter .PHONY: gen_defaulter
gen_defaulter: $(DEFAULTER_FILES) $(DEFAULTER_GEN) gen_defaulter: $(DEFAULTER_GEN) $(META_DIR)/$(DEFAULTER_GEN).todo
$(RUN_GEN_DEFAULTER) if [[ -s $(META_DIR)/$(DEFAULTER_GEN).todo ]]; then \
pkgs=$$(cat $(META_DIR)/$(DEFAULTER_GEN).todo | paste -sd, -); \
.PHONY: verify_gen_deepcopy if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
verify_gen_defaulter: $(DEFAULTER_GEN) echo "DBG: running $(DEFAULTER_GEN) for $$pkgs"; \
$(RUN_GEN_DEFAULTER) --verify-only fi; \
./hack/run-in-gopath.sh $(DEFAULTER_GEN) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
--extra-peer-dirs $$(echo $(addprefix $(PRJ_SRC_PATH)/, $(DEFAULTER_DIRS)) | sed 's/ /,/g') \
-O $(DEFAULTER_BASENAME) \
"$$@"; \
fi
# For each dir in DEFAULTER_DIRS, this establishes a dependency between the # For each dir in DEFAULTER_DIRS, this establishes a dependency between the
# output file and the input files that should trigger a rebuild. # output file and the input files that should trigger a rebuild.
# #
# The variable value was set in $(GOFILES_META) and included as part of the # Note that this is a deps-only statement, not a full rule (see below for that).
# dependency management logic.
#
# Note that this is a deps-only statement, not a full rule (see below). This
# has to be done in a distinct step because wildcards don't work in static
# pattern rules.
# #
# The '$(eval)' is needed because this has a different RHS for each LHS, and # The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse. # would otherwise produce results that make can't parse.
# $(foreach dir, $(DEFAULTER_DIRS), $(eval \
# We depend on the $(GOFILES_META).stamp to detect when the set of input files $(dir)/$(DEFAULTER_FILENAME): $($(PRJ_SRC_PATH)/$(dir)) \
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(DEFAULTER_DIRS), $(eval \
$(dir)/$(DEFAULTER_FILENAME): $(META_DIR)/$(dir)/$(GOFILES_META).stamp \
$(gofiles__$(dir)) \
)) ))
# For each dir in DEFAULTER_DIRS, for each target in $(defaulters__$(dir)),
# this establishes a dependency between the output file and the input files
# that should trigger a rebuild.
#
# The variable value was set in $(GOFILES_META) and included as part of the
# dependency management logic.
#
# Note that this is a deps-only statement, not a full rule (see below). This
# has to be done in a distinct step because wildcards don't work in static
# pattern rules.
#
# The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse.
#
# We depend on the $(GOFILES_META).stamp to detect when the set of input files
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(DEFAULTER_DIRS), \
$(foreach tgt, $(defaulters__$(dir)), $(eval \
$(dir)/$(DEFAULTER_FILENAME): $(META_DIR)/$(tgt)/$(GOFILES_META).stamp \
$(gofiles__$(tgt)) \
)) \
)
# Unilaterally remove any leftovers from previous runs.
$(shell rm -f $(META_DIR)/$(DEFAULTER_GEN)*.todo)
# How to regenerate defaulter code. This is a little slow to run, so we batch # How to regenerate defaulter code. This is a little slow to run, so we batch
# it up and trigger the batch from the 'generated_files' target. # it up and trigger the batch from the 'generated_files' target.
$(META_DIR)/$(DEFAULTER_GEN).todo: $(DEFAULTER_FILES)
$(DEFAULTER_FILES): $(DEFAULTER_GEN) $(DEFAULTER_FILES): $(DEFAULTER_GEN)
mkdir -p $$(dirname $(META_DIR)/$(DEFAULTER_GEN))
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \ if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: defaulter needed $(@D): $?"; \ echo "DBG: defaulter needed $(@D): $?"; \
ls -lf --full-time $@ $? || true; \ ls -lf --full-time $@ $? || true; \
fi fi
echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEFAULTER_GEN).todo echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEFAULTER_GEN).todo
# This calculates the dependencies for the generator tool, so we only rebuild
# it when needed. It is PHONY so that it always runs, but it only updates the
# file if the contents have actually changed. We 'sinclude' this later.
.PHONY: $(META_DIR)/$(DEFAULTER_GEN).mk
$(META_DIR)/$(DEFAULTER_GEN).mk:
mkdir -p $(@D); \
(echo -n "$(DEFAULTER_GEN): "; \
./hack/run-in-gopath.sh go list \
-f '{{.ImportPath}}{{"\n"}}{{range .Deps}}{{.}}{{"\n"}}{{end}}' \
./vendor/k8s.io/code-generator/cmd/defaulter-gen \
| grep --color=never "^$(PRJ_SRC_PATH)/" \
| xargs ./hack/run-in-gopath.sh go list \
-f '{{$$d := .Dir}}{{$$d}}{{"\n"}}{{range .GoFiles}}{{$$d}}/{{.}}{{"\n"}}{{end}}' \
| paste -sd' ' - \
| sed 's/ / \\=,/g' \
| tr '=,' '\n\t' \
| sed "s|$$(pwd -P)/||"; \
) > $@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(DEFAULTER_GEN).mk changed"; \
fi; \
cat $@.tmp > $@; \
rm -f $@.tmp; \
fi
# Include dependency info for the generator tool. This will cause the rule of
# the same name to be considered and if it is updated, make will restart.
sinclude $(META_DIR)/$(DEFAULTER_GEN).mk
# How to build the generator tool. The deps for this are defined in # How to build the generator tool. The deps for this are defined in
# the $(DEFAULTER_GEN).mk, above. # the $(GO_PKGDEPS_FILE), above.
# #
# A word on the need to touch: This rule might trigger if, for example, a # A word on the need to touch: This rule might trigger if, for example, a
# non-Go file was added or deleted from a directory on which this depends. # non-Go file was added or deleted from a directory on which this depends.
# This target needs to be reconsidered, but Go realizes it doesn't actually # This target needs to be reconsidered, but Go realizes it doesn't actually
# have to be rebuilt. In that case, make will forever see the dependency as # have to be rebuilt. In that case, make will forever see the dependency as
# newer than the binary, and try to rebuild it over and over. So we touch it, # newer than the binary, and try to "rebuild" it over and over. So we touch
# and make is happy. # it, and make is happy.
$(DEFAULTER_GEN): $(DEFAULTER_GEN): $(k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/defaulter-gen)
hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/defaulter-gen hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/defaulter-gen
touch $@ touch $@
#
# Conversion generation # Conversion generation
# #
# Any package that wants conversion functions generated must include one or # Any package that wants conversion functions generated must include one or
@ -526,171 +334,52 @@ CONVERSION_DIRS := $(shell \
CONVERSION_FILES := $(addsuffix /$(CONVERSION_FILENAME), $(CONVERSION_DIRS)) CONVERSION_FILES := $(addsuffix /$(CONVERSION_FILENAME), $(CONVERSION_DIRS))
CONVERSION_EXTRA_PEER_DIRS := k8s.io/kubernetes/pkg/apis/core,k8s.io/kubernetes/pkg/apis/core/v1,k8s.io/api/core/v1 CONVERSION_EXTRA_PEER_DIRS := k8s.io/kubernetes/pkg/apis/core,k8s.io/kubernetes/pkg/apis/core/v1,k8s.io/api/core/v1
# Shell function for reuse in rules. # Reset the list of packages that need generation.
RUN_GEN_CONVERSION = \ $(shell mkdir -p $$(dirname $(META_DIR)/$(CONVERSION_GEN)))
function run_gen_conversion() { \ $(shell rm -f $(META_DIR)/$(CONVERSION_GEN).todo)
if [[ -f $(META_DIR)/$(CONVERSION_GEN).todo ]]; then \
pkgs=$$(cat $(META_DIR)/$(CONVERSION_GEN).todo | paste -sd, -); \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: running $(CONVERSION_GEN) for $$pkgs"; \
fi; \
./hack/run-in-gopath.sh $(CONVERSION_GEN) \
--extra-peer-dirs $(CONVERSION_EXTRA_PEER_DIRS) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
-O $(CONVERSION_BASENAME) \
"$$@"; \
fi \
}; \
run_gen_conversion
# This rule aggregates the set of files to generate and then generates them all # This rule aggregates the set of files to generate and then generates them all
# in a single run of the tool. # in a single run of the tool.
.PHONY: gen_conversion .PHONY: gen_conversion
gen_conversion: $(CONVERSION_FILES) $(CONVERSION_GEN) gen_conversion: $(CONVERSION_GEN) $(META_DIR)/$(CONVERSION_GEN).todo
$(RUN_GEN_CONVERSION) if [[ -s $(META_DIR)/$(CONVERSION_GEN).todo ]]; then \
pkgs=$$(cat $(META_DIR)/$(CONVERSION_GEN).todo | paste -sd, -); \
.PHONY: verify_gen_conversion if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
verify_gen_conversion: $(CONVERSION_GEN) echo "DBG: running $(CONVERSION_GEN) for $$pkgs"; \
$(RUN_GEN_CONVERSION) --verify-only fi; \
./hack/run-in-gopath.sh $(CONVERSION_GEN) \
# Establish a dependency between the deps file and the dir. Whenever a dir --extra-peer-dirs $(CONVERSION_EXTRA_PEER_DIRS) \
# changes (files added or removed) the deps file will be considered stale. --v $(KUBE_VERBOSE) \
# --logtostderr \
# This is looser than we really need (e.g. we don't really care about non *.go -i "$$pkgs" \
# files or even *_test.go files), but this is much easier to represent. -O $(CONVERSION_BASENAME) \
# "$$@"; \
# Because we 'sinclude' the deps file, it is considered for rebuilding, as part fi
# of make's normal evaluation. If it gets rebuilt, make will restart.
#
# The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse.
$(foreach dir, $(CONVERSION_DIRS), $(eval \
$(META_DIR)/$(dir)/$(CONVERSIONS_META): $(dir) \
))
# How to rebuild a deps file. When make determines that the deps file is stale
# (see above), it executes this rule, and then re-loads the deps file.
#
# This is looser than we really need (e.g. we don't really care about test
# files), but this is MUCH faster than calling `go list`.
#
# We regenerate the output file in order to satisfy make's "newer than" rules,
# but we only need to rebuild targets if the contents actually changed. That
# is what the .stamp file represents.
$(foreach dir, $(CONVERSION_DIRS), \
$(META_DIR)/$(dir)/$(CONVERSIONS_META)):
TAGS=$$(grep --color=never -h '^// *+k8s:conversion-gen=' $</*.go \
| cut -f2- -d= \
| sed 's|$(PRJ_SRC_PATH)/||' \
| sed 's|^k8s.io/|vendor/k8s.io/|'); \
mkdir -p $(@D); \
echo "conversions__$< := $$(echo $${TAGS})" >$@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: conversions changed for $@"; \
fi; \
touch $@.stamp; \
fi; \
mv $@.tmp $@
# Include any deps files as additional Makefile rules. This triggers make to
# consider the deps files for rebuild, which makes the whole
# dependency-management logic work. 'sinclude' is "silent include" which does
# not fail if the file does not exist.
$(foreach dir, $(CONVERSION_DIRS), $(eval \
sinclude $(META_DIR)/$(dir)/$(CONVERSIONS_META) \
))
# For each dir in CONVERSION_DIRS, this establishes a dependency between the # For each dir in CONVERSION_DIRS, this establishes a dependency between the
# output file and the input files that should trigger a rebuild. # output file and the input files that should trigger a rebuild.
# #
# The variable value was set in $(GOFILES_META) and included as part of the # Note that this is a deps-only statement, not a full rule (see below for that).
# dependency management logic.
#
# Note that this is a deps-only statement, not a full rule (see below). This
# has to be done in a distinct step because wildcards don't work in static
# pattern rules.
# #
# The '$(eval)' is needed because this has a different RHS for each LHS, and # The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse. # would otherwise produce results that make can't parse.
# $(foreach dir, $(CONVERSION_DIRS), $(eval \
# We depend on the $(GOFILES_META).stamp to detect when the set of input files $(dir)/$(CONVERSION_FILENAME): $($(PRJ_SRC_PATH)/$(dir)) \
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(CONVERSION_DIRS), $(eval \
$(dir)/$(CONVERSION_FILENAME): $(META_DIR)/$(dir)/$(GOFILES_META).stamp \
$(gofiles__$(dir)) \
)) ))
# For each dir in CONVERSION_DIRS, for each target in $(conversions__$(dir)),
# this establishes a dependency between the output file and the input files
# that should trigger a rebuild.
#
# The variable value was set in $(GOFILES_META) and included as part of the
# dependency management logic.
#
# Note that this is a deps-only statement, not a full rule (see below). This
# has to be done in a distinct step because wildcards don't work in static
# pattern rules.
#
# The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse.
#
# We depend on the $(GOFILES_META).stamp to detect when the set of input files
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(CONVERSION_DIRS), \
$(foreach tgt, $(conversions__$(dir)), $(eval \
$(dir)/$(CONVERSION_FILENAME): $(META_DIR)/$(tgt)/$(GOFILES_META).stamp \
$(gofiles__$(tgt)) \
)) \
)
# Unilaterally remove any leftovers from previous runs.
$(shell rm -f $(META_DIR)/$(CONVERSION_GEN)*.todo)
# How to regenerate conversion code. This is a little slow to run, so we batch # How to regenerate conversion code. This is a little slow to run, so we batch
# it up and trigger the batch from the 'generated_files' target. # it up and trigger the batch from the 'generated_files' target.
$(META_DIR)/$(CONVERSION_GEN).todo: $(CONVERSION_FILES)
$(CONVERSION_FILES): $(CONVERSION_GEN) $(CONVERSION_FILES): $(CONVERSION_GEN)
mkdir -p $$(dirname $(META_DIR)/$(CONVERSION_GEN))
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \ if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: conversion needed $(@D): $?"; \ echo "DBG: conversion needed $(@D): $?"; \
ls -lf --full-time $@ $? || true; \ ls -lf --full-time $@ $? || true; \
fi fi
echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(CONVERSION_GEN).todo echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(CONVERSION_GEN).todo
# This calculates the dependencies for the generator tool, so we only rebuild
# it when needed. It is PHONY so that it always runs, but it only updates the
# file if the contents have actually changed. We 'sinclude' this later.
.PHONY: $(META_DIR)/$(CONVERSION_GEN).mk
$(META_DIR)/$(CONVERSION_GEN).mk:
mkdir -p $(@D); \
(echo -n "$(CONVERSION_GEN): "; \
./hack/run-in-gopath.sh go list \
-f '{{.ImportPath}}{{"\n"}}{{range .Deps}}{{.}}{{"\n"}}{{end}}' \
./vendor/k8s.io/code-generator/cmd/conversion-gen \
| grep --color=never "^$(PRJ_SRC_PATH)/" \
| xargs ./hack/run-in-gopath.sh go list \
-f '{{$$d := .Dir}}{{$$d}}{{"\n"}}{{range .GoFiles}}{{$$d}}/{{.}}{{"\n"}}{{end}}' \
| paste -sd' ' - \
| sed 's/ / \\=,/g' \
| tr '=,' '\n\t' \
| sed "s|$$(pwd -P)/||"; \
) > $@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(CONVERSION_GEN).mk changed"; \
fi; \
cat $@.tmp > $@; \
rm -f $@.tmp; \
fi
# Include dependency info for the generator tool. This will cause the rule of
# the same name to be considered and if it is updated, make will restart.
sinclude $(META_DIR)/$(CONVERSION_GEN).mk
# How to build the generator tool. The deps for this are defined in # How to build the generator tool. The deps for this are defined in
# the $(CONVERSION_GEN).mk, above. # the $(GO_PKGDEPS_FILE), above.
# #
# A word on the need to touch: This rule might trigger if, for example, a # A word on the need to touch: This rule might trigger if, for example, a
# non-Go file was added or deleted from a directory on which this depends. # non-Go file was added or deleted from a directory on which this depends.
@ -698,12 +387,12 @@ sinclude $(META_DIR)/$(CONVERSION_GEN).mk
# have to be rebuilt. In that case, make will forever see the dependency as # have to be rebuilt. In that case, make will forever see the dependency as
# newer than the binary, and try to rebuild it over and over. So we touch it, # newer than the binary, and try to rebuild it over and over. So we touch it,
# and make is happy. # and make is happy.
$(CONVERSION_GEN): $(CONVERSION_GEN): $(k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/conversion-gen)
hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/conversion-gen hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/conversion-gen
touch $@ touch $@
#
# Open-api generation # OpenAPI generation
# #
# Any package that wants open-api functions generated must include a # Any package that wants open-api functions generated must include a
# comment-tag in column 0 of one file of the form: # comment-tag in column 0 of one file of the form:
@ -736,77 +425,38 @@ gen_openapi: $(OPENAPI_OUTFILE) $(OPENAPI_GEN)
# For each dir in OPENAPI_DIRS, this establishes a dependency between the # For each dir in OPENAPI_DIRS, this establishes a dependency between the
# output file and the input files that should trigger a rebuild. # output file and the input files that should trigger a rebuild.
# #
# Note that this is a deps-only statement, not a full rule (see below). This # Note that this is a deps-only statement, not a full rule (see below for that).
# has to be done in a distinct step because wildcards don't work in static
# pattern rules.
# #
# The '$(eval)' is needed because this has a different RHS for each LHS, and # The '$(eval)' is needed because this has a different RHS for each LHS, and
# would otherwise produce results that make can't parse. # would otherwise produce results that make can't parse.
# $(foreach dir, $(OPENAPI_DIRS), $(eval \
# We depend on the $(GOFILES_META).stamp to detect when the set of input files $(OPENAPI_OUTFILE): $($(PRJ_SRC_PATH)/$(dir)) \
# has changed. This allows us to detect deleted input files.
$(foreach dir, $(OPENAPI_DIRS), $(eval \
$(OPENAPI_OUTFILE): $(META_DIR)/$(dir)/$(GOFILES_META).stamp \
$(gofiles__$(dir)) \
)) ))
# How to regenerate open-api code. This emits a single file for all results. # How to regenerate open-api code. This emits a single file for all results.
$(OPENAPI_OUTFILE): $(OPENAPI_GEN) $(OPENAPI_GEN) $(OPENAPI_OUTFILE): $(OPENAPI_GEN)
function run_gen_openapi() { \ ./hack/run-in-gopath.sh $(OPENAPI_GEN) \
./hack/run-in-gopath.sh $(OPENAPI_GEN) \ --v $(KUBE_VERBOSE) \
--v $(KUBE_VERBOSE) \ --logtostderr \
--logtostderr \ -i $$(echo $(addprefix $(PRJ_SRC_PATH)/, $(OPENAPI_DIRS)) | sed 's/ /,/g') \
-i $$(echo $(addprefix $(PRJ_SRC_PATH)/, $(OPENAPI_DIRS)) | sed 's/ /,/g') \ -p $(PRJ_SRC_PATH)/$(OPENAPI_OUTPUT_PKG) \
-p $(PRJ_SRC_PATH)/$(OPENAPI_OUTPUT_PKG) \ -O $(OPENAPI_BASENAME) \
-O $(OPENAPI_BASENAME) \ "$$@"
"$$@"; \
}; \
run_gen_openapi
# This calculates the dependencies for the generator tool, so we only rebuild
# it when needed. It is PHONY so that it always runs, but it only updates the
# file if the contents have actually changed. We 'sinclude' this later.
.PHONY: $(META_DIR)/$(OPENAPI_GEN).mk
$(META_DIR)/$(OPENAPI_GEN).mk:
mkdir -p $(@D); \
(echo -n "$(OPENAPI_GEN): "; \
./hack/run-in-gopath.sh go list \
-f '{{.ImportPath}}{{"\n"}}{{range .Deps}}{{.}}{{"\n"}}{{end}}' \
./vendor/k8s.io/code-generator/cmd/openapi-gen \
| grep --color=never "^$(PRJ_SRC_PATH)/" \
| xargs ./hack/run-in-gopath.sh go list \
-f '{{$$d := .Dir}}{{$$d}}{{"\n"}}{{range .GoFiles}}{{$$d}}/{{.}}{{"\n"}}{{end}}' \
| paste -sd' ' - \
| sed 's/ / \\=,/g' \
| tr '=,' '\n\t' \
| sed "s|$$(pwd -P)/||"; \
) > $@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(OPENAPI_GEN).mk changed"; \
fi; \
cat $@.tmp > $@; \
rm -f $@.tmp; \
fi
# Include dependency info for the generator tool. This will cause the rule of
# the same name to be considered and if it is updated, make will restart.
sinclude $(META_DIR)/$(OPENAPI_GEN).mk
# How to build the generator tool. The deps for this are defined in # How to build the generator tool. The deps for this are defined in
# the $(OPENAPI_GEN).mk, above. # the $(GO_PKGDEPS_FILE), above.
# #
# A word on the need to touch: This rule might trigger if, for example, a # A word on the need to touch: This rule might trigger if, for example, a
# non-Go file was added or deleted from a directory on which this depends. # non-Go file was added or deleted from a directory on which this depends.
# This target needs to be reconsidered, but Go realizes it doesn't actually # This target needs to be reconsidered, but Go realizes it doesn't actually
# have to be rebuilt. In that case, make will forever see the dependency as # have to be rebuilt. In that case, make will forever see the dependency as
# newer than the binary, and try to rebuild it over and over. So we touch it, # newer than the binary, and try to "rebuild" it over and over. So we touch
# and make is happy. # it, and make is happy.
$(OPENAPI_GEN): $(OPENAPI_GEN): $(k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/openapi-gen)
hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/openapi-gen hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/openapi-gen
touch $@ touch $@
#
# bindata generation # bindata generation
# #
@ -822,38 +472,6 @@ BINDATA_SCRIPT := hack/generate-bindata.sh
gen_bindata: $(BINDATA_GEN) FORCE gen_bindata: $(BINDATA_GEN) FORCE
./hack/run-in-gopath.sh $(BINDATA_SCRIPT) ./hack/run-in-gopath.sh $(BINDATA_SCRIPT)
FORCE:
# This calculates the dependencies for the generator tool, so we only rebuild
# it when needed. It is PHONY so that it always runs, but it only updates the
# file if the contents have actually changed. We 'sinclude' this later.
.PHONY: $(META_DIR)/$(BINDATA_GEN).mk
$(META_DIR)/$(BINDATA_GEN).mk:
mkdir -p $(@D); \
(echo -n "$(BINDATA_GEN): "; \
./hack/run-in-gopath.sh go list \
-f '{{.ImportPath}}{{"\n"}}{{range .Deps}}{{.}}{{"\n"}}{{end}}' \
./vendor/github.com/jteeuwen/go-bindata/go-bindata \
| grep --color=never "^$(PRJ_SRC_PATH)/" \
| xargs ./hack/run-in-gopath.sh go list \
-f '{{$$d := .Dir}}{{$$d}}{{"\n"}}{{range .GoFiles}}{{$$d}}/{{.}}{{"\n"}}{{end}}' \
| paste -sd' ' - \
| sed 's/ / \\=,/g' \
| tr '=,' '\n\t' \
| sed "s|$$(pwd -P)/||"; \
) > $@.tmp; \
if ! cmp -s $@.tmp $@; then \
if [[ "$(DBG_CODEGEN)" == 1 ]]; then \
echo "DBG: $(BINDATA_GEN).mk changed"; \
fi; \
cat $@.tmp > $@; \
rm -f $@.tmp; \
fi
# Include dependency info for the generator tool. This will cause the rule of
# the same name to be considered and if it is updated, make will restart.
sinclude $(META_DIR)/$(BINDATA_GEN).mk
# How to build the generator tool. The deps for this are defined in # How to build the generator tool. The deps for this are defined in
# the $(BINDATA_GEN).mk, above. # the $(BINDATA_GEN).mk, above.
# #
@ -863,6 +481,6 @@ sinclude $(META_DIR)/$(BINDATA_GEN).mk
# have to be rebuilt. In that case, make will forever see the dependency as # have to be rebuilt. In that case, make will forever see the dependency as
# newer than the binary, and try to rebuild it over and over. So we touch it, # newer than the binary, and try to rebuild it over and over. So we touch it,
# and make is happy. # and make is happy.
$(BINDATA_GEN): $(BINDATA_GEN): $(k8s.io/kubernetes/vendor/github.com/jteeuwen/go-bindata/go-bindata)
hack/make-rules/build.sh ./vendor/github.com/jteeuwen/go-bindata/go-bindata hack/make-rules/build.sh ./vendor/github.com/jteeuwen/go-bindata/go-bindata
touch $@ touch $@

View File

@ -106,7 +106,10 @@ filegroup(
filegroup( filegroup(
name = "all-srcs", name = "all-srcs",
srcs = [":package-srcs"], srcs = [
":package-srcs",
"//hack/make-rules/helpers/go2make:all-srcs",
],
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )

View File

@ -36,22 +36,23 @@ trap "rm -f '${CACHE}'" HUP INT TERM ERR
# Example: # Example:
# kfind -type f -name foobar.go # kfind -type f -name foobar.go
function kfind() { function kfind() {
# include the "special" vendor directories which are actually part # We want to include the "special" vendor directories which are actually
# of the Kubernetes source tree - generators will use these for # part of the Kubernetes source tree (./staging/*) but we need them to be
# including certain core API concepts. # named as their ./vendor/* equivalents. Also, we do not want all of
find -H . ./vendor/k8s.io/apimachinery ./vendor/k8s.io/apiserver ./vendor/k8s.io/kube-aggregator ./vendor/k8s.io/apiextensions-apiserver ./vendor/k8s.io/metrics ./vendor/k8s.io/sample-apiserver ./vendor/k8s.io/api ./vendor/k8s.io/client-go ./vendor/k8s.io/code-generator ./vendor/k8s.io/sample-controller \ # ./vendor or even all of ./vendor/k8s.io.
find -H . \
\( \ \( \
-not \( \ -not \( \
\( \ \( \
-path ./vendor -o \ -path ./vendor -o \
-path ./staging -o \
-path ./_\* -o \ -path ./_\* -o \
-path ./.\* -o \ -path ./.\* -o \
-path ./docs \ -path ./docs \
\) -prune \ \) -prune \
\) \ \) \
\) \ \) \
"$@" "$@" \
| sed 's|^./staging/src|vendor|'
} }
NEED_FIND=true NEED_FIND=true

View File

@ -0,0 +1,41 @@
# gazelle:exclude testdata
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"go2make.go",
"pkgwalk.go",
],
importpath = "k8s.io/kubernetes/hack/make-rules/helpers/go2make",
visibility = ["//visibility:private"],
deps = ["//vendor/github.com/spf13/pflag:go_default_library"],
)
go_binary(
name = "go2make",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["pkgwalk_test.go"],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,215 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
goflag "flag"
"fmt"
"go/build"
"io"
"os"
"sort"
"strings"
"github.com/spf13/pflag"
)
var flPrune = pflag.StringSlice("prune", nil, "sub-packages to prune (recursive, may be specified multiple times)")
var flDebug = pflag.BoolP("debug", "d", false, "enable debugging output")
var flHelp = pflag.BoolP("help", "h", false, "print help and exit")
func main() {
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
pflag.Usage = func() { help(os.Stderr) }
pflag.Parse()
debug("PWD", getwd())
build.Default.BuildTags = []string{"ignore_autogenerated"}
build.Default.UseAllFiles = false
if *flHelp {
help(os.Stdout)
os.Exit(0)
}
if len(pflag.Args()) == 0 {
help(os.Stderr)
os.Exit(1)
}
for _, in := range pflag.Args() {
if strings.HasSuffix(in, "/...") {
// Recurse.
debug("starting", in)
pkgName := strings.TrimSuffix(in, "/...")
if err := WalkPkg(pkgName, visitPkg); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} else {
// Import one package.
if err := saveImport(in); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
}
}
}
func help(out io.Writer) {
fmt.Fprintf(out, "Usage: %s [FLAG...] <PKG...>\n", os.Args[0])
fmt.Fprintf(out, "\n")
fmt.Fprintf(out, "go2make calculates all of the dependencies of a set of Go packages and prints\n")
fmt.Fprintf(out, "them as variable definitions suitable for use as a Makefile.\n")
fmt.Fprintf(out, "\n")
fmt.Fprintf(out, "Package specifications may be simple (e.g. 'example.com/txt/color') or\n")
fmt.Fprintf(out, "recursive (e.g. 'example.com/txt/...')\n")
fmt.Fprintf(out, " Example:\n")
fmt.Fprintf(out, " $ %s ./example.com/pretty\n", os.Args[0])
fmt.Fprintf(out, " example.com/txt/split := \\\n")
fmt.Fprintf(out, " /go/src/example.com/txt/split/ \\\n")
fmt.Fprintf(out, " /go/src/example.com/txt/split/split.go \\\n")
fmt.Fprintf(out, " ./example.com/pretty := \\\n")
fmt.Fprintf(out, " /go/src/example.com/pretty/ \\\n")
fmt.Fprintf(out, " /go/src/example.com/pretty/print.go \\\n")
fmt.Fprintf(out, " /go/src/example.com/txt/split/ \\\n")
fmt.Fprintf(out, " /go/src/example.com/txt/split/split.go\n")
fmt.Fprintf(out, "\n")
fmt.Fprintf(out, " Flags:\n")
pflag.PrintDefaults()
}
func debug(items ...interface{}) {
if *flDebug {
x := []interface{}{"DBG:"}
x = append(x, items...)
fmt.Println(x...)
}
}
func visitPkg(importPath, absPath string) error {
debug("visit", importPath)
return saveImport(importPath)
}
func prune(pkgName string) bool {
for _, pr := range *flPrune {
if pr == pkgName {
return true
}
}
return false
}
// cache keeps track of which packages we have already loaded.
var cache = map[string]*build.Package{}
func saveImport(pkgName string) error {
if cache[pkgName] != nil {
return nil
}
if prune(pkgName) {
debug("prune", pkgName)
return ErrSkipPkg
}
pkg, err := loadPackage(pkgName)
if err != nil {
return err
}
debug("save", pkgName)
cache[pkgName] = pkg
debug("recurse", pkgName)
defer func() { debug("done ", pkgName) }()
if !pkg.Goroot && (len(pkg.GoFiles)+len(pkg.Imports) > 0) {
// Process deps of this package before the package itself.
for _, impName := range pkg.Imports {
if impName == "C" {
continue
}
debug("depends on", impName)
saveImport(impName)
}
// Emit a variable for each package.
var buf bytes.Buffer
buf.WriteString(pkgName)
buf.WriteString(" := ")
// Packages depend on their own directories, their own files, and
// transitive list of all deps' directories and files.
all := map[string]struct{}{}
all[pkg.Dir+"/"] = struct{}{}
filesForPkg(pkg, all)
for _, imp := range pkg.Imports {
pkg := cache[imp]
if pkg == nil || pkg.Goroot {
continue
}
all[pkg.Dir+"/"] = struct{}{}
filesForPkg(pkg, all)
}
// Sort and de-dup them.
files := flatten(all)
for _, f := range files {
buf.WriteString(" \\\n ")
buf.WriteString(f)
}
fmt.Println(buf.String())
}
return nil
}
func filesForPkg(pkg *build.Package, all map[string]struct{}) {
for _, file := range pkg.GoFiles {
if pkg.Dir != "." {
file = pkg.Dir + "/" + file
}
all[file] = struct{}{}
}
}
func flatten(all map[string]struct{}) []string {
list := make([]string, 0, len(all))
for k := range all {
list = append(list, k)
}
sort.Strings(list)
return list
}
func loadPackage(pkgName string) (*build.Package, error) {
debug("load", pkgName)
pkg, err := build.Import(pkgName, getwd(), 0)
if err != nil {
// We can ignore NoGoError. Anything else is real.
if _, ok := err.(*build.NoGoError); !ok {
return nil, err
}
}
return pkg, nil
}
func getwd() string {
pwd, err := os.Getwd()
if err != nil {
panic(fmt.Sprintf("can't get working directory: %v", err))
}
return pwd
}

View File

@ -0,0 +1,117 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"go/build"
"os"
"path"
"sort"
)
// VisitFunc is a function called by WalkPkg to examine a single package.
type VisitFunc func(importPath string, absPath string) error
// ErrSkipPkg can be returned by a VisitFunc to indicate that the package in
// question should not be walked any further.
var ErrSkipPkg = fmt.Errorf("package skipped")
// WalkPkg recursively visits all packages under pkgName. This is similar
// to filepath.Walk, except that it follows symlinks. A package is always
// visited before the children of that package. If visit returns ErrSkipPkg,
// pkgName will not be walked.
func WalkPkg(pkgName string, visit VisitFunc) error {
// Visit the package itself.
pkg, err := findPackage(pkgName)
if err != nil {
return err
}
if err := visit(pkg.ImportPath, pkg.Dir); err == ErrSkipPkg {
return nil
} else if err != nil {
return err
}
// Read all of the child dirents and find sub-packages.
infos, err := readDirInfos(pkg.Dir)
if err != nil {
return err
}
for _, info := range infos {
if !info.IsDir() {
continue
}
name := info.Name()
if name[0] == '_' || (len(name) > 1 && name[0] == '.') || name == "testdata" {
continue
}
// Don't use path.Join() because it drops leading `./` via path.Clean().
err := WalkPkg(pkgName+"/"+name, visit)
if err != nil {
return err
}
}
return nil
}
// findPackage finds a Go package.
func findPackage(pkgName string) (*build.Package, error) {
debug("find", pkgName)
pkg, err := build.Import(pkgName, getwd(), build.FindOnly)
if err != nil {
return nil, err
}
return pkg, nil
}
// readDirInfos returns a list of os.FileInfo structures for the dirents under
// dirPath. The result list is sorted by name. This is very similar to
// ioutil.ReadDir, except that it follows symlinks.
func readDirInfos(dirPath string) ([]os.FileInfo, error) {
names, err := readDirNames(dirPath)
if err != nil {
return nil, err
}
sort.Strings(names)
infos := make([]os.FileInfo, 0, len(names))
for _, n := range names {
info, err := os.Stat(path.Join(dirPath, n))
if err != nil {
return nil, err
}
infos = append(infos, info)
}
return infos, nil
}
// readDirNames returns a list of all dirents in dirPath. The result list is
// not sorted or filtered.
func readDirNames(dirPath string) ([]string, error) {
d, err := os.Open(dirPath)
if err != nil {
return nil, err
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
return nil, err
}
return names, nil
}

View File

@ -0,0 +1,222 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"path"
"reflect"
"sort"
"testing"
)
func Test_WalkPkg(t *testing.T) {
testCases := []struct {
pkg string
fail bool
expected []string
}{
{
pkg: "./testdata/nonexistent-dir",
fail: true,
},
{
pkg: "./testdata/dir-without-gofiles",
expected: []string{"./testdata/dir-without-gofiles"},
},
{
pkg: "./testdata/dir-with-gofiles",
expected: []string{"./testdata/dir-with-gofiles", "./testdata/dir-with-gofiles/subdir"},
},
}
for i, tc := range testCases {
visited := []string{}
err := WalkPkg(tc.pkg, func(imp, abs string) error {
if _, base := path.Split(imp); base == "skipme" {
return ErrSkipPkg
}
visited = append(visited, imp)
return nil
})
if err != nil && tc.fail {
continue
}
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
if tc.fail {
t.Errorf("[%d] expected error", i)
continue
}
if !reflect.DeepEqual(visited, tc.expected) {
t.Errorf("[%d] unexpected results: %v", i, visited)
}
}
}
func Test_findPackage(t *testing.T) {
testCases := []struct {
pkg string
fail bool
}{
{
pkg: "./testdata/nonexistent-dir",
fail: true,
},
{
pkg: "./testdata/dir-without-gofiles",
},
{
pkg: "./testdata/dir-with-gofiles",
},
}
for i, tc := range testCases {
_, err := findPackage(tc.pkg)
if err != nil && tc.fail {
continue
}
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
if tc.fail {
t.Errorf("[%d] expected error", i)
continue
}
}
}
func Test_readDirInfos(t *testing.T) {
testCases := []struct {
dir string
fail bool
expected map[string]bool
}{
{
dir: "./testdata/nonexistent-dir",
fail: true,
},
{
dir: "./testdata/dir-without-gofiles",
expected: map[string]bool{"README": true},
},
{
dir: "./testdata/dir-with-gofiles",
expected: map[string]bool{
"README": true,
"foo.go": true,
"bar.go": true,
"subdir": true,
"testdata": true,
"_underscore": true,
".dot": true,
"skipme": true,
},
},
}
for i, tc := range testCases {
infos, err := readDirInfos(tc.dir)
if err != nil && tc.fail {
continue
}
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
if tc.fail {
t.Errorf("[%d] expected error", i)
continue
}
result := make([]string, len(infos))
sorted := make([]string, len(infos))
for i, inf := range infos {
result[i] = inf.Name()
sorted[i] = inf.Name()
}
sort.Strings(sorted)
if !reflect.DeepEqual(result, sorted) {
t.Errorf("[%d] result was not sorted: %v", i, result)
}
for _, r := range result {
if !tc.expected[r] {
t.Errorf("[%d] got unexpected result: %s", i, r)
} else {
delete(tc.expected, r)
}
}
for r := range tc.expected {
t.Errorf("[%d] missing expected result: %s", i, r)
}
}
}
func Test_readDirNames(t *testing.T) {
testCases := []struct {
dir string
fail bool
expected map[string]bool
}{
{
dir: "./testdata/nonexistent-dir",
fail: true,
},
{
dir: "./testdata/dir-without-gofiles",
expected: map[string]bool{"README": true},
},
{
dir: "./testdata/dir-with-gofiles",
expected: map[string]bool{
"README": true,
"foo.go": true,
"bar.go": true,
"subdir": true,
"testdata": true,
"_underscore": true,
".dot": true,
"skipme": true,
},
},
}
for i, tc := range testCases {
result, err := readDirNames(tc.dir)
if err != nil && tc.fail {
continue
}
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
if tc.fail {
t.Errorf("[%d] expected error", i)
continue
}
for _, r := range result {
if !tc.expected[r] {
t.Errorf("[%d] got unexpected result: %s", i, r)
} else {
delete(tc.expected, r)
}
}
for r := range tc.expected {
t.Errorf("[%d] missing expected result: %s", i, r)
}
}
}

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1,20 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gofiles
func bar() {
}

View File

@ -0,0 +1,20 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gofiles
func foo() {
}

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

View File

@ -0,0 +1 @@
README

303
hack/verify-generated-files-remake.sh Normal file → Executable file
View File

@ -21,10 +21,303 @@ set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh" source "${KUBE_ROOT}/hack/lib/init.sh"
make generated_files # $1 = filename pattern as in "zz_generated.$1.go"
X=$(make generated_files DBG_CODEGEN=1) function find_genfiles() {
if [[ -n "${X}" ]]; then find . \
echo "Back-to-back 'make' runs are not clean for codegen" \( \
echo "${X}" -not \( \
\( \
-path ./_\* -o \
-path ./.\* \
\) -prune \
\) \
\) -name "zz_generated.$1.go"
}
# $1 = filename pattern as in "zz_generated.$1.go"
# $2 timestamp file
function newer() {
find_genfiles "$1" | while read F; do
if [[ "${F}" -nt "$2" ]]; then
echo "${F}"
fi
done
}
# $1 = filename pattern as in "zz_generated.$1.go"
# $2 timestamp file
function older() {
find_genfiles "$1" | while read F; do
if [[ "$2" -nt "${F}" ]]; then
echo "${F}"
fi
done
}
function assert_clean() {
make generated_files >/dev/null
touch "${STAMP}"
make generated_files >/dev/null
X=($(newer deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated files changed on back-to-back 'make' runs:"
echo " ${X[@]:-(none)}"
return 1
fi
true
}
STAMP=/tmp/stamp.$RANDOM
#
# Test when we touch a file in a package that needs codegen.
#
assert_clean
DIR=staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1
touch "$DIR/types.go"
touch "${STAMP}"
make generated_files >/dev/null
X=($(newer deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 1 || ! ( "${X[0]}" =~ "${DIR}/zz_generated.deepcopy.go" ) ]]; then
echo "Wrong generated deepcopy files changed after touching src file:"
echo " ${X[@]:-(none)}"
exit 1
fi
X=($(newer defaults "${STAMP}"))
if [[ "${#X[*]}" != 1 || ! ( "${X[0]}" =~ "${DIR}/zz_generated.defaults.go" ) ]]; then
echo "Wrong generated defaults files changed after touching src file:"
echo " ${X[@]:-(none)}"
exit 1
fi
X=($(newer conversion "${STAMP}"))
if [[ "${#X[*]}" != 1 || ! ( "${X[0]}" =~ "${DIR}/zz_generated.conversion.go" ) ]]; then
echo "Wrong generated conversion files changed after touching src file:"
echo " ${X[@]:-(none)}"
exit 1
fi
#
# Test when the codegen tool itself changes: deepcopy
#
assert_clean
touch staging/src/k8s.io/code-generator/cmd/deepcopy-gen/main.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated deepcopy files did not change after touching code-generator file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch staging/src/k8s.io/code-generator/cmd/deepcopy-gen/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated deepcopy files did not change after touching code-generator dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated deepcopy files did not change after touching code-generator dep file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/gengo/examples/deepcopy-gen/generators/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older deepcopy "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated deepcopy files did not change after touching code-generator dep dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
#
# Test when the codegen tool itself changes: defaults
#
assert_clean
touch staging/src/k8s.io/code-generator/cmd/defaulter-gen/main.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older defaults "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated defaults files did not change after touching code-generator file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch staging/src/k8s.io/code-generator/cmd/defaulter-gen/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older defaults "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated defaults files did not change after touching code-generator dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older defaults "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated defaults files did not change after touching code-generator dep file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/gengo/examples/defaulter-gen/generators/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older defaults "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated defaults files did not change after touching code-generator dep dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
#
# Test when the codegen tool itself changes: conversion
#
assert_clean
touch staging/src/k8s.io/code-generator/cmd/conversion-gen/main.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older conversion "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated conversion files did not change after touching code-generator file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch staging/src/k8s.io/code-generator/cmd/conversion-gen/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older conversion "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated conversion files did not change after touching code-generator dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/code-generator/cmd/conversion-gen/generators/conversion.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older conversion "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated conversion files did not change after touching code-generator dep file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/code-generator/cmd/conversion-gen/generators/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older conversion "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated conversion files did not change after touching code-generator dep dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
#
# Test when we touch a file in a package that needs codegen.
#
assert_clean
touch "staging/src/k8s.io/api/core/v1/types.go"
touch "${STAMP}"
make generated_files >/dev/null
X=($(newer openapi "${STAMP}"))
if [[ "${#X[*]}" != 1 || ! ( "${X[0]}" =~ "pkg/generated/openapi/zz_generated.openapi.go" ) ]]; then
echo "Wrong generated openapi files changed after touching src file:"
echo "${X[@]:-(none)}"
exit 1
fi
#
# Test when the codegen tool itself changes: openapi
#
assert_clean
touch staging/src/k8s.io/code-generator/cmd/openapi-gen/main.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older openapi "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated openapi files did not change after touching code-generator file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch staging/src/k8s.io/code-generator/cmd/openapi-gen/
touch "${STAMP}"
make generated_files >/dev/null
X=($(older openapi "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated openapi files did not change after touching code-generator dir:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
touch "${STAMP}"
make generated_files >/dev/null
X=($(older openapi "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated openapi files did not change after touching code-generator dep file:"
echo " ${X[@]:-(none)}"
exit 1
fi
assert_clean
touch vendor/k8s.io/kube-openapi/pkg/generators
touch "${STAMP}"
make generated_files >/dev/null
X=($(older openapi "${STAMP}"))
if [[ "${#X[*]}" != 0 ]]; then
echo "Generated openapi files did not change after touching code-generator dep dir:"
echo " ${X[@]:-(none)}"
exit 1 exit 1
fi fi