diff options
author | dcorbacho <dparracorbacho@piotal.io> | 2020-11-18 14:27:41 +0000 |
---|---|---|
committer | dcorbacho <dparracorbacho@piotal.io> | 2020-11-18 14:27:41 +0000 |
commit | f23a51261d9502ec39df0f8db47ba6b22aa7659f (patch) | |
tree | 53dcdf46e7dc2c14e81ee960bce8793879b488d3 /deps/rabbit_common/mk | |
parent | afa2c2bf6c7e0e9b63f4fb53dc931c70388e1c82 (diff) | |
parent | 9f6d64ec4a4b1eeac24d7846c5c64fd96798d892 (diff) | |
download | rabbitmq-server-git-stream-timestamp-offset.tar.gz |
Merge remote-tracking branch 'origin/master' into stream-timestamp-offsetstream-timestamp-offset
Diffstat (limited to 'deps/rabbit_common/mk')
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-build.mk | 42 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-components.hexpm.mk | 36 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-components.mk | 359 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-dist.mk | 365 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-early-plugin.mk | 3 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-early-test.mk | 130 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-hexpm.mk | 67 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-macros.mk | 22 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-plugin.mk | 23 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-run.mk | 428 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-test.mk | 80 | ||||
-rw-r--r-- | deps/rabbit_common/mk/rabbitmq-tools.mk | 429 | ||||
-rwxr-xr-x | deps/rabbit_common/mk/xrefr | 338 |
13 files changed, 2322 insertions, 0 deletions
diff --git a/deps/rabbit_common/mk/rabbitmq-build.mk b/deps/rabbit_common/mk/rabbitmq-build.mk new file mode 100644 index 0000000000..2fedcf629b --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-build.mk @@ -0,0 +1,42 @@ +# -------------------------------------------------------------------- +# Compiler flags. +# -------------------------------------------------------------------- + +ifeq ($(filter rabbitmq-macros.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-macros.mk +endif + +# NOTE: This plugin is loaded twice because Erlang.mk recurses. That's +# why ERL_LIBS may contain twice the path to Elixir libraries or +# ERLC_OPTS may contain duplicated flags. + +TEST_ERLC_OPTS += +nowarn_export_all + +ifneq ($(filter-out rabbit_common amqp_client,$(PROJECT)),) +# Add the CLI ebin directory to the code path for the compiler: plugin +# CLI extensions may access behaviour modules defined in this directory. +RMQ_ERLC_OPTS += -pa $(DEPS_DIR)/rabbitmq_cli/_build/dev/lib/rabbitmqctl/ebin +endif + +# Add Lager parse_transform module and our default Lager extra sinks. +LAGER_EXTRA_SINKS += rabbit_log \ + rabbit_log_channel \ + rabbit_log_connection \ + rabbit_log_feature_flags \ + rabbit_log_federation \ + rabbit_log_ldap \ + rabbit_log_mirroring \ + rabbit_log_osiris \ + rabbit_log_prelaunch \ + rabbit_log_queue \ + rabbit_log_ra \ + rabbit_log_shovel \ + rabbit_log_upgrade +lager_extra_sinks = $(subst $(space),$(comma),$(LAGER_EXTRA_SINKS)) + +RMQ_ERLC_OPTS += +'{parse_transform,lager_transform}' \ + +'{lager_extra_sinks,[$(lager_extra_sinks)]}' + +# Push our compilation options to both the normal and test ERLC_OPTS. +ERLC_OPTS += $(RMQ_ERLC_OPTS) +TEST_ERLC_OPTS += $(RMQ_ERLC_OPTS) diff --git a/deps/rabbit_common/mk/rabbitmq-components.hexpm.mk b/deps/rabbit_common/mk/rabbitmq-components.hexpm.mk new file mode 100644 index 0000000000..4b110176a7 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-components.hexpm.mk @@ -0,0 +1,36 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# PROJECT_VERSION defaults to: +# 1. the version exported by rabbitmq-server-release; +# 2. the version stored in `git-revisions.txt`, if it exists; +# 3. a version based on git-describe(1), if it is a Git clone; +# 4. 0.0.0 + +PROJECT_VERSION := $(RABBITMQ_VERSION) + +ifeq ($(PROJECT_VERSION),) +PROJECT_VERSION := $(shell \ +if test -f git-revisions.txt; then \ + head -n1 git-revisions.txt | \ + awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ +else \ + (git describe --dirty --abbrev=7 --tags --always --first-parent \ + 2>/dev/null || echo rabbitmq_v0_0_0) | \ + sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ + -e 's/-/./g'; \ +fi) +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +dep_amqp_client = hex $(PROJECT_VERSION) +dep_rabbit_common = hex $(PROJECT_VERSION) + +# Third-party dependencies version pinning. diff --git a/deps/rabbit_common/mk/rabbitmq-components.mk b/deps/rabbit_common/mk/rabbitmq-components.mk new file mode 100644 index 0000000000..b2a3be8b35 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-components.mk @@ -0,0 +1,359 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# PROJECT_VERSION defaults to: +# 1. the version exported by rabbitmq-server-release; +# 2. the version stored in `git-revisions.txt`, if it exists; +# 3. a version based on git-describe(1), if it is a Git clone; +# 4. 0.0.0 + +PROJECT_VERSION := $(RABBITMQ_VERSION) + +ifeq ($(PROJECT_VERSION),) +PROJECT_VERSION := $(shell \ +if test -f git-revisions.txt; then \ + head -n1 git-revisions.txt | \ + awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ +else \ + (git describe --dirty --abbrev=7 --tags --always --first-parent \ + 2>/dev/null || echo rabbitmq_v0_0_0) | \ + sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ + -e 's/-/./g'; \ +fi) +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_amqp10_client = git_rmq rabbitmq-amqp1.0-client $(current_rmq_ref) $(base_rmq_ref) master +dep_amqp10_common = git_rmq rabbitmq-amqp1.0-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_oauth2 = git_rmq rabbitmq-auth-backend-oauth2 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc_exchange = git_rmq rabbitmq-lvc-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_prometheus = git_rmq rabbitmq-prometheus $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_random_exchange = git_rmq rabbitmq-random-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stream = git_rmq rabbitmq-stream $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# Third-party dependencies version pinning. +# +# We do that in this file, which is copied in all projects, to ensure +# all projects use the same versions. It avoids conflicts and makes it +# possible to work with rabbitmq-public-umbrella. + +dep_accept = hex 0.3.5 +dep_cowboy = hex 2.8.0 +dep_cowlib = hex 2.9.1 +dep_jsx = hex 2.11.0 +dep_lager = hex 3.8.0 +dep_prometheus = git https://github.com/deadtrickster/prometheus.erl.git master +dep_ra = git https://github.com/rabbitmq/ra.git master +dep_ranch = hex 1.7.1 +dep_recon = hex 2.5.1 +dep_observer_cli = hex 1.5.4 +dep_stdout_formatter = hex 0.2.4 +dep_sysmon_handler = hex 1.3.0 + +RABBITMQ_COMPONENTS = amqp_client \ + amqp10_common \ + amqp10_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_cache \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_backend_oauth2 \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_aws \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_cli \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_client_helpers \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_cts \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc_exchange \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_peer_discovery_aws \ + rabbitmq_peer_discovery_common \ + rabbitmq_peer_discovery_consul \ + rabbitmq_peer_discovery_etcd \ + rabbitmq_peer_discovery_k8s \ + rabbitmq_prometheus \ + rabbitmq_random_exchange \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_stream \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Erlang.mk does not rebuild dependencies by default, once they were +# compiled once, except for those listed in the `$(FORCE_REBUILD)` +# variable. +# +# We want all RabbitMQ components to always be rebuilt: this eases +# the work on several components at the same time. + +FORCE_REBUILD = $(RABBITMQ_COMPONENTS) + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +possible_base_rmq_ref := master +ifeq ($(possible_base_rmq_ref),$(current_rmq_ref)) +base_rmq_ref := $(current_rmq_ref) +else +base_rmq_ref := $(shell \ + (git rev-parse --verify -q master >/dev/null && \ + git rev-parse --verify -q $(possible_base_rmq_ref) >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) $(possible_base_rmq_ref) && \ + echo $(possible_base_rmq_ref)) || \ + echo master) +endif +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Macro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# Umbrella-specific settings. +# -------------------------------------------------------------------- + +# If the top-level project is a RabbitMQ component, we override +# $(DEPS_DIR) for this project to point to the top-level's one. +# +# We also verify that the guessed DEPS_DIR is actually named `deps`, +# to rule out any situation where it is a coincidence that we found a +# `rabbitmq-components.mk` up upper directories. + +possible_deps_dir_1 = $(abspath ..) +possible_deps_dir_2 = $(abspath ../../..) + +ifeq ($(notdir $(possible_deps_dir_1)),deps) +ifneq ($(wildcard $(possible_deps_dir_1)/../rabbitmq-components.mk),) +deps_dir_overriden = 1 +DEPS_DIR ?= $(possible_deps_dir_1) +DISABLE_DISTCLEAN = 1 +endif +endif + +ifeq ($(deps_dir_overriden),) +ifeq ($(notdir $(possible_deps_dir_2)),deps) +ifneq ($(wildcard $(possible_deps_dir_2)/../rabbitmq-components.mk),) +deps_dir_overriden = 1 +DEPS_DIR ?= $(possible_deps_dir_2) +DISABLE_DISTCLEAN = 1 +endif +endif +endif + +ifneq ($(wildcard UMBRELLA.md),) +DISABLE_DISTCLEAN = 1 +endif + +# We disable `make distclean` so $(DEPS_DIR) is not accidentally removed. + +ifeq ($(DISABLE_DISTCLEAN),1) +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif diff --git a/deps/rabbit_common/mk/rabbitmq-dist.mk b/deps/rabbit_common/mk/rabbitmq-dist.mk new file mode 100644 index 0000000000..3e17a27939 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-dist.mk @@ -0,0 +1,365 @@ +.PHONY: dist test-dist do-dist cli-scripts cli-escripts clean-dist + +DIST_DIR = plugins +CLI_SCRIPTS_DIR = sbin +CLI_ESCRIPTS_DIR = escript +MIX = echo y | mix + +# Set $(DIST_AS_EZS) to a non-empty value to enable the packaging of +# plugins as .ez archives. +ifeq ($(USE_RABBIT_BOOT_SCRIPT),) +DIST_AS_EZS ?= +else +DIST_AS_EZS = +endif + +dist_verbose_0 = @echo " DIST " $@; +dist_verbose_2 = set -x; +dist_verbose = $(dist_verbose_$(V)) + +MIX_ARCHIVES ?= $(HOME)/.mix/archives + +MIX_TASK_ARCHIVE_DEPS_VERSION = 0.5.0 +mix_task_archive_deps = $(MIX_ARCHIVES)/mix_task_archive_deps-$(MIX_TASK_ARCHIVE_DEPS_VERSION) + +# We take the version of an Erlang application from the .app file. This +# macro is called like this: +# +# $(call get_app_version,/path/to/name.app.src) + +ifeq ($(PLATFORM),msys2) +core_unix_path = $(shell cygpath $1) +else +core_unix_path = $1 +endif + +define get_app_version +$(shell awk ' +/{ *vsn *, *"/ { + vsn=$$0; + sub(/.*{ *vsn, *"/, "", vsn); + sub(/".*/, "", vsn); + print vsn; + exit; +}' $(1)) +endef + +define get_mix_project_version +$(shell cd $(1) && \ + $(MIX) do deps.get, deps.compile, compile >/dev/null && \ + $(MIX) run --no-start -e "IO.puts(Mix.Project.config[:version])") +endef + +# Define the target to create an .ez plugin archive for an +# Erlang.mk-based project. This macro is called like this: +# +# $(call do_ez_target_erlangmk,app_name,app_version,app_dir) + +define do_ez_target_erlangmk +dist_$(1)_ez_dir = $$(if $(2),$(DIST_DIR)/$(1)-$(2), \ + $$(if $$(VERSION),$(DIST_DIR)/$(1)-$$(VERSION),$(DIST_DIR)/$(1))) +ifeq ($(DIST_AS_EZS),) +dist_$(1)_ez = $$(dist_$(1)_ez_dir) +else +dist_$(1)_ez = $$(dist_$(1)_ez_dir).ez +endif + +$$(dist_$(1)_ez): APP = $(1) +$$(dist_$(1)_ez): VSN = $(2) +$$(dist_$(1)_ez): SRC_DIR = $(3) +$$(dist_$(1)_ez): EZ_DIR = $$(abspath $$(dist_$(1)_ez_dir)) +$$(dist_$(1)_ez): EZ = $$(dist_$(1)_ez) +$$(dist_$(1)_ez): $$(if $$(wildcard $(3)/ebin $(3)/include $(3)/priv),\ + $$(filter-out %/dep_built %/ebin/test,$$(call core_find,$$(wildcard $(3)/ebin $(3)/include $(3)/priv),*)),) + +# If the application's Makefile defines a `list-dist-deps` target, we +# use it to populate the dependencies list. This is useful when the +# application has also a `prepare-dist` target to modify the created +# tree before we make an archive out of it. + +ifeq ($$(shell test -f $(3)/rabbitmq-components.mk \ + && grep -q '^list-dist-deps::' $(3)/Makefile && echo yes),yes) +$$(dist_$(1)_ez): $$(patsubst %,$(3)/%, \ + $$(shell $(MAKE) --no-print-directory -C $(3) list-dist-deps \ + APP=$(1) VSN=$(2) EZ_DIR=$$(abspath $$(dist_$(1)_ez_dir)))) +endif + +ERLANGMK_DIST_APPS += $(1) + +ERLANGMK_DIST_EZS += $$(dist_$(1)_ez) + +endef + +# Define the target to create an .ez plugin archive for a Mix-based +# project. This macro is called like this: +# +# $(call do_ez_target_mix,app_name,app_version,app_dir) + +define get_mix_project_dep_ezs +$(shell cd $(1) && \ + $(MIX) do deps.get, deps.compile, compile >/dev/null && \ + $(MIX) archive.build.all.list -e -o $(DIST_DIR) --skip "rabbit $(ERLANGMK_DIST_APPS)") +endef + +define do_ez_target_mix +dist_$(1)_ez_dir = $$(if $(2),$(DIST_DIR)/$(1)-$(2), \ + $$(if $$(VERSION),$(DIST_DIR)/$(1)-$$(VERSION),$(DIST_DIR)/$(1))) +dist_$(1)_ez = $$(dist_$(1)_ez_dir).ez + +$$(dist_$(1)_ez): APP = $(1) +$$(dist_$(1)_ez): VSN = $(2) +$$(dist_$(1)_ez): SRC_DIR = $(3) +$$(dist_$(1)_ez): EZ_DIR = $$(abspath $$(dist_$(1)_ez_dir)) +$$(dist_$(1)_ez): EZ = $$(dist_$(1)_ez) +$$(dist_$(1)_ez): $$(if $$(wildcard _build/dev/lib/$(1)/ebin $(3)/priv),\ + $$(filter-out %/dep_built,$$(call core_find,$$(wildcard _build/dev/lib/$(1)/ebin $(3)/priv),*)),) + +MIX_DIST_EZS += $$(dist_$(1)_ez) +EXTRA_DIST_EZS += $$(call get_mix_project_dep_ezs,$(3)) + +endef + +# Real entry point: it tests the existence of an .app file to determine +# if it is an Erlang application (and therefore if it should be provided +# as an .ez plugin archive) and calls do_ez_target_erlangmk. If instead +# it finds a Mix configuration file, it calls do_ez_target_mix. It +# should be called as: +# +# $(call ez_target,path_to_app) + +define ez_target +dist_$(1)_appdir = $(2) +dist_$(1)_appfile = $$(dist_$(1)_appdir)/ebin/$(1).app +dist_$(1)_mixfile = $$(dist_$(1)_appdir)/mix.exs + +$$(if $$(shell test -f $$(dist_$(1)_appfile) && echo OK), \ + $$(eval $$(call do_ez_target_erlangmk,$(1),$$(call get_app_version,$$(dist_$(1)_appfile)),$$(dist_$(1)_appdir))), \ + $$(if $$(shell test -f $$(dist_$(1)_mixfile) && [ "x$(1)" != "xrabbitmqctl" ] && [ "x$(1)" != "xrabbitmq_cli" ] && echo OK), \ + $$(eval $$(call do_ez_target_mix,$(1),$$(call get_mix_project_version,$$(dist_$(1)_appdir)),$$(dist_$(1)_appdir))))) + +endef + +ifneq ($(filter do-dist,$(MAKECMDGOALS)),) +# The following code is evaluated only when running "make do-dist", +# otherwise it would trigger an infinite loop, as this code calls "make +# list-dist-deps" (see do_ez_target_erlangmk). +ifdef DIST_PLUGINS_LIST +# Now, try to create an .ez target for the top-level project and all +# dependencies. + +ifeq ($(wildcard $(DIST_PLUGINS_LIST)),) +$(error DIST_PLUGINS_LIST ($(DIST_PLUGINS_LIST)) is missing) +endif + +$(eval $(foreach path, \ + $(filter-out %/looking_glass %/lz4, \ + $(sort $(shell cat $(DIST_PLUGINS_LIST))) $(CURDIR)), \ + $(call ez_target,$(if $(filter $(path),$(CURDIR)),$(PROJECT),$(notdir $(path))),$(path)))) +endif +endif + +# The actual recipe to create the .ez plugin archive. Some variables +# are defined in the do_ez_target_erlangmk and do_ez_target_mix macros +# above. All .ez archives are also listed in this do_ez_target_erlangmk +# and do_ez_target_mix macros. + +RSYNC ?= rsync +RSYNC_V_0 = +RSYNC_V_1 = -v +RSYNC_V = $(RSYNC_V_$(V)) + +ZIP ?= zip +ZIP_V_0 = -q +ZIP_V_1 = +ZIP_V = $(ZIP_V_$(V)) + +$(ERLANGMK_DIST_EZS): + $(verbose) rm -rf $(EZ_DIR) $(EZ) + $(verbose) mkdir -p $(EZ_DIR) + $(dist_verbose) $(RSYNC) -a $(RSYNC_V) \ + --exclude '/ebin/dep_built' \ + --exclude '/ebin/test' \ + --include '/ebin/***' \ + --include '/include/***' \ + --include '/priv/***' \ + --exclude '*' \ + $(call core_unix_path,$(SRC_DIR))/ $(call core_unix_path,$(EZ_DIR))/ + @# Give a chance to the application to make any modification it + @# wants to the tree before we make an archive. + $(verbose) ! (test -f $(SRC_DIR)/rabbitmq-components.mk \ + && grep -q '^prepare-dist::' $(SRC_DIR)/Makefile) || \ + $(MAKE) --no-print-directory -C $(SRC_DIR) prepare-dist \ + APP=$(APP) VSN=$(VSN) EZ_DIR=$(EZ_DIR) +ifneq ($(DIST_AS_EZS),) + $(verbose) (cd $(DIST_DIR) && \ + find "$(basename $(notdir $@))" | LC_COLLATE=C sort \ + > "$(basename $(notdir $@)).manifest" && \ + $(ZIP) $(ZIP_V) --names-stdin "$(notdir $@)" \ + < "$(basename $(notdir $@)).manifest") + $(verbose) rm -rf $(EZ_DIR) $(EZ_DIR).manifest +endif + +$(MIX_DIST_EZS): $(mix_task_archive_deps) + $(verbose) cd $(SRC_DIR) && \ + $(MIX) do deps.get, deps.compile, compile, archive.build.all \ + -e -o $(abspath $(DIST_DIR)) --skip "rabbit $(ERLANGMK_DIST_APPS)" + +MIX_TASK_ARCHIVE_DEPS_URL = https://github.com/rabbitmq/mix_task_archive_deps/releases/download/$(MIX_TASK_ARCHIVE_DEPS_VERSION)/mix_task_archive_deps-$(MIX_TASK_ARCHIVE_DEPS_VERSION).ez + +$(mix_task_archive_deps): + $(gen_verbose) mix archive.install --force $(MIX_TASK_ARCHIVE_DEPS_URL) + +# We need to recurse because the top-level make instance is evaluated +# before dependencies are downloaded. + +MAYBE_APPS_LIST = $(if $(shell test -f $(ERLANG_MK_TMP)/apps.log && echo OK), \ + $(ERLANG_MK_TMP)/apps.log) +DIST_LOCK = $(DIST_DIR).lock + +dist:: $(ERLANG_MK_RECURSIVE_DEPS_LIST) all + $(gen_verbose) \ + if command -v flock >/dev/null; then \ + flock $(DIST_LOCK) \ + sh -c '$(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"'; \ + elif command -v lockf >/dev/null; then \ + lockf $(DIST_LOCK) \ + sh -c '$(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"'; \ + else \ + $(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"; \ + fi + +test-dist:: export TEST_DIR=NON-EXISTENT +test-dist:: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) test-build + $(gen_verbose) \ + if command -v flock >/dev/null; then \ + flock $(DIST_LOCK) \ + sh -c '$(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"'; \ + elif command -v lockf >/dev/null; then \ + lockf $(DIST_LOCK) \ + sh -c '$(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"'; \ + else \ + $(MAKE) do-dist \ + DIST_PLUGINS_LIST="$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(MAYBE_APPS_LIST)"; \ + fi + +DIST_EZS = $(ERLANGMK_DIST_EZS) $(MIX_DIST_EZS) + +do-dist:: $(DIST_EZS) + $(verbose) unwanted='$(filter-out $(DIST_EZS) $(EXTRA_DIST_EZS), \ + $(wildcard $(DIST_DIR)/*))'; \ + test -z "$$unwanted" || (echo " RM $$unwanted" && rm -rf $$unwanted) + +CLI_SCRIPTS_LOCK = $(CLI_SCRIPTS_DIR).lock +CLI_ESCRIPTS_LOCK = $(CLI_ESCRIPTS_DIR).lock + +ifneq ($(filter-out rabbit_common amqp10_common,$(PROJECT)),) +dist:: install-cli +test-build:: install-cli +endif + +install-cli: install-cli-scripts install-cli-escripts + @: + +ifeq ($(PROJECT),rabbit) +install-cli-scripts: + $(gen_verbose) \ + if command -v flock >/dev/null; then \ + flock $(CLI_SCRIPTS_LOCK) \ + sh -c 'mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in scripts/*; do \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done'; \ + elif command -v lockf >/dev/null; then \ + lockf $(CLI_SCRIPTS_LOCK) \ + sh -c 'mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in scripts/*; do \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done'; \ + else \ + mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in scripts/*; do \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done; \ + fi +else + +install-cli-scripts: + $(gen_verbose) \ + set -e; \ + if test -d "$(DEPS_DIR)/rabbit/scripts"; then \ + rabbit_scripts_dir='$(DEPS_DIR)/rabbit/scripts'; \ + elif test -d "$(DEPS_DIR)/../scripts"; then \ + rabbit_scripts_dir='$(DEPS_DIR)/../scripts'; \ + else \ + echo 'rabbit/scripts directory not found' 1>&2; \ + exit 1; \ + fi; \ + test -d "$$rabbit_scripts_dir"; \ + if command -v flock >/dev/null; then \ + flock $(CLI_SCRIPTS_LOCK) \ + sh -e -c 'mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in "'$$rabbit_scripts_dir'"/*; do \ + test -f "$$file"; \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done'; \ + elif command -v lockf >/dev/null; then \ + lockf $(CLI_SCRIPTS_LOCK) \ + sh -e -c 'mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in "'$$rabbit_scripts_dir'"/*; do \ + test -f "$$file"; \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done'; \ + else \ + mkdir -p "$(CLI_SCRIPTS_DIR)" && \ + for file in "$$rabbit_scripts_dir"/*; do \ + test -f "$$file"; \ + cmp -s "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")" || \ + cp -a "$$file" "$(CLI_SCRIPTS_DIR)/$$(basename "$$file")"; \ + done; \ + fi +endif + +install-cli-escripts: + $(gen_verbose) \ + if command -v flock >/dev/null; then \ + flock $(CLI_ESCRIPTS_LOCK) \ + sh -c 'mkdir -p "$(CLI_ESCRIPTS_DIR)" && \ + $(MAKE) -C "$(DEPS_DIR)/rabbitmq_cli" install \ + PREFIX="$(abspath $(CLI_ESCRIPTS_DIR))" \ + DESTDIR='; \ + elif command -v lockf >/dev/null; then \ + lockf $(CLI_ESCRIPTS_LOCK) \ + sh -c 'mkdir -p "$(CLI_ESCRIPTS_DIR)" && \ + $(MAKE) -C "$(DEPS_DIR)/rabbitmq_cli" install \ + PREFIX="$(abspath $(CLI_ESCRIPTS_DIR))" \ + DESTDIR='; \ + else \ + mkdir -p "$(CLI_ESCRIPTS_DIR)" && \ + $(MAKE) -C "$(DEPS_DIR)/rabbitmq_cli" install \ + PREFIX="$(abspath $(CLI_ESCRIPTS_DIR))" \ + DESTDIR= ; \ + fi + +clean-dist:: + $(gen_verbose) rm -rf \ + "$(DIST_DIR)" \ + "$(CLI_SCRIPTS_DIR)" \ + "$(CLI_ESCRIPTS_DIR)" + +clean:: clean-dist diff --git a/deps/rabbit_common/mk/rabbitmq-early-plugin.mk b/deps/rabbit_common/mk/rabbitmq-early-plugin.mk new file mode 100644 index 0000000000..7b5f14b8f9 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-early-plugin.mk @@ -0,0 +1,3 @@ +ifeq ($(filter rabbitmq-early-test.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-early-test.mk +endif diff --git a/deps/rabbit_common/mk/rabbitmq-early-test.mk b/deps/rabbit_common/mk/rabbitmq-early-test.mk new file mode 100644 index 0000000000..f4f00173b3 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-early-test.mk @@ -0,0 +1,130 @@ +# -------------------------------------------------------------------- +# xref +# -------------------------------------------------------------------- + +ifeq ($(filter distclean distclean-xref,$(MAKECMDGOALS)),) +ifneq ($(PROJECT),rabbit_common) +XREFR := $(DEPS_DIR)/rabbit_common/mk/xrefr +else +XREFR := mk/xrefr +endif +endif + +# -------------------------------------------------------------------- +# dialyzer +# -------------------------------------------------------------------- + +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions + +# -------------------------------------------------------------------- +# %-on-concourse dependencies. +# -------------------------------------------------------------------- + +ifneq ($(words $(filter %-on-concourse,$(MAKECMDGOALS))),0) +TEST_DEPS += ci $(RMQ_CI_CT_HOOKS) +NO_AUTOPATCH += ci $(RMQ_CI_CT_HOOKS) +dep_ci = git git@github.com:rabbitmq/rabbitmq-ci master +endif + +# -------------------------------------------------------------------- +# Common Test flags. +# -------------------------------------------------------------------- + +# We start the common_test node as a hidden Erlang node. The benefit +# is that other Erlang nodes won't try to connect to each other after +# discovering the common_test node if they are not meant to. +# +# This helps when several unrelated RabbitMQ clusters are started in +# parallel. + +CT_OPTS += -hidden + +# Enable the following common_test hooks on Travis and Concourse: +# +# cth_fail_fast +# This hook will make sure the first failure puts an end to the +# testsuites; ie. all remaining tests are skipped. +# +# cth_styledout +# This hook will change the output of common_test to something more +# concise and colored. +# +# On Jenkins, in addition to those common_test hooks, enable JUnit-like +# report. Jenkins parses those reports so the results can be browsed +# from its UI. Furthermore, it displays a graph showing evolution of the +# results over time. + +ifndef TRAVIS +CT_HOOKS ?= cth_styledout +TEST_DEPS += cth_styledout +endif + +ifdef TRAVIS +FAIL_FAST = 1 +SKIP_AS_ERROR = 1 +endif + +ifdef CONCOURSE +FAIL_FAST = 1 +SKIP_AS_ERROR = 1 +endif + +RMQ_CI_CT_HOOKS = cth_fail_fast +ifeq ($(FAIL_FAST),1) +CT_HOOKS += $(RMQ_CI_CT_HOOKS) +TEST_DEPS += $(RMQ_CI_CT_HOOKS) +endif + +dep_cth_fail_fast = git https://github.com/rabbitmq/cth_fail_fast.git master +dep_cth_styledout = git https://github.com/rabbitmq/cth_styledout.git master + +CT_HOOKS_PARAM_VALUE = $(patsubst %,and %,$(CT_HOOKS)) +CT_OPTS += -ct_hooks $(wordlist 2,$(words $(CT_HOOKS_PARAM_VALUE)),$(CT_HOOKS_PARAM_VALUE)) + +# Disable most messages on Travis because it might exceed the limit +# set by Travis. +# +# CAUTION: All arguments after -erl_args are passed to the emulator and +# common_test doesn't interpret them! Therefore, all common_test flags +# *MUST* appear before. + +CT_QUIET_FLAGS = -verbosity 50 \ + -erl_args \ + -kernel error_logger silent + +ifdef TRAVIS +CT_OPTS += $(CT_QUIET_FLAGS) +endif + +# On CI, set $RABBITMQ_CT_SKIP_AS_ERROR so that any skipped +# testsuite/testgroup/testcase is considered an error. + +ifeq ($(SKIP_AS_ERROR),1) +export RABBITMQ_CT_SKIP_AS_ERROR = true +endif + +# -------------------------------------------------------------------- +# Looking Glass rules. +# -------------------------------------------------------------------- + +ifneq ("$(RABBITMQ_TRACER)","") +BUILD_DEPS += looking_glass +dep_looking_glass = git https://github.com/rabbitmq/looking-glass master +ERL_LIBS := "$(ERL_LIBS):../looking_glass:../lz4" +export RABBITMQ_TRACER +endif + +define lg_callgrind.erl +lg_callgrind:profile_many("traces.lz4.*", "callgrind.out", #{running => true}), +halt(). +endef + +.PHONY: profile clean-profile + +profile: + $(gen_verbose) $(call erlang,$(call lg_callgrind.erl)) + +clean:: clean-profile + +clean-profile: + $(gen_verbose) rm -f traces.lz4.* callgrind.out.* diff --git a/deps/rabbit_common/mk/rabbitmq-hexpm.mk b/deps/rabbit_common/mk/rabbitmq-hexpm.mk new file mode 100644 index 0000000000..24281b1321 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-hexpm.mk @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------- +# Hex.pm. +# -------------------------------------------------------------------- + +.PHONY: hex-publish hex-publish-docs + +HEXPM_URL = https://github.com/rabbitmq/hexpm-cli/releases/latest/download/hexpm +HEXPM_CLI = $(ERLANG_MK_TMP)/hexpm + +$(HEXPM_CLI): + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(gen_verbose) $(call core_http_get,$@,$(HEXPM_URL)) + $(verbose) chmod +x $@ + +RABBIT_COMMON_HEXPM_VERSION = $(PROJECT_VERSION) +AMQP_CLIENT_HEXPM_VERSION = $(PROJECT_VERSION) + +rebar.config: dep_rabbit_common = hex $(RABBIT_COMMON_HEXPM_VERSION) +rebar.config: dep_amqp_client = hex $(AMQP_CLIENT_HEXPM_VERSION) + +define RABBITMQ_HEXPM_DEFAULT_FILES + "erlang.mk", + "git-revisions.txt", + "include", + "LICENSE*", + "Makefile", + "rabbitmq-components.mk", + "README", + "README.md", + "src" +endef + +ifeq ($(PROJECT),rabbit_common) +RMQ_COMPONENTS_PREFIX = mk +RMQ_COMPONENTS_HEXPM = mk/rabbitmq-components.hexpm.mk +else +RMQ_COMPONENTS_PREFIX = . +RMQ_COMPONENTS_HEXPM = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.hexpm.mk +endif + +hex-publish: $(HEXPM_CLI) app rebar.config + $(gen_verbose) echo "$(PROJECT_DESCRIPTION) $(PROJECT_VERSION)" \ + > git-revisions.txt + $(verbose) mv \ + $(RMQ_COMPONENTS_PREFIX)/rabbitmq-components.mk \ + rabbitmq-components.mk.not-hexpm + $(verbose) cp \ + $(RMQ_COMPONENTS_HEXPM) \ + $(RMQ_COMPONENTS_PREFIX)/rabbitmq-components.mk + $(verbose) grep -E '^dep.* = hex' \ + rabbitmq-components.mk.not-hexpm \ + >> $(RMQ_COMPONENTS_PREFIX)/rabbitmq-components.mk + $(verbose) touch -r \ + rabbitmq-components.mk.not-hexpm \ + $(RMQ_COMPONENTS_PREFIX)/rabbitmq-components.mk + $(verbose) trap '\ + rm -f git-revisions.txt rebar.lock; \ + if test -f rabbitmq-components.mk.not-hexpm; then \ + mv \ + rabbitmq-components.mk.not-hexpm \ + $(RMQ_COMPONENTS_PREFIX)/rabbitmq-components.mk; \ + fi' EXIT INT; \ + $(HEXPM_CLI) publish + +hex-publish-docs: $(HEXPM_CLI) app docs + $(gen_verbose) trap 'rm -f rebar.lock' EXIT INT; \ + $(HEXPM_CLI) docs diff --git a/deps/rabbit_common/mk/rabbitmq-macros.mk b/deps/rabbit_common/mk/rabbitmq-macros.mk new file mode 100644 index 0000000000..048745a7f0 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-macros.mk @@ -0,0 +1,22 @@ +# Macro to compare two x.y.z versions. +# +# Usage: +# ifeq ($(call compare_version,$(ERTS_VER),$(MAX_ERTS_VER),<),true) +# # Only evaluated if $(ERTS_VER) < $(MAX_ERTS_VER) +# endif + +define compare_version +$(shell awk 'BEGIN { + split("$(1)", v1, "."); + version1 = v1[1] * 1000000 + v1[2] * 10000 + v1[3] * 100 + v1[4]; + + split("$(2)", v2, "."); + version2 = v2[1] * 1000000 + v2[2] * 10000 + v2[3] * 100 + v2[4]; + + if (version1 $(3) version2) { + print "true"; + } else { + print "false"; + } +}') +endef diff --git a/deps/rabbit_common/mk/rabbitmq-plugin.mk b/deps/rabbit_common/mk/rabbitmq-plugin.mk new file mode 100644 index 0000000000..29064a9a4f --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-plugin.mk @@ -0,0 +1,23 @@ +ifeq ($(filter rabbitmq-build.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-build.mk +endif + +ifeq ($(filter rabbitmq-hexpm.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-hexpm.mk +endif + +ifeq ($(filter rabbitmq-dist.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-dist.mk +endif + +ifeq ($(filter rabbitmq-run.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-run.mk +endif + +ifeq ($(filter rabbitmq-test.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-test.mk +endif + +ifeq ($(filter rabbitmq-tools.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-tools.mk +endif diff --git a/deps/rabbit_common/mk/rabbitmq-run.mk b/deps/rabbit_common/mk/rabbitmq-run.mk new file mode 100644 index 0000000000..bef62c03f7 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-run.mk @@ -0,0 +1,428 @@ +.PHONY: run-broker run-background-broker run-node run-background-node \ + start-background-node start-rabbit-on-node \ + stop-rabbit-on-node set-resource-alarm clear-resource-alarm \ + stop-node + +ifeq ($(filter rabbitmq-dist.mk,$(notdir $(MAKEFILE_LIST))),) +include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-dist.mk +endif + +exec_verbose_0 = @echo " EXEC " $@; +exec_verbose_2 = set -x; +exec_verbose = $(exec_verbose_$(V)) + +ifeq ($(PLATFORM),msys2) +TEST_TMPDIR ?= $(TEMP)/rabbitmq-test-instances +else +TMPDIR ?= /tmp +TEST_TMPDIR ?= $(TMPDIR)/rabbitmq-test-instances +endif + +# Location of the scripts controlling the broker. +RABBITMQ_SCRIPTS_DIR ?= $(CURDIR)/sbin + +ifeq ($(PLATFORM),msys2) +RABBITMQ_PLUGINS ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmq-plugins.bat +RABBITMQ_SERVER ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmq-server.bat +RABBITMQCTL ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmqctl.bat +else +RABBITMQ_PLUGINS ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmq-plugins +RABBITMQ_SERVER ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmq-server +RABBITMQCTL ?= $(RABBITMQ_SCRIPTS_DIR)/rabbitmqctl +endif + +export RABBITMQ_SCRIPTS_DIR RABBITMQCTL RABBITMQ_PLUGINS RABBITMQ_SERVER + +# We export MAKE to be sure scripts and tests use the proper command. +export MAKE + +# We need to pass the location of codegen to the Java client ant +# process. +CODEGEN_DIR = $(DEPS_DIR)/rabbitmq_codegen +PYTHONPATH = $(CODEGEN_DIR) +export PYTHONPATH + +ANT ?= ant +ANT_FLAGS += -Dmake.bin=$(MAKE) \ + -DUMBRELLA_AVAILABLE=true \ + -Drabbitmqctl.bin=$(RABBITMQCTL) \ + -Dsibling.codegen.dir=$(CODEGEN_DIR) +ifeq ($(PROJECT),rabbitmq_test) +ANT_FLAGS += -Dsibling.rabbitmq_test.dir=$(CURDIR) +else +ANT_FLAGS += -Dsibling.rabbitmq_test.dir=$(DEPS_DIR)/rabbitmq_test +endif +export ANT ANT_FLAGS + +node_tmpdir = $(TEST_TMPDIR)/$(1) +node_pid_file = $(call node_tmpdir,$(1))/$(1).pid +node_log_base = $(call node_tmpdir,$(1))/log +node_mnesia_base = $(call node_tmpdir,$(1))/mnesia +node_mnesia_dir = $(call node_mnesia_base,$(1))/$(1) +node_quorum_dir = $(call node_mnesia_dir,$(1))/quorum +node_stream_dir = $(call node_mnesia_dir,$(1))/stream +node_plugins_expand_dir = $(call node_tmpdir,$(1))/plugins +node_feature_flags_file = $(call node_tmpdir,$(1))/feature_flags +node_enabled_plugins_file = $(call node_tmpdir,$(1))/enabled_plugins + +# Broker startup variables for the test environment. +ifeq ($(PLATFORM),msys2) +HOSTNAME := $(COMPUTERNAME) +else +HOSTNAME := $(shell hostname -s) +endif + +RABBITMQ_NODENAME ?= rabbit@$(HOSTNAME) +RABBITMQ_NODENAME_FOR_PATHS ?= $(RABBITMQ_NODENAME) +NODE_TMPDIR ?= $(call node_tmpdir,$(RABBITMQ_NODENAME_FOR_PATHS)) + +RABBITMQ_BASE ?= $(NODE_TMPDIR) +RABBITMQ_PID_FILE ?= $(call node_pid_file,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_LOG_BASE ?= $(call node_log_base,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_MNESIA_BASE ?= $(call node_mnesia_base,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_MNESIA_DIR ?= $(call node_mnesia_dir,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_QUORUM_DIR ?= $(call node_quorum_dir,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_STREAM_DIR ?= $(call node_stream_dir,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_PLUGINS_EXPAND_DIR ?= $(call node_plugins_expand_dir,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_FEATURE_FLAGS_FILE ?= $(call node_feature_flags_file,$(RABBITMQ_NODENAME_FOR_PATHS)) +RABBITMQ_ENABLED_PLUGINS_FILE ?= $(call node_enabled_plugins_file,$(RABBITMQ_NODENAME_FOR_PATHS)) + +# Enable colourful debug logging by default +# To change this, set RABBITMQ_LOG to info, notice, warning etc. +RABBITMQ_LOG ?= debug,+color +export RABBITMQ_LOG + +# erlang.mk adds dependencies' ebin directory to ERL_LIBS. This is +# a sane default, but we prefer to rely on the .ez archives in the +# `plugins` directory so the plugin code is executed. The `plugins` +# directory is added to ERL_LIBS by rabbitmq-env. +DIST_ERL_LIBS = $(patsubst :%,%,$(patsubst %:,%,$(subst :$(APPS_DIR):,:,$(subst :$(DEPS_DIR):,:,:$(ERL_LIBS):)))) + +ifdef PLUGINS_FROM_DEPS_DIR +RMQ_PLUGINS_DIR=$(DEPS_DIR) +else +RMQ_PLUGINS_DIR=$(CURDIR)/$(DIST_DIR) +endif + +define basic_script_env_settings +MAKE="$(MAKE)" \ +ERL_LIBS="$(DIST_ERL_LIBS)" \ +RABBITMQ_NODENAME="$(1)" \ +RABBITMQ_NODE_IP_ADDRESS="$(RABBITMQ_NODE_IP_ADDRESS)" \ +RABBITMQ_NODE_PORT="$(3)" \ +RABBITMQ_BASE="$(call node_tmpdir,$(2))" \ +RABBITMQ_PID_FILE="$(call node_pid_file,$(2))" \ +RABBITMQ_LOG_BASE="$(call node_log_base,$(2))" \ +RABBITMQ_MNESIA_BASE="$(call node_mnesia_base,$(2))" \ +RABBITMQ_MNESIA_DIR="$(call node_mnesia_dir,$(2))" \ +RABBITMQ_QUORUM_DIR="$(call node_quorum_dir,$(2))" \ +RABBITMQ_STREAM_DIR="$(call node_stream_dir,$(2))" \ +RABBITMQ_FEATURE_FLAGS_FILE="$(call node_feature_flags_file,$(2))" \ +RABBITMQ_PLUGINS_DIR="$(if $(RABBITMQ_PLUGINS_DIR),$(RABBITMQ_PLUGINS_DIR),$(RMQ_PLUGINS_DIR))" \ +RABBITMQ_PLUGINS_EXPAND_DIR="$(call node_plugins_expand_dir,$(2))" \ +RABBITMQ_SERVER_START_ARGS="-ra wal_sync_method sync $(RABBITMQ_SERVER_START_ARGS)" \ +RABBITMQ_ENABLED_PLUGINS="$(RABBITMQ_ENABLED_PLUGINS)" +endef + +BASIC_SCRIPT_ENV_SETTINGS = \ + $(call basic_script_env_settings,$(RABBITMQ_NODENAME),$(RABBITMQ_NODENAME_FOR_PATHS),$(RABBITMQ_NODE_PORT)) \ + RABBITMQ_ENABLED_PLUGINS_FILE="$(RABBITMQ_ENABLED_PLUGINS_FILE)" + +test-tmpdir: + $(verbose) mkdir -p $(TEST_TMPDIR) + +virgin-test-tmpdir: + $(gen_verbose) rm -rf $(TEST_TMPDIR) + $(verbose) mkdir -p $(TEST_TMPDIR) + +node-tmpdir: + $(verbose) mkdir -p $(RABBITMQ_LOG_BASE) \ + $(RABBITMQ_MNESIA_BASE) \ + $(RABBITMQ_PLUGINS_EXPAND_DIR) + +virgin-node-tmpdir: + $(gen_verbose) rm -rf $(NODE_TMPDIR) + $(verbose) mkdir -p $(RABBITMQ_LOG_BASE) \ + $(RABBITMQ_MNESIA_BASE) \ + $(RABBITMQ_PLUGINS_EXPAND_DIR) + +.PHONY: test-tmpdir virgin-test-tmpdir node-tmpdir virgin-node-tmpdir + +ifdef LEAVE_PLUGINS_DISABLED +RABBITMQ_ENABLED_PLUGINS ?= +else +RABBITMQ_ENABLED_PLUGINS ?= ALL +endif + +# -------------------------------------------------------------------- +# Run a full RabbitMQ. +# -------------------------------------------------------------------- + +define test_rabbitmq_config +%% vim:ft=erlang: + +[ + {rabbit, [ +$(if $(RABBITMQ_NODE_PORT), {tcp_listeners$(comma) [$(RABBITMQ_NODE_PORT)]}$(comma),) + {loopback_users, []}, + {log, [{file, [{level, debug}]}, + {console, [{level, debug}]}]} + ]}, + {rabbitmq_management, [ +$(if $(RABBITMQ_NODE_PORT), {listener$(comma) [{port$(comma) $(shell echo "$$(($(RABBITMQ_NODE_PORT) + 10000))")}]},) + ]}, + {rabbitmq_mqtt, [ +$(if $(RABBITMQ_NODE_PORT), {tcp_listeners$(comma) [$(shell echo "$$((1883 + $(RABBITMQ_NODE_PORT) - 5672))")]},) + ]}, + {rabbitmq_stomp, [ +$(if $(RABBITMQ_NODE_PORT), {tcp_listeners$(comma) [$(shell echo "$$((61613 + $(RABBITMQ_NODE_PORT) - 5672))")]},) + ]}, + {ra, [ + {data_dir, "$(RABBITMQ_QUORUM_DIR)"}, + {wal_sync_method, sync} + ]}, + {lager, [ + {colors, [ + %% https://misc.flogisoft.com/bash/tip_colors_and_formatting + {debug, "\\\e[0;34m" }, + {info, "\\\e[1;37m" }, + {notice, "\\\e[1;36m" }, + {warning, "\\\e[1;33m" }, + {error, "\\\e[1;31m" }, + {critical, "\\\e[1;35m" }, + {alert, "\\\e[1;44m" }, + {emergency, "\\\e[1;41m" } + ]} + ]}, + {osiris, [ + {data_dir, "$(RABBITMQ_STREAM_DIR)"} + ]} +]. +endef + +define test_rabbitmq_config_with_tls +%% vim:ft=erlang: + +[ + {rabbit, [ + {loopback_users, []}, + {log, [{file, [{level, debug}]}, + {console, [{level, debug}]}]}, + {ssl_listeners, [5671]}, + {ssl_options, [ + {cacertfile, "$(TEST_TLS_CERTS_DIR_in_config)/testca/cacert.pem"}, + {certfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/cert.pem"}, + {keyfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]} + ]}, + {rabbitmq_management, [ + {listener, [ + {port, 15671}, + {ssl, true}, + {ssl_opts, [ + {cacertfile, "$(TEST_TLS_CERTS_DIR_in_config)/testca/cacert.pem"}, + {certfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/cert.pem"}, + {keyfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]} + ]} + ]}, + {ra, [ + {data_dir, "$(RABBITMQ_QUORUM_DIR)"}, + {wal_sync_method, sync} + ]}, + {lager, [ + {colors, [ + %% https://misc.flogisoft.com/bash/tip_colors_and_formatting + {debug, "\\\e[0;34m" }, + {info, "\\\e[1;37m" }, + {notice, "\\\e[1;36m" }, + {warning, "\\\e[1;33m" }, + {error, "\\\e[1;31m" }, + {critical, "\\\e[1;35m" }, + {alert, "\\\e[1;44m" }, + {emergency, "\\\e[1;41m" } + ]} + ]}, + {osiris, [ + {data_dir, "$(RABBITMQ_STREAM_DIR)"} + ]} +]. +endef + +TEST_CONFIG_FILE ?= $(TEST_TMPDIR)/test.config +TEST_TLS_CERTS_DIR := $(TEST_TMPDIR)/tls-certs +ifeq ($(origin TEST_TLS_CERTS_DIR_in_config),undefined) +ifeq ($(PLATFORM),msys2) +TEST_TLS_CERTS_DIR_in_config := $(shell echo $(TEST_TLS_CERTS_DIR) | sed -E "s,^/([^/]+),\1:,") +else +TEST_TLS_CERTS_DIR_in_config := $(TEST_TLS_CERTS_DIR) +endif +export TEST_TLS_CERTS_DIR_in_config +endif + +.PHONY: $(TEST_CONFIG_FILE) +$(TEST_CONFIG_FILE): node-tmpdir + $(gen_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(config)))" > $@ + +$(TEST_TLS_CERTS_DIR): node-tmpdir + $(gen_verbose) $(MAKE) -C $(DEPS_DIR)/rabbitmq_ct_helpers/tools/tls-certs \ + DIR=$(TEST_TLS_CERTS_DIR) all + +show-test-tls-certs-dir: $(TEST_TLS_CERTS_DIR) + @echo $(TEST_TLS_CERTS_DIR) + +ifdef NOBUILD +DIST_TARGET ?= +else +ifeq ($(wildcard ebin/test),) +DIST_TARGET ?= dist +else +DIST_TARGET ?= test-dist +endif +endif + +run-broker run-tls-broker: RABBITMQ_CONFIG_FILE := $(basename $(TEST_CONFIG_FILE)) +run-broker: config := $(test_rabbitmq_config) +run-tls-broker: config := $(test_rabbitmq_config_with_tls) +run-tls-broker: $(TEST_TLS_CERTS_DIR) + +run-broker run-tls-broker: node-tmpdir $(DIST_TARGET) $(TEST_CONFIG_FILE) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + RABBITMQ_ALLOW_INPUT=true \ + RABBITMQ_CONFIG_FILE=$(RABBITMQ_CONFIG_FILE) \ + $(RABBITMQ_SERVER) + +run-background-broker: node-tmpdir $(DIST_TARGET) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + $(RABBITMQ_SERVER) -detached + +# -------------------------------------------------------------------- +# Run a bare Erlang node. +# -------------------------------------------------------------------- + +run-node: node-tmpdir $(DIST_TARGET) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + RABBITMQ_NODE_ONLY=true \ + RABBITMQ_ALLOW_INPUT=true \ + $(RABBITMQ_SERVER) + +run-background-node: virgin-node-tmpdir $(DIST_TARGET) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + RABBITMQ_NODE_ONLY=true \ + $(RABBITMQ_SERVER) -detached + +# -------------------------------------------------------------------- +# Start RabbitMQ in the background. +# -------------------------------------------------------------------- + +ifneq ($(LOG_TO_STDIO),yes) +REDIRECT_STDIO = > $(RABBITMQ_LOG_BASE)/startup_log \ + 2> $(RABBITMQ_LOG_BASE)/startup_err +endif + +RMQCTL_WAIT_TIMEOUT ?= 60 + +define rmq_started +true = rpc:call('$(1)', rabbit, is_running, []), +halt(). +endef + +start-background-node: node-tmpdir $(DIST_TARGET) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + RABBITMQ_NODE_ONLY=true \ + $(RABBITMQ_SERVER) \ + $(REDIRECT_STDIO) & + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) wait --timeout $(RMQCTL_WAIT_TIMEOUT) $(RABBITMQ_PID_FILE) kernel + +start-background-broker: node-tmpdir $(DIST_TARGET) + $(BASIC_SCRIPT_ENV_SETTINGS) \ + $(RABBITMQ_SERVER) \ + $(REDIRECT_STDIO) & + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) wait --timeout $(RMQCTL_WAIT_TIMEOUT) $(RABBITMQ_PID_FILE) && \ + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(call erlang,$(call rmq_started,$(RABBITMQ_NODENAME)),-sname sbb-$$$$ -hidden) + +start-rabbit-on-node: + $(exec_verbose) ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) \ + eval 'rabbit:start().' | \ + sed -E -e '/^ completed with .* plugins\.$$/d' -e '/^ok$$/d' + $(verbose) ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) wait --timeout $(RMQCTL_WAIT_TIMEOUT) $(RABBITMQ_PID_FILE) + +stop-rabbit-on-node: + $(exec_verbose) ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) \ + eval 'rabbit:stop().' | \ + sed -E -e '/^ok$$/d' + +stop-node: + $(exec_verbose) ( \ + pid=$$(test -f $(RABBITMQ_PID_FILE) && cat $(RABBITMQ_PID_FILE)); \ + test "$$pid" && \ + kill -TERM "$$pid" && \ + echo waiting for process to exit && \ + while ps -p "$$pid" >/dev/null 2>&1; do sleep 1; done \ + ) || : + +# " <-- To please Vim syntax hilighting. + +# -------------------------------------------------------------------- +# Start a RabbitMQ cluster in the background. +# -------------------------------------------------------------------- + +NODES ?= 2 + +start-brokers start-cluster: $(DIST_TARGET) + @for n in $$(seq $(NODES)); do \ + nodename="rabbit-$$n@$(HOSTNAME)"; \ + $(MAKE) start-background-broker \ + NOBUILD=1 \ + RABBITMQ_NODENAME="$$nodename" \ + RABBITMQ_NODE_PORT="$$((5672 + $$n - 1))" \ + RABBITMQ_SERVER_START_ARGS=" \ + -rabbit loopback_users [] \ + -rabbitmq_management listener [{port,$$((15672 + $$n - 1))}] \ + -rabbitmq_mqtt tcp_listeners [$$((1883 + $$n - 1))] \ + -rabbitmq_stomp tcp_listeners [$$((61613 + $$n - 1))] \ + -rabbitmq_prometheus tcp_config [{port,$$((15692 + $$n - 1))}] \ + -rabbitmq_stream tcp_listeners [$$((5555 + $$n - 1))] \ + "; \ + if test '$@' = 'start-cluster' && test "$$nodename1"; then \ + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n "$$nodename" stop_app; \ + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n "$$nodename" join_cluster "$$nodename1"; \ + ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n "$$nodename" start_app; \ + else \ + nodename1=$$nodename; \ + fi; \ + done + +stop-brokers stop-cluster: + @for n in $$(seq $(NODES) -1 1); do \ + nodename="rabbit-$$n@$(HOSTNAME)"; \ + $(MAKE) stop-node \ + RABBITMQ_NODENAME="$$nodename"; \ + done + +# -------------------------------------------------------------------- +# Used by testsuites. +# -------------------------------------------------------------------- + +set-resource-alarm: + $(exec_verbose) ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) \ + eval 'rabbit_alarm:set_alarm({{resource_limit, $(SOURCE), node()}, []}).' + +clear-resource-alarm: + $(exec_verbose) ERL_LIBS="$(DIST_ERL_LIBS)" \ + $(RABBITMQCTL) -n $(RABBITMQ_NODENAME) \ + eval 'rabbit_alarm:clear_alarm({resource_limit, $(SOURCE), node()}).' diff --git a/deps/rabbit_common/mk/rabbitmq-test.mk b/deps/rabbit_common/mk/rabbitmq-test.mk new file mode 100644 index 0000000000..931f072125 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-test.mk @@ -0,0 +1,80 @@ +.PHONY: ct-slow ct-fast + +ct-slow ct-fast: + $(MAKE) ct CT_SUITES='$(CT_SUITES)' + +# -------------------------------------------------------------------- +# xref +# -------------------------------------------------------------------- + +# We need the list of dependencies of the current project. We use it in +# xrefr(1) to scan for Elixir-based projects. For those, we need to add +# the path inside `_build` to the xref code path. + +ifneq ($(filter xref,$(MAKECMDGOALS)),) +export ERLANG_MK_RECURSIVE_DEPS_LIST +endif + +xref: $(ERLANG_MK_RECURSIVE_DEPS_LIST) + +# -------------------------------------------------------------------- +# Helpers to run Make targets on Concourse. +# -------------------------------------------------------------------- + +FLY ?= fly +FLY_TARGET ?= $(shell $(FLY) targets | awk '/ci\.rabbitmq\.com/ { print $$1; }') + +CONCOURSE_TASK = $(ERLANG_MK_TMP)/concourse-task.yaml + +CI_DIR ?= $(DEPS_DIR)/ci +PIPELINE_DIR = $(CI_DIR)/server-release +BRANCH_RELEASE = $(shell "$(PIPELINE_DIR)/scripts/map-branch-to-release.sh" "$(base_rmq_ref)") +PIPELINE_DATA = $(PIPELINE_DIR)/release-data-$(BRANCH_RELEASE).yaml +REPOSITORY_NAME = $(shell "$(PIPELINE_DIR)/scripts/map-erlang-app-and-repository-name.sh" "$(PIPELINE_DATA)" "$(PROJECT)") + +CONCOURSE_PLATFORM ?= linux +ERLANG_VERSION ?= $(shell "$(PIPELINE_DIR)/scripts/list-erlang-versions.sh" "$(PIPELINE_DATA)" | head -n 1) +TASK_INPUTS = $(shell "$(PIPELINE_DIR)/scripts/list-task-inputs.sh" "$(CONCOURSE_TASK)") + +.PHONY: $(CONCOURSE_TASK) +$(CONCOURSE_TASK): $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) + $(gen_verbose) echo 'platform: $(CONCOURSE_PLATFORM)' > "$@" + $(verbose) echo 'inputs:' >> "$@" + $(verbose) echo ' - name: $(PROJECT)' >> "$@" + $(verbose) cat $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) | while read -r file; do \ + echo " - name: $$(basename "$$file")" >> "$@"; \ + done + $(verbose) echo 'outputs:' >> "$@" + $(verbose) echo ' - name: test-output' >> "$@" +ifeq ($(CONCOURSE_PLATFORM),linux) + $(verbose) echo 'image_resource:' >> "$@" + $(verbose) echo ' type: docker-image' >> "$@" + $(verbose) echo ' source:' >> "$@" + $(verbose) echo ' repository: pivotalrabbitmq/rabbitmq-server-buildenv' >> "$@" + $(verbose) echo ' tag: linux-erlang-$(ERLANG_VERSION)' >> "$@" +endif + $(verbose) echo 'run:' >> "$@" + $(verbose) echo ' path: ci/server-release/scripts/test-erlang-app.sh' >> "$@" + $(verbose) echo ' args:' >> "$@" + $(verbose) echo " - $(PROJECT)" >> "$@" +# This section must be the last because the `%-on-concourse` target +# appends other variables. + $(verbose) echo 'params:' >> "$@" +ifdef V + $(verbose) echo ' V: "$(V)"' >> "$@" +endif +ifdef t + $(verbose) echo ' t: "$(t)"' >> "$@" +endif + +%-on-concourse: $(CONCOURSE_TASK) + $(verbose) test -d "$(PIPELINE_DIR)" + $(verbose) echo ' MAKE_TARGET: "$*"' >> "$(CONCOURSE_TASK)" + $(FLY) -t $(FLY_TARGET) execute \ + --config="$(CONCOURSE_TASK)" \ + $(foreach input,$(TASK_INPUTS), \ + $(if $(filter $(PROJECT),$(input)), \ + --input="$(input)=.", \ + --input="$(input)=$(DEPS_DIR)/$(input)")) \ + --output="test-output=$(CT_LOGS_DIR)/on-concourse" + $(verbose) rm -f "$(CT_LOGS_DIR)/on-concourse/filename" diff --git a/deps/rabbit_common/mk/rabbitmq-tools.mk b/deps/rabbit_common/mk/rabbitmq-tools.mk new file mode 100644 index 0000000000..6672153cb0 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-tools.mk @@ -0,0 +1,429 @@ +ifeq ($(PLATFORM),msys2) +HOSTNAME := $(COMPUTERNAME) +else +HOSTNAME := $(shell hostname -s) +endif + +READY_DEPS = $(foreach DEP,\ + $(filter $(RABBITMQ_COMPONENTS),$(DEPS) $(BUILD_DEPS) $(TEST_DEPS)), \ + $(if $(wildcard $(DEPS_DIR)/$(DEP)),$(DEP),)) + +RELEASED_RMQ_DEPS = $(filter $(RABBITMQ_COMPONENTS),$(DEPS) $(BUILD_DEPS)) + +.PHONY: show-upstream-git-fetch-url show-upstream-git-push-url \ + show-current-git-fetch-url show-current-git-push-url + +show-upstream-git-fetch-url: + @echo $(RABBITMQ_UPSTREAM_FETCH_URL) + +show-upstream-git-push-url: + @echo $(RABBITMQ_UPSTREAM_PUSH_URL) + +show-current-git-fetch-url: + @echo $(RABBITMQ_CURRENT_FETCH_URL) + +show-current-git-push-url: + @echo $(RABBITMQ_CURRENT_PUSH_URL) + +.PHONY: update-erlang-mk update-rabbitmq-components.mk + +update-erlang-mk: erlang-mk + $(verbose) if test "$(DO_COMMIT)" = 'yes'; then \ + git diff --quiet -- erlang.mk \ + || git commit -m 'Update erlang.mk' -- erlang.mk; \ + fi + $(verbose) for repo in $(READY_DEPS:%=$(DEPS_DIR)/%); do \ + ! test -f $$repo/erlang.mk \ + || $(MAKE) -C $$repo erlang-mk; \ + if test "$(DO_COMMIT)" = 'yes'; then \ + (cd $$repo; \ + git diff --quiet -- erlang.mk \ + || git commit -m 'Update erlang.mk' -- erlang.mk); \ + fi; \ + done + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +ifeq ($(PROJECT),rabbit_common) +check-rabbitmq-components.mk: + @: +else +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) +endif + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: +ifeq ($(FORCE),yes) + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +else + $(gen_verbose) if test -d .git && test -d $(DEPS_DIR)/rabbit_common/.git; then \ + upstream_branch=$$(LANG=C git -C $(DEPS_DIR)/rabbit_common branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}'); \ + local_branch=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}'); \ + test "$$local_branch" = "$$upstream_branch" || exit 0; \ + fi; \ + cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +endif +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif + +update-rabbitmq-components-mk: rabbitmq-components-mk + $(verbose) for repo in $(READY_DEPS:%=$(DEPS_DIR)/%); do \ + ! test -f $$repo/rabbitmq-components.mk \ + || $(MAKE) -C $$repo rabbitmq-components-mk; \ + done + +update-contributor-code-of-conduct: + $(verbose) for repo in $(READY_DEPS:%=$(DEPS_DIR)/%); do \ + cp $(DEPS_DIR)/rabbit_common/CODE_OF_CONDUCT.md $$repo/CODE_OF_CONDUCT.md; \ + cp $(DEPS_DIR)/rabbit_common/CONTRIBUTING.md $$repo/CONTRIBUTING.md; \ + done + +ifdef CREDS +define replace_aws_creds + set -e; \ + if test -f "$(CREDS)"; then \ + key_id=$(shell travis encrypt --no-interactive \ + "AWS_ACCESS_KEY_ID=$$(awk '/^rabbitmq-s3-access-key-id/ { print $$2; }' < "$(CREDS)")"); \ + access_key=$(shell travis encrypt --no-interactive \ + "AWS_SECRET_ACCESS_KEY=$$(awk '/^rabbitmq-s3-secret-access-key/ { print $$2; }' < "$(CREDS)")"); \ + mv .travis.yml .travis.yml.orig; \ + awk "\ + /^ global:/ { \ + print; \ + print \" - secure: $$key_id\"; \ + print \" - secure: $$access_key\"; \ + next; \ + } \ + /- secure:/ { next; } \ + { print; }" < .travis.yml.orig > .travis.yml; \ + rm -f .travis.yml.orig; \ + else \ + echo " INFO: CREDS file missing; not setting/updating AWS credentials"; \ + fi +endef +else +define replace_aws_creds + echo " INFO: CREDS not set; not setting/updating AWS credentials" +endef +endif + +ifeq ($(PROJECT),rabbit_common) +travis-yml: + $(gen_verbose) $(replace_aws_creds) +else +travis-yml: + $(gen_verbose) \ + set -e; \ + if test -d .git && test -d $(DEPS_DIR)/rabbit_common/.git; then \ + upstream_branch=$$(LANG=C git -C $(DEPS_DIR)/rabbit_common branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}'); \ + local_branch=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}'); \ + test "$$local_branch" = "$$upstream_branch" || exit 0; \ + fi; \ + test -f .travis.yml || exit 0; \ + (grep -E -- '- secure:' .travis.yml || :) > .travis.yml.creds; \ + cp -a $(DEPS_DIR)/rabbit_common/.travis.yml .travis.yml.orig; \ + awk ' \ + /^ global:/ { \ + print; \ + system("test -f .travis.yml.creds && cat .travis.yml.creds"); \ + next; \ + } \ + /- secure:/ { next; } \ + { print; } \ + ' < .travis.yml.orig > .travis.yml; \ + rm -f .travis.yml.orig .travis.yml.creds; \ + if test -f .travis.yml.patch; then \ + patch -p0 < .travis.yml.patch; \ + rm -f .travis.yml.orig; \ + fi; \ + $(replace_aws_creds) +ifeq ($(DO_COMMIT),yes) + $(verbose) ! test -f .travis.yml || \ + git diff --quiet .travis.yml \ + || git commit -m 'Travis CI: Update config from rabbitmq-common' .travis.yml +endif +endif + +update-travis-yml: travis-yml + $(verbose) for repo in $(READY_DEPS:%=$(DEPS_DIR)/%); do \ + ! test -f $$repo/rabbitmq-components.mk \ + || $(MAKE) -C $$repo travis-yml; \ + done + +ifneq ($(wildcard .git),) + +.PHONY: sync-gitremote sync-gituser + +sync-gitremote: $(READY_DEPS:%=$(DEPS_DIR)/%+sync-gitremote) + @: + +%+sync-gitremote: + $(exec_verbose) cd $* && \ + git remote set-url origin \ + '$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(notdir $*))' + $(verbose) cd $* && \ + git remote set-url --push origin \ + '$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(notdir $*))' + +ifeq ($(origin, RMQ_GIT_GLOBAL_USER_NAME),undefined) +RMQ_GIT_GLOBAL_USER_NAME := $(shell git config --global user.name) +export RMQ_GIT_GLOBAL_USER_NAME +endif +ifeq ($(origin RMQ_GIT_GLOBAL_USER_EMAIL),undefined) +RMQ_GIT_GLOBAL_USER_EMAIL := $(shell git config --global user.email) +export RMQ_GIT_GLOBAL_USER_EMAIL +endif +ifeq ($(origin RMQ_GIT_USER_NAME),undefined) +RMQ_GIT_USER_NAME := $(shell git config user.name) +export RMQ_GIT_USER_NAME +endif +ifeq ($(origin RMQ_GIT_USER_EMAIL),undefined) +RMQ_GIT_USER_EMAIL := $(shell git config user.email) +export RMQ_GIT_USER_EMAIL +endif + +sync-gituser: $(READY_DEPS:%=$(DEPS_DIR)/%+sync-gituser) + @: + +%+sync-gituser: +ifeq ($(RMQ_GIT_USER_NAME),$(RMQ_GIT_GLOBAL_USER_NAME)) + $(exec_verbose) cd $* && git config --unset user.name || : +else + $(exec_verbose) cd $* && git config user.name "$(RMQ_GIT_USER_NAME)" +endif +ifeq ($(RMQ_GIT_USER_EMAIL),$(RMQ_GIT_GLOBAL_USER_EMAIL)) + $(verbose) cd $* && git config --unset user.email || : +else + $(verbose) cd $* && git config user.email "$(RMQ_GIT_USER_EMAIL)" +endif + +.PHONY: sync-gitignore-from-master +sync-gitignore-from-master: $(READY_DEPS:%=$(DEPS_DIR)/%+sync-gitignore-from-master) + +%+sync-gitignore-from-master: + $(gen_verbose) cd $* && \ + if test -d .git; then \ + branch=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}'); \ + ! test "$$branch" = 'master' || exit 0; \ + git show origin/master:.gitignore > .gitignore; \ + fi +ifeq ($(DO_COMMIT),yes) + $(verbose) cd $* && \ + if test -d .git; then \ + git diff --quiet .gitignore \ + || git commit -m 'Git: Sync .gitignore from master' .gitignore; \ + fi +endif + +.PHONY: show-branch + +show-branch: $(READY_DEPS:%=$(DEPS_DIR)/%+show-branch) + $(verbose) printf '%-34s %s\n' $(PROJECT): "$$(git symbolic-ref -q --short HEAD || git describe --tags --exact-match)" + +%+show-branch: + $(verbose) printf '%-34s %s\n' $(notdir $*): "$$(cd $* && (git symbolic-ref -q --short HEAD || git describe --tags --exact-match))" + +SINCE_TAG ?= last-release +COMMITS_LOG_OPTS ?= --oneline --decorate --no-merges +MARKDOWN ?= no + +define show_commits_since_tag +set -e; \ +if test "$1"; then \ + erlang_app=$(notdir $1); \ + repository=$(call rmq_cmp_repo_name,$(notdir $1)); \ + git_dir=-C\ "$1"; \ +else \ + erlang_app=$(PROJECT); \ + repository=$(call rmq_cmp_repo_name,$(PROJECT)); \ +fi; \ +case "$(SINCE_TAG)" in \ +last-release) \ + tags_count=$$(git $$git_dir tag -l 2>/dev/null | grep -E -v '(-beta|_milestone|[-_]rc)' | wc -l); \ + ;; \ +*) \ + tags_count=$$(git $$git_dir tag -l 2>/dev/null | wc -l); \ + ;; \ +esac; \ +if test "$$tags_count" -gt 0; then \ + case "$(SINCE_TAG)" in \ + last-release) \ + ref=$$(git $$git_dir describe --abbrev=0 --tags \ + --exclude "*-beta*" \ + --exclude "*_milestone*" \ + --exclude "*[-_]rc*"); \ + ;; \ + last-prerelease) \ + ref=$$(git $$git_dir describe --abbrev=0 --tags); \ + ;; \ + *) \ + git $$git_dir rev-parse "$(SINCE_TAG)" -- >/dev/null; \ + ref=$(SINCE_TAG); \ + ;; \ + esac; \ + commits_count=$$(git $$git_dir log --oneline "$$ref.." | wc -l); \ + if test "$$commits_count" -gt 0; then \ + if test "$(MARKDOWN)" = yes; then \ + printf "\n## [\`$$repository\`](https://github.com/rabbitmq/$$repository)\n\nCommits since \`$$ref\`:\n\n"; \ + git $$git_dir --no-pager log $(COMMITS_LOG_OPTS) \ + --format="format:* %s ([\`%h\`](https://github.com/rabbitmq/$$repository/commit/%H))" \ + "$$ref.."; \ + echo; \ + else \ + echo; \ + echo "# $$repository - Commits since $$ref"; \ + git $$git_dir log $(COMMITS_LOG_OPTS) "$$ref.."; \ + fi; \ + fi; \ +else \ + if test "$(MARKDOWN)" = yes; then \ + printf "\n## [\`$$repository\`](https://github.com/rabbitmq/$$repository)\n\n**New** since the last release!\n"; \ + else \ + echo; \ + echo "# $$repository - New since the last release!"; \ + fi; \ +fi +endef + +.PHONY: commits-since-release + +commits-since-release: commits-since-release-title \ + $(RELEASED_RMQ_DEPS:%=$(DEPS_DIR)/%+commits-since-release) + $(verbose) $(call show_commits_since_tag) + +commits-since-release-title: + $(verbose) set -e; \ + case "$(SINCE_TAG)" in \ + last-release) \ + tags_count=$$(git $$git_dir tag -l 2>/dev/null | grep -E -v '(-beta|_milestone|[-_]rc)' | wc -l); \ + ;; \ + *) \ + tags_count=$$(git $$git_dir tag -l 2>/dev/null | wc -l); \ + ;; \ + esac; \ + if test "$$tags_count" -gt 0; then \ + case "$(SINCE_TAG)" in \ + last-release) \ + ref=$$(git $$git_dir describe --abbrev=0 --tags \ + --exclude "*-beta*" \ + --exclude "*_milestone*" \ + --exclude "*[-_]rc*"); \ + ;; \ + last-prerelease) \ + ref=$$(git $$git_dir describe --abbrev=0 --tags); \ + ;; \ + *) \ + ref=$(SINCE_TAG); \ + ;; \ + esac; \ + version=$$(echo "$$ref" | sed -E \ + -e 's/rabbitmq_v([0-9]+)_([0-9]+)_([0-9]+)/v\1.\2.\3/' \ + -e 's/_milestone/-beta./' \ + -e 's/_rc/-rc./' \ + -e 's/^v//'); \ + echo "# Changes since RabbitMQ $$version"; \ + else \ + echo "# Changes since the beginning of time"; \ + fi + +%+commits-since-release: + $(verbose) $(call show_commits_since_tag,$*) + +endif # ($(wildcard .git),) + +# -------------------------------------------------------------------- +# erlang.mk query-deps* formatting. +# -------------------------------------------------------------------- + +# We need to provide a repo mapping for deps resolved via git_rmq fetch method +query_repo_git_rmq = https://github.com/rabbitmq/$(call rmq_cmp_repo_name,$(1)) + +# -------------------------------------------------------------------- +# Common test logs compression. +# -------------------------------------------------------------------- + +.PHONY: ct-logs-archive clean-ct-logs-archive + +ifneq ($(wildcard logs/*),) +TAR := tar +ifeq ($(PLATFORM),freebsd) +TAR := gtar +endif +ifeq ($(PLATFORM),darwin) +TAR := gtar +endif + +CT_LOGS_ARCHIVE ?= $(PROJECT)-ct-logs-$(subst _,-,$(subst -,,$(subst .,,$(patsubst ct_run.ct_$(PROJECT)@$(HOSTNAME).%,%,$(notdir $(lastword $(wildcard logs/ct_run.*))))))).tar.xz + +ifeq ($(patsubst %.tar.xz,%,$(CT_LOGS_ARCHIVE)),$(CT_LOGS_ARCHIVE)) +$(error CT_LOGS_ARCHIVE file must use '.tar.xz' as its filename extension) +endif + +ct-logs-archive: $(CT_LOGS_ARCHIVE) + @: + +$(CT_LOGS_ARCHIVE): + $(gen_verbose) \ + for file in logs/*; do \ + ! test -L "$$file" || rm "$$file"; \ + done + $(verbose) \ + $(TAR) -c \ + --exclude "*/mnesia" \ + --transform "s/^logs/$(patsubst %.tar.xz,%,$(notdir $(CT_LOGS_ARCHIVE)))/" \ + -f - logs | \ + xz > "$@" +else +ct-logs-archive: + @: +endif + +clean-ct-logs-archive:: + $(gen_verbose) rm -f $(PROJECT)-ct-logs-*.tar.xz + +clean:: clean-ct-logs-archive + +# -------------------------------------------------------------------- +# Generate a file listing RabbitMQ component dependencies and their +# Git commit hash. +# -------------------------------------------------------------------- + +.PHONY: rabbitmq-deps.mk clean-rabbitmq-deps.mk + +rabbitmq-deps.mk: $(PROJECT)-rabbitmq-deps.mk + @: + +closing_paren := ) + +define rmq_deps_mk_line +dep_$(1) := git $(dir $(RABBITMQ_UPSTREAM_FETCH_URL))$(call rmq_cmp_repo_name,$(1)).git $$(git -C "$(2)" rev-parse HEAD) +endef + +$(PROJECT)-rabbitmq-deps.mk: $(ERLANG_MK_RECURSIVE_DEPS_LIST) + $(gen_verbose) echo "# In $(PROJECT) - commit $$(git rev-parse HEAD)" > $@ + $(verbose) cat $(ERLANG_MK_RECURSIVE_DEPS_LIST) | \ + while read -r dir; do \ + component=$$(basename "$$dir"); \ + case "$$component" in \ + $(foreach component,$(RABBITMQ_COMPONENTS),$(component)$(closing_paren) echo "$(call rmq_deps_mk_line,$(component),$$dir)" ;;) \ + esac; \ + done >> $@ + +clean:: clean-rabbitmq-deps.mk + +clean-rabbitmq-deps.mk: + $(gen_verbose) rm -f $(PROJECT)-rabbitmq-deps.mk diff --git a/deps/rabbit_common/mk/xrefr b/deps/rabbit_common/mk/xrefr new file mode 100755 index 0000000000..03c408fcb4 --- /dev/null +++ b/deps/rabbit_common/mk/xrefr @@ -0,0 +1,338 @@ +#!/usr/bin/env escript +%% vim:ft=erlang: + +%% The code is copied from xref_runner. +%% https://github.com/inaka/xref_runner +%% +%% The only change is the support of our erlang_version_support +%% attribute: we don't want any warnings about functions which will be +%% dropped at load time. +%% +%% It's also a plain text escript instead of a compiled one because we +%% want to support Erlang R16B03 and the version of xref_runner uses +%% maps and is built with something like Erlang 18. + +%% This mode allows us to reference local function. For instance: +%% lists:map(fun generate_comment/1, Comments) +-mode(compile). + +-define(DIRS, ["ebin", "test"]). + +-define(CHECKS, [undefined_function_calls, + undefined_functions, + locals_not_used]). + +main(_) -> + Checks = ?CHECKS, + ElixirDeps = get_elixir_deps_paths(), + [true = code:add_path(P) || P <- ElixirDeps], + XrefWarnings = lists:append([check(Check) || Check <- Checks]), + warnings_prn(XrefWarnings), + case XrefWarnings of + [] -> ok; + _ -> halt(1) + end. + +get_elixir_deps_paths() -> + case os:getenv("ERLANG_MK_RECURSIVE_DEPS_LIST") of + false -> + []; + Filename -> + {ok, Fd} = file:open(Filename, [read]), + get_elixir_deps_paths1(Fd, []) + end. + +get_elixir_deps_paths1(Fd, Paths) -> + case file:read_line(Fd) of + {ok, Line0} -> + Line = Line0 -- [$\r, $\n], + RootPath = case os:type() of + {unix, _} -> + Line; + {win32, _} -> + case os:find_executable("cygpath.exe") of + false -> + Line; + Cygpath -> + os:cmd( + io_lib:format("~s --windows \"~s\"", + [Cygpath, Line])) + -- [$\r, $\n] + end + end, + Glob = filename:join([RootPath, "_build", "dev", "lib", "*", "ebin"]), + NewPaths = filelib:wildcard(Glob), + get_elixir_deps_paths1(Fd, Paths ++ NewPaths); + eof -> + add_elixir_stdlib_path(Paths) + end. + +add_elixir_stdlib_path(Paths) -> + case find_elixir_home() of + false -> Paths; + ElixirLibDir -> [ElixirLibDir | Paths] + end. + +find_elixir_home() -> + ElixirExe = case os:type() of + {unix, _} -> "elixir"; + {win32, _} -> "elixir.bat" + end, + case os:find_executable(ElixirExe) of + false -> false; + ExePath -> resolve_symlink(ExePath) + end. + +resolve_symlink(ExePath) -> + case file:read_link_all(ExePath) of + {error, einval} -> + determine_elixir_home(ExePath); + {ok, ResolvedLink} -> + ExePath1 = filename:absname(ResolvedLink, + filename:dirname(ExePath)), + resolve_symlink(ExePath1); + {error, _} -> + false + end. + +determine_elixir_home(ExePath) -> + LibPath = filename:join([filename:dirname(filename:dirname(ExePath)), + "lib", + "elixir", + "ebin"]), + case filelib:is_dir(LibPath) of + true -> LibPath; + false -> {skip, "Failed to locate Elixir lib dir"} + end. +check(Check) -> + Dirs = ?DIRS, + lists:foreach(fun code:add_path/1, Dirs), + + {ok, Xref} = xref:start([]), + try + ok = xref:set_library_path(Xref, code:get_path()), + + lists:foreach( + fun(Dir) -> + case filelib:is_dir(Dir) of + true -> {ok, _} = xref:add_directory(Xref, Dir); + false -> ok + end + end, Dirs), + + {ok, Results} = xref:analyze(Xref, Check), + + FilteredResults = filter_xref_results(Check, Results), + + [result_to_warning(Check, Result) || Result <- FilteredResults] + after + stopped = xref:stop(Xref) + end. + +%% ------------------------------------------------------------------- +%% Filtering results. +%% ------------------------------------------------------------------- + +filter_xref_results(Check, Results) -> + SourceModules = + lists:usort([source_module(Result) || Result <- Results]), + + Ignores = lists:flatmap( + fun(Module) -> get_ignorelist(Module, Check) end, SourceModules), + + UnusedFunctions = lists:flatmap( + fun(Mod) -> get_unused_compat_functions(Mod) end, + SourceModules), + + ToIgnore = case get(results_to_ignore) of + undefined -> []; + RTI -> RTI + end, + NewToIgnore = [parse_xref_target(Result) + || Result <- Results, + lists:member(parse_xref_source(Result), UnusedFunctions)], + AllToIgnore = ToIgnore ++ NewToIgnore ++ [mfa(M, {F, A}) + || {_, {M, F, A}} <- Ignores], + put(results_to_ignore, AllToIgnore), + + [Result || Result <- Results, + not lists:member(parse_xref_result(Result), Ignores) andalso + not lists:member(parse_xref_result(Result), AllToIgnore) andalso + not lists:member(parse_xref_source(Result), UnusedFunctions)]. + +source_module({Mt, _Ft, _At}) -> Mt; +source_module({{Ms, _Fs, _As}, _Target}) -> Ms. + +%% +%% Ignore behaviour functions, and explicitly marked functions +%% +%% Functions can be ignored by using +%% -ignore_xref([{F, A}, {M, F, A}...]). +get_ignorelist(Mod, Check) -> + %% Get ignore_xref attribute and combine them in one list + Attributes = + try + Mod:module_info(attributes) + catch + _Class:_Error -> [] + end, + + IgnoreXref = + [mfa(Mod, Value) || {ignore_xref, Values} <- Attributes, Value <- Values], + + BehaviourCallbacks = get_behaviour_callbacks(Check, Mod, Attributes), + + %% And create a flat {M, F, A} list + IgnoreXref ++ BehaviourCallbacks. + +get_behaviour_callbacks(exports_not_used, Mod, Attributes) -> + Behaviours = [Value || {behaviour, Values} <- Attributes, Value <- Values], + [{Mod, {Mod, F, A}} + || B <- Behaviours, {F, A} <- B:behaviour_info(callbacks)]; +get_behaviour_callbacks(_Check, _Mod, _Attributes) -> + []. + +get_unused_compat_functions(Module) -> + OTPVersion = code_version:get_otp_version(), + Attributes = try + Module:module_info(attributes) + catch + _Class:_Error -> [] + end, + CompatTuples = [Tuple + || {erlang_version_support, Tuples} <- Attributes, + Tuple <- Tuples], + get_unused_compat_functions(Module, OTPVersion, CompatTuples, []). + +get_unused_compat_functions(_, _, [], Result) -> + Result; +get_unused_compat_functions(Module, + OTPVersion, + [{MinOTPVersion, Choices} | Rest], + Result) -> + Functions = lists:map( + fun({_, Arity, Pre, Post}) -> + if + OTPVersion >= MinOTPVersion -> + %% We ignore the "pre" function. + mfa(Module, {Pre, Arity}); + true -> + %% We ignore the "post" function. + mfa(Module, {Post, Arity}) + end + end, Choices), + get_unused_compat_functions(Module, OTPVersion, Rest, + Result ++ Functions). + +mfa(M, {F, A}) -> {M, {M, F, A}}; +mfa(M, MFA) -> {M, MFA}. + +parse_xref_result({{SM, _, _}, MFAt}) -> {SM, MFAt}; +parse_xref_result({TM, _, _} = MFAt) -> {TM, MFAt}. + +parse_xref_source({{SM, _, _} = MFAt, _}) -> {SM, MFAt}; +parse_xref_source({TM, _, _} = MFAt) -> {TM, MFAt}. + +parse_xref_target({_, {TM, _, _} = MFAt}) -> {TM, MFAt}; +parse_xref_target({TM, _, _} = MFAt) -> {TM, MFAt}. + +%% ------------------------------------------------------------------- +%% Preparing results. +%% ------------------------------------------------------------------- + +result_to_warning(Check, {MFASource, MFATarget}) -> + {Filename, Line} = get_source(MFASource), + [{filename, Filename}, + {line, Line}, + {source, MFASource}, + {target, MFATarget}, + {check, Check}]; +result_to_warning(Check, MFA) -> + {Filename, Line} = get_source(MFA), + [{filename, Filename}, + {line, Line}, + {source, MFA}, + {check, Check}]. + +%% +%% Given a MFA, find the file and LOC where it's defined. Note that +%% xref doesn't work if there is no abstract_code, so we can avoid +%% being too paranoid here. +%% +get_source({M, F, A}) -> + case code:get_object_code(M) of + error -> {"", 0}; + {M, Bin, _} -> find_function_source(M, F, A, Bin) + end. + +find_function_source(M, F, A, Bin) -> + AbstractCode = beam_lib:chunks(Bin, [abstract_code]), + {ok, {M, [{abstract_code, {raw_abstract_v1, Code}}]}} = AbstractCode, + + %% Extract the original source filename from the abstract code + [Source|_] = [S || {attribute, _, file, {S, _}} <- Code], + + %% Extract the line number for a given function def + Fn = [E || E <- Code, + element(1, E) == function, + element(3, E) == F, + element(4, E) == A], + + case Fn of + [{function, Line, F, _, _}] when is_integer(Line) -> + {Source, Line}; + [{function, Line, F, _, _}] -> + {Source, erl_anno:line(Line)}; + %% do not crash if functions are exported, even though they + %% are not in the source. + %% parameterized modules add new/1 and instance/1 for example. + [] -> {Source, 0} + end. + +%% ------------------------------------------------------------------- +%% Reporting results. +%% ------------------------------------------------------------------- + +warnings_prn([]) -> + ok; +warnings_prn(Comments) -> + Messages = lists:map(fun generate_comment/1, Comments), + lists:foreach(fun warning_prn/1, Messages). + +warning_prn(Message) -> + FullMessage = Message ++ "~n", + io:format(FullMessage, []). + +generate_comment(XrefWarning) -> + Filename = proplists:get_value(filename, XrefWarning), + Line = proplists:get_value(line, XrefWarning), + Source = proplists:get_value(source, XrefWarning), + Check = proplists:get_value(check, XrefWarning), + Target = proplists:get_value(target, XrefWarning), + Position = case {Filename, Line} of + {"", _} -> ""; + {Filename, 0} -> [Filename, " "]; + {Filename, Line} -> [Filename, ":", + integer_to_list(Line), " "] + end, + [Position, generate_comment_text(Check, Source, Target)]. + +generate_comment_text(Check, {SM, SF, SA}, TMFA) -> + SMFA = io_lib:format("`~p:~p/~p`", [SM, SF, SA]), + generate_comment_text(Check, SMFA, TMFA); +generate_comment_text(Check, SMFA, {TM, TF, TA}) -> + TMFA = io_lib:format("`~p:~p/~p`", [TM, TF, TA]), + generate_comment_text(Check, SMFA, TMFA); + +generate_comment_text(undefined_function_calls, SMFA, TMFA) -> + io_lib:format("~s calls undefined function ~s", [SMFA, TMFA]); +generate_comment_text(undefined_functions, SMFA, _TMFA) -> + io_lib:format("~s is not defined as a function", [SMFA]); +generate_comment_text(locals_not_used, SMFA, _TMFA) -> + io_lib:format("~s is an unused local function", [SMFA]); +generate_comment_text(exports_not_used, SMFA, _TMFA) -> + io_lib:format("~s is an unused export", [SMFA]); +generate_comment_text(deprecated_function_calls, SMFA, TMFA) -> + io_lib:format("~s calls deprecated function ~s", [SMFA, TMFA]); +generate_comment_text(deprecated_functions, SMFA, _TMFA) -> + io_lib:format("~s is deprecated", [SMFA]). |