Description: Add common build structure needed by all rabbitmq plugins
Author: Brian Thomason <brian.thomason@canonical.com>

--- /dev/null
+++ rabbitmq-stomp-2.5.0+hg20110623/common/generate_deps
@@ -0,0 +1,61 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+-mode(compile).
+
+%% We expect the list of Erlang source and header files to arrive on
+%% stdin, with the entries colon-separated.
+main([TargetFile, EbinDir]) ->
+    ErlsAndHrls = [ string:strip(S,left) ||
+                      S <- string:tokens(io:get_line(""), ":\n")],
+    ErlFiles = [F || F <- ErlsAndHrls, lists:suffix(".erl", F)],
+    Modules = sets:from_list(
+                [list_to_atom(filename:basename(FileName, ".erl")) ||
+                    FileName <- ErlFiles]),
+    HrlFiles = [F || F <- ErlsAndHrls, lists:suffix(".hrl", F)],
+    IncludeDirs = lists:usort([filename:dirname(Path) || Path <- HrlFiles]),
+    Headers = sets:from_list(HrlFiles),
+    Deps = lists:foldl(
+             fun (Path, Deps1) ->
+                     dict:store(Path, detect_deps(IncludeDirs, EbinDir,
+                                                  Modules, Headers, Path),
+                                Deps1)
+             end, dict:new(), ErlFiles),
+    {ok, Hdl} = file:open(TargetFile, [write, delayed_write]),
+    dict:fold(
+      fun (_Path, [], ok) ->
+              ok;
+          (Path, Dep, ok) ->
+              Module = filename:basename(Path, ".erl"),
+              ok = file:write(Hdl, [EbinDir, "/", Module, ".beam: ",
+                                   Path]),
+              ok = sets:fold(fun (E, ok) -> file:write(Hdl, [" ", E]) end,
+                             ok, Dep),
+              file:write(Hdl, ["\n"])
+      end, ok, Deps),
+    ok = file:write(Hdl, [TargetFile, ": ", escript:script_name(), "\n"]),
+    ok = file:sync(Hdl),
+    ok = file:close(Hdl).
+
+detect_deps(IncludeDirs, EbinDir, Modules, Headers, Path) ->
+    {ok, Forms} = epp:parse_file(Path, IncludeDirs, [{use_specs, true}]),
+    lists:foldl(
+      fun ({attribute, _Line, Attribute, Behaviour}, Deps)
+          when Attribute =:= behaviour orelse Attribute =:= behavior ->
+              maybe_add_to_deps(EbinDir, Modules, Behaviour, Deps);
+          ({attribute, _Line, compile, {parse_transform, Transform}}, Deps) ->
+              maybe_add_to_deps(EbinDir, Modules, Transform, Deps);
+          ({attribute, _Line, file, {FileName, _LineNumber1}}, Deps) ->
+              case sets:is_element(FileName, Headers) of
+                  true  -> sets:add_element(FileName, Deps);
+                  false -> Deps
+              end;
+          (_Form, Deps) ->
+              Deps
+      end, sets:new(), Forms).
+
+maybe_add_to_deps(EbinDir, Modules, Module, Deps) ->
+    case sets:is_element(Module, Modules) of
+        true  -> sets:add_element(
+                   [EbinDir, "/", atom_to_list(Module), ".beam"], Deps);
+        false -> Deps
+    end.
--- /dev/null
+++ rabbitmq-stomp-2.5.0+hg20110623/common/generate_app
@@ -0,0 +1,16 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+main([InFile, OutFile | SrcDirs]) ->
+    Modules = [list_to_atom(filename:basename(F, ".erl")) ||
+                  SrcDir <- SrcDirs,
+                  F <- filelib:wildcard("*.erl", SrcDir)],
+    {ok, [{application, Application, Properties}]} = file:consult(InFile),
+    NewProperties =
+        case proplists:get_value(modules, Properties) of
+            [] -> lists:keyreplace(modules, 1, Properties, {modules, Modules});
+            _  -> Properties
+        end,
+    file:write_file(
+      OutFile,
+      io_lib:format("~p.~n", [{application, Application, NewProperties}])).
--- /dev/null
+++ rabbitmq-stomp-2.5.0+hg20110623/common/umbrella.mk
@@ -0,0 +1,47 @@
+# The default goal
+dist:
+
+UMBRELLA_BASE_DIR:=./common
+
+include $(UMBRELLA_BASE_DIR)/common.mk
+
+# We start at the initial package (i.e. the one in the current directory)
+PACKAGE_DIR:=$(call canonical_path,.)
+
+# Produce all of the releasable artifacts of this package
+.PHONY: dist
+dist: $(PACKAGE_DIR)+dist
+
+# Clean the package and all its dependencies
+.PHONY: clean
+clean: $(PACKAGE_DIR)+clean-with-deps
+
+# Clean just the initial package
+.PHONY: clean-local
+clean-local: $(PACKAGE_DIR)+clean
+
+# Run erlang with the package, its tests, and all its dependencies
+# available.
+.PHONY: run
+run: $(PACKAGE_DIR)+run
+
+# Run the broker with the package, its tests, and all its dependencies
+# available.
+.PHONY: run-in-broker
+run-in-broker: $(PACKAGE_DIR)+run-in-broker
+
+# Runs the package's tests
+.PHONY: test
+test: $(PACKAGE_DIR)+test
+
+# Test the package with code coverage recording on.  Note that
+# coverage only covers the in-broker tests.
+.PHONY: coverage
+coverage: $(PACKAGE_DIR)+coverage
+
+# Do the initial package
+include $(UMBRELLA_BASE_DIR)/do-package.mk
+
+# We always need the coverage package to support the coverage goal
+PACKAGE_DIR:=$(COVERAGE_PATH)
+$(eval $(call do_package,$(COVERAGE_PATH)))
--- /dev/null
+++ rabbitmq-stomp-2.5.0+hg20110623/common/common.mk
@@ -0,0 +1,139 @@
+# Various global definitions
+
+# UMBRELLA_BASE_DIR should be set to the path of the
+# rabbitmq-public-umbrella directory before this file is included.
+
+# Make version check
+REQUIRED_MAKE_VERSION:=3.81
+ifneq ($(shell ( echo "$(MAKE_VERSION)" ; echo "$(REQUIRED_MAKE_VERSION)" ) | sort -t. -n | head -1),$(REQUIRED_MAKE_VERSION))
+$(error GNU make version $(REQUIRED_MAKE_VERSION) required)
+endif
+
+# This is the standard trick for making pattern substitution work
+# (amongst others) when the replacement needs to include a comma.
+COMMA:=,
+
+# Global settings that can be overridden on the command line
+
+# These ones are expected to be passed down to the sub-makes invoked
+# for non-integrated packages
+VERSION ?= 2.5.0
+ERL ?= erl
+ERL_OPTS ?=
+ERLC ?= erlc
+ERLC_OPTS ?= -Wall +debug_info
+TMPDIR ?= /tmp
+
+NODENAME ?= rabbit-test
+ERL_CALL ?= erl_call
+ERL_CALL_OPTS ?= -sname $(NODENAME) -e
+
+# Where we put all the files produced when running tests.
+TEST_TMPDIR=$(TMPDIR)/rabbitmq-test
+
+# Callable functions
+
+# Convert a package name to the corresponding erlang app name
+define package_to_app_name
+$(subst -,_,$(1))
+endef
+
+# If the variable named $(1) holds a non-empty value, return it.
+# Otherwise, set the variable to $(2) and return that value.
+define memoize
+$(if $($(1)),$($(1)),$(eval $(1):=$(2))$(2))
+endef
+
+# Return a canonical form for the path in $(1)
+#
+# Absolute path names can be a bit verbose.  This provides a way to
+# canonicalize path names with more concise results.
+define canonical_path
+$(call memoize,SHORT_$(realpath $(1)),$(1))
+endef
+
+# Convert a package name to a path name
+define package_to_path
+$(call canonical_path,$(UMBRELLA_BASE_DIR)/$(1))
+endef
+
+# Produce a cp command to copy from $(1) to $(2), unless $(1) is
+# empty, in which case do nothing.
+#
+# The optional $(3) gives a suffix to append to the command, if a
+# command is produced.
+define copy
+$(if $(1),cp -r $(1) $(2)$(if $(3), $(3)))
+endef
+
+# Produce the makefile fragment for the package with path in $(1), if
+# it hasn't already been visited.  The path should have been
+# canonicalized via canonical_path.
+define do_package
+# Have we already visited this package?  If so, skip it
+ifndef DONE_$(1)
+PACKAGE_DIR:=$(1)
+include $(UMBRELLA_BASE_DIR)/do-package.mk
+endif
+endef
+
+# This is used to chain test rules, so that test-all-packages works in
+# the presence of 'make -j'
+define chain_test
+$(if $(CHAIN_TESTS),$(CHAINED_TESTS)$(eval CHAINED_TESTS+=$(1)))
+endef
+
+# Mark the non-integrated repos
+NON_INTEGRATED_$(call package_to_path,rabbitmq-server):=true
+NON_INTEGRATED_$(call package_to_path,rabbitmq-erlang-client):=true
+NON_INTEGRATED_DEPS_$(call package_to_path,rabbitmq-erlang-client):=rabbitmq-server
+
+# Where the coverage package lives
+COVERAGE_PATH:=$(call package_to_path,coverage)
+
+# Where the rabbitmq-server package lives
+RABBITMQ_SERVER_PATH=$(call package_to_path,rabbitmq-server)
+
+# Cleaning support
+ifndef MAKECMDGOALS
+TESTABLEGOALS:=$(.DEFAULT_GOAL)
+else
+TESTABLEGOALS:=$(MAKECMDGOALS)
+endif
+
+# The CLEANING variable can be used to determine whether the top-level
+# goal is cleaning related.  In particular, it can be used to prevent
+# including generated files when cleaning, which might otherwise
+# trigger undesirable activity.
+ifeq "$(strip $(patsubst clean%,,$(patsubst %clean,,$(TESTABLEGOALS))))" ""
+CLEANING:=true
+endif
+
+# Include a generated makefile fragment
+#
+# Note that this includes using "-include", and thus make will proceed
+# even if an error occurs while the fragment is being re-made (we
+# don't use "include" becuase it will produce a superfluous error
+# message when the fragment is re-made because it doesn't exist).
+# Thus you should also list the fragment as a dependency of any rules
+# that will refer to the contents of the fragment.
+define safe_include
+ifndef CLEANING
+-include $(1)
+
+# If we fail to make the fragment, make will just loop trying to
+# create it.  So we have to explicitly catch that case.
+$$(if $$(MAKE_RESTARTS),$$(if $$(wildcard $(1)),,$$(error Failed to produce $(1))))
+
+endif
+endef
+
+# This is not the make default, but it is a good idea
+.DELETE_ON_ERROR:
+
+# Declarations for global targets
+.PHONY: all-releasable copy-releasable all-packages clean-all-packages
+all-releasable::
+copy-releasable::
+all-packages::
+clean-all-packages::
--- /dev/null
+++ rabbitmq-stomp-2.5.0+hg20110623/common/do-package.mk
@@ -0,0 +1,507 @@
+# This file produces the makefile fragment associated with a package.
+# It includes the package's package.mk, interprets all of the
+# variables that package.mk might have set, and then visits any
+# dependencies of the package that have not already been visited.
+#
+# PACKAGE_DIR should be set to the canonical path of the package.
+
+# Mark that this package has been visited, so we can avoid doing it again
+DONE_$(PACKAGE_DIR):=true
+
+# Declare the standard per-package targets
+.PHONY: $(PACKAGE_DIR)+dist $(PACKAGE_DIR)+clean $(PACKAGE_DIR)+clean-recursive
+
+$(PACKAGE_DIR)+dist:: $(PACKAGE_DIR)/dist/.done
+
+$(PACKAGE_DIR)+clean::
+
+$(PACKAGE_DIR)+clean-with-deps:: $(PACKAGE_DIR)+clean
+
+# Hook into the "all package" targets used by the main public-umbrella
+# makefile
+all-packages:: $(PACKAGE_DIR)/dist/.done
+clean-all-packages:: $(PACKAGE_DIR)+clean
+
+ifndef NON_INTEGRATED_$(PACKAGE_DIR)
+
+PACKAGE_NAME=$(notdir $(abspath $(PACKAGE_DIR)))
+
+# Set all the per-package vars to their default values
+
+# The packages upon which this package depends
+DEPS:=
+
+# The name of the erlang application produced by the package
+#APP_NAME=$(call package_to_app_name,$(PACKAGE_NAME))
+APP_NAME=rabbitmq_stomp
+
+# The location of the .app file which is used as the basis for the
+# .app file which goes into the .ez
+ORIGINAL_APP_FILE=$(EBIN_DIR)/$(APP_NAME).app
+
+# The location of the source for that file (before the modules list is
+# generated). Ignored if DO_NOT_GENERATE_APP_FILE is set.
+ORIGINAL_APP_SOURCE=$(EBIN_DIR)/$(APP_NAME).app.in
+
+# Set to prevent generation of the app file.
+DO_NOT_GENERATE_APP_FILE:=
+
+# Should the .ez files for this package and its dependencies be
+# included in RabbitMQ releases?
+RELEASABLE:=
+
+# The options to pass to erlc when compiling .erl files in this
+# package
+PACKAGE_ERLC_OPTS=$(ERLC_OPTS)
+
+# The directories containing Erlang source files
+SOURCE_DIRS:=$(PACKAGE_DIR)/src
+
+# The Erlang source files to compile and include in the package .ez file
+SOURCE_ERLS=$(strip $(foreach D,$(SOURCE_DIRS),$(wildcard $(D)/*.erl)))
+
+# The directories containing Erlang *.hrl files to include in the
+# package .ez file.
+INCLUDE_DIRS:=$(PACKAGE_DIR)/include
+
+# The Erlang .hrl files to include in the package .ez file.
+INCLUDE_HRLS=$(strip $(foreach D,$(INCLUDE_DIRS),$(wildcard $(D)/*.hrl)))
+
+# The location of the directory containing the .app file.  This is
+# also where the .beam files produced by compiling SOURCE_ERLS will
+# go.
+EBIN_DIR:=$(PACKAGE_DIR)/ebin
+
+# The .beam files for the application.
+EBIN_BEAMS=$(patsubst %,$(EBIN_DIR)/%.beam,$(notdir $(basename $(SOURCE_ERLS))))
+
+# Erlang expressions which will be invoked during testing (not in the
+# broker).
+STANDALONE_TEST_COMMANDS:=
+
+# Erlang expressions which will be invoked within the broker during
+# testing.
+WITH_BROKER_TEST_COMMANDS:=
+
+# Config file to give to the test broker.
+WITH_BROKER_TEST_CONFIG:=
+
+# Test scripts which should be invokedduring testing
+STANDALONE_TEST_SCRIPTS:=
+
+# Test scripts which should be invoked alongside a running broker
+# during testing
+WITH_BROKER_TEST_SCRIPTS:=
+
+# The directory within the package that contains tests
+TEST_DIR=$(PACKAGE_DIR)/test
+
+# The directories containing .erl files for tests
+TEST_SOURCE_DIRS=$(TEST_DIR)/src
+
+# The .erl files for tests
+TEST_SOURCE_ERLS=$(strip $(foreach D,$(TEST_SOURCE_DIRS),$(wildcard $(D)/*.erl)))
+
+# Where to put .beam files produced by compiling TEST_SOURCE_ERLS
+TEST_EBIN_DIR=$(TEST_DIR)/ebin
+
+# The .beam files produced by compiling TEST_SOURCE_ERLS
+TEST_EBIN_BEAMS=$(patsubst %,$(TEST_EBIN_DIR)/%.beam,$(notdir $(basename $(TEST_SOURCE_ERLS))))
+
+# Wrapper package variables
+
+# The git URL to clone from.  Setting this variable marks the package
+# as a wrapper package.
+UPSTREAM_GIT:=
+
+# The Mercurial URL to clone from.  Setting this variable marks the
+# package as a wrapper package.
+UPSTREAM_HG:=
+
+UPSTREAM_TYPE=$(if $(UPSTREAM_GIT),git)$(if $(UPSTREAM_HG),hg)
+
+# The upstream revision to clone.  Leave empty for default or master
+UPSTREAM_REVISION:=
+
+# Where to clone the upstream repository to
+CLONE_DIR=$(PACKAGE_DIR)/$(patsubst %-wrapper,%,$(PACKAGE_NAME))-$(UPSTREAM_TYPE)
+
+# The source directories contained in the cloned repositories.  These
+# are appended to SOURCE_DIRS.
+UPSTREAM_SOURCE_DIRS=$(CLONE_DIR)/src
+
+# The include directories contained in the cloned repositories.  These
+# are appended to INCLUDE_DIRS.
+UPSTREAM_INCLUDE_DIRS=$(CLONE_DIR)/include
+
+# Patches to apply to the upstream codebase after cloning, if any
+WRAPPER_PATCHES:=
+
+# The version number to assign to the build artifacts
+PACKAGE_VERSION=$(VERSION)
+
+# Should the app version incorporate the version from the original
+# .app file?
+RETAIN_ORIGINAL_VERSION:=
+
+# The original version that should be incorporated into the package
+# version if RETAIN_ORIGINAL_VERSION is set.  If empty, the original
+# version will be extracted from ORIGINAL_APP_FILE.
+ORIGINAL_VERSION:=
+
+# For customising construction of the build application directory.
+CONSTRUCT_APP_PREREQS:=
+construct_app_commands=
+
+package_rules=
+
+# Now let the package makefile fragment do its stuff
+include $(PACKAGE_DIR)/package.mk
+
+# package_rules provides a convenient way to force prompt expansion
+# of variables, including expansion in commands that would otherwise
+# be deferred.
+#
+# If package_rules is defined by the package makefile, we expand it
+# and eval it.  The point here is to get around the fact that make
+# defers expansion of commands.  But if we use package variables in
+# targets, as we naturally want to do, deferred expansion doesn't
+# work: They might have been trampled on by a later package.  Because
+# we expand package_rules here, references to package varialbes will
+# get expanded with the values we expect.
+#
+# The downside is that any variable references for which expansion
+# really should be deferred need to be protected by doulbing up the
+# dollar.  E.g., inside package_rules, you should write $$@, not $@.
+#
+# We use the same trick again below.
+ifdef package_rules
+$(eval $(package_rules))
+endif
+
+# Some variables used for brevity below.  Packages can't set these.
+APP_FILE=$(PACKAGE_DIR)/build/$(APP_NAME).app.$(PACKAGE_VERSION)
+APP_DONE=$(PACKAGE_DIR)/build/app/.done.$(PACKAGE_VERSION)
+APP_DIR=$(PACKAGE_DIR)/build/app/$(APP_NAME)-$(PACKAGE_VERSION)
+EZ_FILE=$(PACKAGE_DIR)/dist/$(APP_NAME)-$(PACKAGE_VERSION).ez
+DEPS_FILE=$(PACKAGE_DIR)/build/deps.mk
+
+
+# Convert the DEPS package names to canonical paths
+DEP_PATHS:=$(foreach DEP,$(DEPS),$(call package_to_path,$(DEP)))
+
+# Handle RETAIN_ORIGINAL_VERSION / ORIGINAL_VERSION
+ifdef RETAIN_ORIGINAL_VERSION
+
+# Automatically acquire ORIGINAL_VERSION from ORIGINAL_APP_FILE
+ifndef ORIGINAL_VERSION
+
+# The generated ORIGINAL_VERSION setting goes in build/version.mk
+$(eval $(call safe_include,$(PACKAGE_DIR)/build/version.mk))
+
+$(PACKAGE_DIR)/build/version.mk: $(ORIGINAL_APP_FILE)
+	sed -n -e 's|^.*{vsn, *"\([^"]*\)".*$$|ORIGINAL_VERSION:=\1|p' <$< >$@
+
+$(APP_FILE): $(PACKAGE_DIR)/build/version.mk
+
+endif # ifndef ORIGINAL_VERSION
+
+PACKAGE_VERSION:=$(ORIGINAL_VERSION)-rmq$(VERSION)
+
+endif # ifdef RETAIN_ORIGINAL_VERSION
+
+# Handle wrapper packages
+ifneq ($(UPSTREAM_TYPE),)
+
+SOURCE_DIRS+=$(UPSTREAM_SOURCE_DIRS)
+INCLUDE_DIRS+=$(UPSTREAM_INCLUDE_DIRS)
+
+define package_rules
+
+ifdef UPSTREAM_GIT
+$(CLONE_DIR)/.done:
+	rm -rf $(CLONE_DIR)
+	git clone $(UPSTREAM_GIT) $(CLONE_DIR)
+	$(if $(UPSTREAM_REVISION),cd $(CLONE_DIR) && git checkout $(UPSTREAM_REVISION))
+	$(if $(WRAPPER_PATCHES),$(foreach F,$(WRAPPER_PATCHES),patch -d $(CLONE_DIR) -p1 <$(PACKAGE_DIR)/$(F) &&) :)
+	touch $$@
+endif # UPSTREAM_GIT
+
+ifdef UPSTREAM_HG
+$(CLONE_DIR)/.done:
+	rm -rf $(CLONE_DIR)
+	hg clone -r $(or $(UPSTREAM_REVISION),default) $(UPSTREAM_HG) $(CLONE_DIR)
+	$(if $(WRAPPER_PATCHES),$(foreach F,$(WRAPPER_PATCHES),patch -d $(CLONE_DIR) -p1 <$(PACKAGE_DIR)/$(F) &&) :)
+	touch $$@
+endif # UPSTREAM_HG
+
+# When we clone, we need to remake anything derived from the app file
+# (e.g. build/version.mk).
+$(ORIGINAL_APP_FILE): $(CLONE_DIR)/.done
+
+# We include the commit hash into the package version, via
+# build/hash.mk
+$(eval $(call safe_include,$(PACKAGE_DIR)/build/hash.mk))
+
+$(PACKAGE_DIR)/build/hash.mk: $(CLONE_DIR)/.done
+	@mkdir -p $$(@D)
+ifdef UPSTREAM_GIT
+	echo UPSTREAM_SHORT_HASH:=`git --git-dir=$(CLONE_DIR)/.git log -n 1 HEAD | grep commit | cut -b 8-14` >$$@
+endif
+ifdef UPSTREAM_HG
+	echo UPSTREAM_SHORT_HASH:=`hg id -R $(CLONE_DIR) -i | cut -c -7` >$$@
+endif
+
+$(APP_FILE): $(PACKAGE_DIR)/build/hash.mk
+
+PACKAGE_VERSION:=$(PACKAGE_VERSION)-$(UPSTREAM_TYPE)$(UPSTREAM_SHORT_HASH)
+
+$(PACKAGE_DIR)+clean::
+	rm -rf $(CLONE_DIR)
+endef # package_rules
+$(eval $(package_rules))
+
+endif # UPSTREAM_TYPE
+
+# Generate a rule to compile .erl files from the directory $(1) into
+# directory $(2), taking extra erlc options from $(3)
+define package_source_dir_targets
+$(2)/%.beam: $(1)/%.erl $(PACKAGE_DIR)/build/dep-apps/.done | $(DEPS_FILE)
+	@mkdir -p $$(@D)
+	ERL_LIBS=$(PACKAGE_DIR)/build/dep-apps $(ERLC) $(PACKAGE_ERLC_OPTS) $(foreach D,$(INCLUDE_DIRS),-I $(D)) -pa $$(@D) -o $$(@D) $(3) $$<
+
+endef
+
+$(eval $(foreach D,$(SOURCE_DIRS),$(call package_source_dir_targets,$(D),$(EBIN_DIR),)))
+$(eval $(foreach D,$(TEST_SOURCE_DIRS),$(call package_source_dir_targets,$(D),$(TEST_EBIN_DIR),-pa $(EBIN_DIR))))
+
+# Commands to run the broker for tests
+#
+# $(1): The value for RABBITMQ_SERVER_START_ARGS
+# $(2): Extra env var settings when invoking the rabbitmq-server script
+# $(3): Extra .ezs to copy into the plugins dir
+define run_broker
+	rm -rf $(TEST_TMPDIR)
+	mkdir -p $(foreach D,log plugins $(NODENAME),$(TEST_TMPDIR)/$(D))
+	cp -a $(PACKAGE_DIR)/dist/*.ez $(TEST_TMPDIR)/plugins
+	$(call copy,$(3),$(TEST_TMPDIR)/plugins)
+	rm -f $(TEST_TMPDIR)/plugins/rabbit_common*.ez
+	RABBITMQ_PLUGINS_DIR=$(TEST_TMPDIR)/plugins \
+	  RABBITMQ_LOG_BASE=$(TEST_TMPDIR)/log \
+	  RABBITMQ_MNESIA_BASE=$(TEST_TMPDIR)/$(NODENAME) \
+	  RABBITMQ_NODENAME=$(NODENAME) \
+	  RABBITMQ_SERVER_START_ARGS=$(1) \
+	  $(2) $(UMBRELLA_BASE_DIR)/rabbitmq-server/scripts/rabbitmq-server
+endef
+
+# Commands to run the package's test suite
+#
+# $(1): Extra .ezs to copy into the plugins dir
+define run_with_broker_tests
+$(if $(WITH_BROKER_TEST_COMMANDS)$(WITH_BROKER_TEST_SCRIPTS),$(call run_with_broker_tests_aux,$1))
+endef
+
+define run_with_broker_tests_aux
+	$(call run_broker,'-pa $(TEST_EBIN_DIR) -coverage directories ["$(EBIN_DIR)"$(COMMA)"$(TEST_EBIN_DIR)"]',RABBITMQ_CONFIG_FILE=$(WITH_BROKER_TEST_CONFIG),$(1)) &
+	sleep 5
+	echo > $(TEST_TMPDIR)/rabbit-test-output && \
+	if $(foreach CMD,$(WITH_BROKER_TEST_COMMANDS), \
+	     echo >> $(TEST_TMPDIR)/rabbit-test-output && \
+	     echo "$(CMD)." \
+               | tee -a $(TEST_TMPDIR)/rabbit-test-output \
+               | $(ERL_CALL) $(ERL_CALL_OPTS) \
+               | tee -a $(TEST_TMPDIR)/rabbit-test-output \
+               | egrep "{ok, (ok|passed)}" >/dev/null &&) \
+	    $(foreach SCRIPT,$(WITH_BROKER_TEST_SCRIPTS),$(SCRIPT) &&) : ; \
+        then \
+	  touch $(TEST_TMPDIR)/.passed ; \
+	  echo "\nPASSED\n" ; \
+	else \
+	  cat $(TEST_TMPDIR)/rabbit-test-output ; \
+	  echo "\n\nFAILED\n" ; \
+	fi
+	sleep 1
+	echo "init:stop()." | $(ERL_CALL) $(ERL_CALL_OPTS) >/dev/null
+	sleep 1
+	test -f $(TEST_TMPDIR)/.passed
+endef
+
+# The targets common to all integrated packages
+define package_rules
+
+# Put all relevant ezs into the dist dir for this package, including
+# the main ez file produced by this package
+#
+# When the package version changes, our .ez filename will change, and
+# we need to regenerate the dist directory.  So the dependency needs
+# to go via a stamp file that incorporates the version in its name.
+# But we need a target with a fixed name for other packages to depend
+# on.  And it can't be a phony, as a phony will always get rebuilt.
+# Hence the need for two stamp files here.
+$(PACKAGE_DIR)/dist/.done: $(PACKAGE_DIR)/dist/.done.$(PACKAGE_VERSION)
+	touch $$@
+
+$(PACKAGE_DIR)/dist/.done.$(PACKAGE_VERSION): $(PACKAGE_DIR)/build/dep-ezs/.done $(APP_DONE)
+	rm -rf $$(@D)
+	mkdir -p $$(@D)
+	cd $(dir $(APP_DIR)) && zip -r $$(abspath $(EZ_FILE)) $(notdir $(APP_DIR))
+	$$(call copy,$$(wildcard $$(<D)/*.ez),$(PACKAGE_DIR)/dist)
+	touch $$@
+
+# Gather all the ezs from dependency packages
+$(PACKAGE_DIR)/build/dep-ezs/.done: $(foreach P,$(DEP_PATHS),$(P)/dist/.done)
+	rm -rf $$(@D)
+	mkdir -p $$(@D)
+	$(if $(DEP_PATHS),$(foreach P,$(DEP_PATHS),$$(call copy,$$(wildcard $(P)/dist/*.ez),$$(@D),&&)) :)
+	touch $$@
+
+# Put together the main app tree for this package
+$(APP_DONE): $(EBIN_BEAMS) $(INCLUDE_HRLS) $(APP_FILE) $(CONSTRUCT_APP_PREREQS)
+	rm -rf $$(@D)
+	mkdir -p $(APP_DIR)/ebin $(APP_DIR)/include
+	$(call copy,$(EBIN_BEAMS),$(APP_DIR)/ebin)
+	cp -a $(APP_FILE) $(APP_DIR)/ebin/$(APP_NAME).app
+	$(call copy,$(INCLUDE_HRLS),$(APP_DIR)/include)
+	$(construct_app_commands)
+	touch $$@
+
+ifdef DO_NOT_GENERATE_APP_FILE
+
+# Copy the .app file into place, set its version number
+$(APP_FILE): $(ORIGINAL_APP_FILE)
+	@mkdir -p $$(@D)
+	sed 's|{vsn, *\"[^\"]*\"|{vsn,\"$(PACKAGE_VERSION)\"|' <$$< >$$@
+
+else
+
+# Generate the .app file, and then copy it into place, and set its version number
+$(APP_FILE): $(ORIGINAL_APP_SOURCE) $(SOURCE_ERLS) $(UMBRELLA_BASE_DIR)/generate_app
+	@mkdir -p $$(@D)
+	escript $(UMBRELLA_BASE_DIR)/generate_app $$< $$@ $(SOURCE_DIRS)
+	sed -i.saved 's|{vsn, *\"[^\"]*\"|{vsn,\"$(PACKAGE_VERSION)\"|' $$@ && rm $$@.saved
+
+endif
+
+# Unpack the ezs from dependency packages, so that their contents are
+# accessible to erlc
+$(PACKAGE_DIR)/build/dep-apps/.done: $(PACKAGE_DIR)/build/dep-ezs/.done
+	rm -rf $$(@D)
+	mkdir -p $$(@D)
+	cd $$(@D) && $$(foreach EZ,$$(wildcard $(PACKAGE_DIR)/build/dep-ezs/*.ez),unzip $$(abspath $$(EZ)) &&) :
+	touch $$@
+
+# Dependency autogeneration.  This is complicated slightly by the need
+# to generate a dependency file which is path-independent.
+$(DEPS_FILE): $(SOURCE_ERLS) $(INCLUDE_HRLS) $(TEST_SOURCE_ERLS)
+	@mkdir -p $$(@D)
+	$$(if $$^,echo $$(subst : ,:,$$(foreach F,$$^,$$(abspath $$(F)):)) | escript $(abspath $(UMBRELLA_BASE_DIR)/generate_deps) $$@ '$$$$(EBIN_DIR)',echo >$$@)
+	$$(foreach F,$(TEST_EBIN_BEAMS),sed -i -e 's|^$$$$(EBIN_DIR)/$$(notdir $$(F)):|$$$$(TEST_EBIN_DIR)/$$(notdir $$(F)):|' $$@ && ) :
+	sed -i -e 's|$$@|$$$$(DEPS_FILE)|' $$@
+
+$(eval $(call safe_include,$(DEPS_FILE)))
+
+$(PACKAGE_DIR)+clean::
+	rm -rf $(EBIN_DIR)/*.beam $(TEST_EBIN_DIR)/*.beam $(PACKAGE_DIR)/dist $(PACKAGE_DIR)/build $(PACKAGE_DIR)/erl_crash.dump
+
+$(PACKAGE_DIR)+clean-with-deps:: $(foreach P,$(DEP_PATHS),$(P)+clean-with-deps)
+
+ifdef RELEASABLE
+all-releasable:: $(PACKAGE_DIR)/dist/.done
+
+copy-releasable:: $(PACKAGE_DIR)/dist/.done
+	cp $(PACKAGE_DIR)/dist/*.ez $(PLUGINS_DIST_DIR)
+endif
+
+# A hook to allow packages to verify that prerequisites are satisfied
+# before running.
+.PHONY: $(PACKAGE_DIR)+pre-run
+$(PACKAGE_DIR)+pre-run::
+
+# Run erlang with the package, its tests, and all its dependencies
+# available.
+.PHONY: $(PACKAGE_DIR)+run
+$(PACKAGE_DIR)+run: $(PACKAGE_DIR)/dist/.done $(TEST_EBIN_BEAMS) $(PACKAGE_DIR)+pre-run
+	ERL_LIBS=$(PACKAGE_DIR)/dist $(ERL) $(ERL_OPTS) -pa $(TEST_EBIN_DIR)
+
+# Run the broker with the package, its tests, and all its dependencies
+# available.
+.PHONY: $(PACKAGE_DIR)+run-in-broker
+$(PACKAGE_DIR)+run-in-broker: $(PACKAGE_DIR)/dist/.done $(RABBITMQ_SERVER_PATH)/dist/.done $(TEST_EBIN_BEAMS)
+	$(call run_broker,'-pa $(TEST_EBIN_DIR)',RABBITMQ_ALLOW_INPUT=true)
+
+# A hook to allow packages to verify that prerequisites are satisfied
+# before running tests.
+.PHONY: $(PACKAGE_DIR)+pre-test
+$(PACKAGE_DIR)+pre-test::
+
+# Runs the package's tests that operate within (or in conjuction with)
+# a running broker.
+.PHONY: $(PACKAGE_DIR)+in-broker-test
+$(PACKAGE_DIR)+in-broker-test: $(PACKAGE_DIR)/dist/.done $(RABBITMQ_SERVER_PATH)/dist/.done $(TEST_EBIN_BEAMS) $(PACKAGE_DIR)+pre-test $(call chain_test,$(PACKAGE_DIR)+in-broker-test)
+	$(call run_with_broker_tests)
+
+# Running the coverage tests requires Erlang/OTP R14. Note that
+# coverage only covers the in-broker tests.
+.PHONY: $(PACKAGE_DIR)+coverage
+$(PACKAGE_DIR)+coverage: $(PACKAGE_DIR)/dist/.done $(COVERAGE_PATH)/dist/.done $(TEST_EBIN_BEAMS) $(PACKAGE_DIR)+pre-test
+	$(call run_with_broker_tests,$(COVERAGE_PATH)/dist/*.ez)
+
+# Runs the package's tests that don't need a running broker
+.PHONY: $(PACKAGE_DIR)+standalone-test
+$(PACKAGE_DIR)+standalone-test: $(PACKAGE_DIR)/dist/.done $(TEST_EBIN_BEAMS) $(PACKAGE_DIR)+pre-test $(call chain_test,$(PACKAGE_DIR)+standalone-test)
+	$$(if $(STANDALONE_TEST_COMMANDS),\
+	  $$(foreach CMD,$(STANDALONE_TEST_COMMANDS),\
+	    ERL_LIBS=$(PACKAGE_DIR)/dist $(ERL) $(ERL_OPTS) -pa $(TEST_EBIN_DIR) -eval "init:stop(case $$(CMD) of ok -> 0; passed -> 0; _Else -> 1 end)" &&\
+	  )\
+	:)
+	$$(if $(STANDALONE_TEST_SCRIPTS),$$(foreach SCRIPT,$(STANDALONE_TEST_SCRIPTS),$$(SCRIPT) &&) :)
+
+# Run all the package's tests
+.PHONY: $(PACKAGE_DIR)+test
+$(PACKAGE_DIR)+test:: $(PACKAGE_DIR)+standalone-test $(PACKAGE_DIR)+in-broker-test
+
+endef
+$(eval $(package_rules))
+
+# Recursing into dependency packages has to be the last thing we do
+# because it will trample all over the per-package variables.
+
+# Recurse into dependency packages
+$(foreach DEP_PATH,$(DEP_PATHS),$(eval $(call do_package,$(DEP_PATH))))
+
+else # NON_INTEGRATED_$(PACKAGE_DIR)
+
+define package_rules
+
+# When the package version changes, our .ez filename will change, and
+# we need to regenerate the dist directory.  So the dependency needs
+# to go via a stamp file that incorporates the version in its name.
+# But we need a target with a fixed name for other packages to depend
+# on.  And it can't be a phony, as a phony will always get rebuilt.
+# Hence the need for two stamp files here.
+$(PACKAGE_DIR)/dist/.done: $(PACKAGE_DIR)/dist/.done.$(VERSION)
+	touch $$@
+
+# Non-integrated packages (rabbitmq-server and rabbitmq-erlang-client)
+# present a dilemma.  We could re-make the package every time we need
+# it.  But that will cause a huge amount of unnecessary rebuilding.
+# Or we could not worry about rebuilding non-integrated packages.
+# That's good for those developing plugins, but not for those who want
+# to work on the broker and erlang client in the context of the
+# plugins.  So instead, we use a conservative approximation to the
+# dependency structure within the package, to tell when to re-run the
+# makefile.
+$(PACKAGE_DIR)/dist/.done.$(VERSION): $(PACKAGE_DIR)/Makefile $(wildcard $(PACKAGE_DIR)/*.mk) $(wildcard $(PACKAGE_DIR)/src/*.erl) $(wildcard $(PACKAGE_DIR)/include/*.hrl) $(wildcard $(PACKAGE_DIR)/*.py) $(foreach DEP,$(NON_INTEGRATED_DEPS_$(PACKAGE_DIR)),$(call package_to_path,$(DEP))/dist/.done)
+	rm -rf $$(@D)
+	$$(MAKE) -C $(PACKAGE_DIR)
+	mkdir -p $$(@D)
+	touch $$@
+
+$(PACKAGE_DIR)+clean::
+	$$(MAKE) -C $(PACKAGE_DIR) clean
+	rm -rf $(PACKAGE_DIR)/dist
+
+endef
+$(eval $(package_rules))
+
+endif # NON_INTEGRATED_$(PACKAGE_DIR)
