diff options
| author | Alexandru Scvortov <alexandru@rabbitmq.com> | 2011-09-22 17:34:25 +0100 |
|---|---|---|
| committer | Alexandru Scvortov <alexandru@rabbitmq.com> | 2011-09-22 17:34:25 +0100 |
| commit | 8aff707c85ce7049d2cbb6aef920e59e9b2d3606 (patch) | |
| tree | 0e27cc4547d0d8ffe2c8a6c8bb150bda0ca3f86e | |
| parent | 1b69e1fa1527fe559130f07b31c3002d8d634b93 (diff) | |
| parent | da265ac0ec05eef8a2fb8e3b521a7e488e7a285f (diff) | |
| download | rabbitmq-server-git-8aff707c85ce7049d2cbb6aef920e59e9b2d3606.tar.gz | |
merge default into bug21319
| -rw-r--r-- | Makefile | 28 | ||||
| -rw-r--r-- | docs/rabbitmq-plugins.1.xml | 151 | ||||
| -rw-r--r-- | include/rabbit.hrl | 7 | ||||
| -rw-r--r-- | packaging/RPMS/Fedora/Makefile | 1 | ||||
| -rw-r--r-- | packaging/RPMS/Fedora/rabbitmq-server.spec | 13 | ||||
| -rw-r--r-- | packaging/debs/Debian/Makefile | 1 | ||||
| -rw-r--r-- | packaging/debs/Debian/debian/postinst | 8 | ||||
| -rw-r--r-- | packaging/debs/Debian/debian/rules | 2 | ||||
| -rw-r--r-- | packaging/generic-unix/Makefile | 1 | ||||
| -rw-r--r-- | packaging/windows/Makefile | 10 | ||||
| -rwxr-xr-x | scripts/rabbitmq-plugins | 32 | ||||
| -rwxr-xr-x | scripts/rabbitmq-plugins.bat | 47 | ||||
| -rwxr-xr-x | scripts/rabbitmq-server | 5 | ||||
| -rwxr-xr-x[-rw-r--r--] | scripts/rabbitmq-server.bat | 9 | ||||
| -rwxr-xr-x[-rw-r--r--] | scripts/rabbitmq-service.bat | 9 | ||||
| -rw-r--r-- | src/rabbit_control.erl | 19 | ||||
| -rw-r--r-- | src/rabbit_misc.erl | 9 | ||||
| -rw-r--r-- | src/rabbit_plugins.erl | 315 | ||||
| -rw-r--r-- | src/rabbit_prelaunch.erl | 29 |
19 files changed, 660 insertions, 36 deletions
@@ -14,11 +14,11 @@ DOCS_DIR=docs INCLUDES=$(wildcard $(INCLUDE_DIR)/*.hrl) $(INCLUDE_DIR)/rabbit_framing.hrl SOURCES=$(wildcard $(SOURCE_DIR)/*.erl) $(SOURCE_DIR)/rabbit_framing_amqp_0_9_1.erl $(SOURCE_DIR)/rabbit_framing_amqp_0_8.erl $(USAGES_ERL) BEAM_TARGETS=$(patsubst $(SOURCE_DIR)/%.erl, $(EBIN_DIR)/%.beam, $(SOURCES)) -TARGETS=$(EBIN_DIR)/rabbit.app $(INCLUDE_DIR)/rabbit_framing.hrl $(BEAM_TARGETS) +TARGETS=$(EBIN_DIR)/rabbit.app $(INCLUDE_DIR)/rabbit_framing.hrl $(BEAM_TARGETS) plugins WEB_URL=http://www.rabbitmq.com/ MANPAGES=$(patsubst %.xml, %.gz, $(wildcard $(DOCS_DIR)/*.[0-9].xml)) WEB_MANPAGES=$(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml) -USAGES_XML=$(DOCS_DIR)/rabbitmqctl.1.xml +USAGES_XML=$(DOCS_DIR)/rabbitmqctl.1.xml $(DOCS_DIR)/rabbitmq-plugins.1.xml USAGES_ERL=$(foreach XML, $(USAGES_XML), $(call usage_xml_to_erl, $(XML))) QC_MODULES := rabbit_backing_queue_qc QC_TRIALS ?= 100 @@ -57,6 +57,8 @@ endif ERLC_OPTS=-I $(INCLUDE_DIR) -o $(EBIN_DIR) -Wall -v +debug_info $(call boolean_macro,$(USE_SPECS),use_specs) $(call boolean_macro,$(USE_PROPER_QC),use_proper_qc) VERSION=0.0.0 +PLUGINS_SRC_DIR?=$(shell [ -d "plugins-src" ] && echo "plugins-src" || echo ) +PLUGINS_DIST_DIR=plugins-dist TARBALL_NAME=rabbitmq-server-$(VERSION) TARGET_SRC_DIR=dist/$(TARBALL_NAME) @@ -101,6 +103,18 @@ endif all: $(TARGETS) +.PHONY: plugins +ifneq "$(PLUGINS_SRC_DIR)" "" +plugins: + [ -d "$(PLUGINS_SRC_DIR)" ] || { echo "No plugins source distribution found (try linking public-umbrella to $(PLUGINS_SRC_DIR)"; false; } + -ln -s "$(CURDIR)" "$(PLUGINS_SRC_DIR)/rabbitmq-server" + mkdir -p $(PLUGINS_DIST_DIR) + PLUGINS_SRC_DIR="" $(MAKE) -C "$(PLUGINS_SRC_DIR)" plugins-dist PLUGINS_DIST_DIR="$(CURDIR)/$(PLUGINS_DIST_DIR)" VERSION=$(VERSION) +else +plugins: +# Not building plugins +endif + $(DEPS_FILE): $(SOURCES) $(INCLUDES) rm -f $@ echo $(subst : ,:,$(foreach FILE,$^,$(FILE):)) | escript generate_deps $@ $(EBIN_DIR) @@ -143,6 +157,8 @@ $(BASIC_PLT): $(BEAM_TARGETS) clean: rm -f $(EBIN_DIR)/*.beam rm -f $(EBIN_DIR)/rabbit.app $(EBIN_DIR)/rabbit.boot $(EBIN_DIR)/rabbit.script $(EBIN_DIR)/rabbit.rel + rm -f $(PLUGINS_DIST_DIR)/*.ez + -PLUGINS_SRC_DIR="" PRESERVE_CLONE_DIR=1 make -C $(PLUGINS_SRC_DIR) clean rm -f $(INCLUDE_DIR)/rabbit_framing.hrl $(SOURCE_DIR)/rabbit_framing_amqp_*.erl codegen.pyc rm -f $(DOCS_DIR)/*.[0-9].gz $(DOCS_DIR)/*.man.xml $(DOCS_DIR)/*.erl $(USAGES_ERL) rm -f $(RABBIT_PLT) @@ -237,7 +253,9 @@ srcdist: distclean cp -r $(DOCS_DIR) $(TARGET_SRC_DIR) chmod 0755 $(TARGET_SRC_DIR)/scripts/* - (cd dist; tar -zcf $(TARBALL_NAME).tar.gz $(TARBALL_NAME)) + [ "x" != "x$(PLUGINS_SRC_DIR)" ] && ln -s $(PLUGINS_SRC_DIR) $(TARGET_SRC_DIR)/plugins-src || echo No plugins source distribution found + + (cd dist; tar -zchf $(TARBALL_NAME).tar.gz $(TARBALL_NAME)) (cd dist; zip -q -r $(TARBALL_NAME).zip $(TARBALL_NAME)) rm -rf $(TARGET_SRC_DIR) @@ -284,12 +302,14 @@ install_bin: all install_dirs cp -r ebin include LICENSE LICENSE-MPL-RabbitMQ INSTALL $(TARGET_DIR) chmod 0755 scripts/* - for script in rabbitmq-env rabbitmq-server rabbitmqctl; do \ + for script in rabbitmq-env rabbitmq-server rabbitmqctl rabbitmq-plugins; do \ cp scripts/$$script $(TARGET_DIR)/sbin; \ [ -e $(SBIN_DIR)/$$script ] || ln -s $(SCRIPTS_REL_PATH)/$$script $(SBIN_DIR)/$$script; \ done mkdir -p $(TARGET_DIR)/plugins echo Put your .ez plugin files in this directory. > $(TARGET_DIR)/plugins/README + mkdir -p $(TARGET_DIR)/$(PLUGINS_DIST_DIR) + -cp $(PLUGINS_DIST_DIR)/*.ez $(TARGET_DIR)/$(PLUGINS_DIST_DIR) install_docs: docs_all install_dirs for section in 1 5; do \ diff --git a/docs/rabbitmq-plugins.1.xml b/docs/rabbitmq-plugins.1.xml new file mode 100644 index 0000000000..edc1ef9365 --- /dev/null +++ b/docs/rabbitmq-plugins.1.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd"> +<!-- + There is some extra magic in this document besides the usual DocBook semantics + to allow us to derive manpages, HTML and usage messages from the same source + document. + + Examples need to be moved to the end for man pages. To this end, <para>s and + <screen>s with role="example" will be moved, and with role="example-prefix" + will be removed. + + The usage messages are more involved. We have some magic in usage.xsl to pull + out the command synopsis, global option and subcommand synopses. We also pull + out <para>s with role="usage". + + Finally we construct lists of possible values for subcommand options, if the + subcommand's <varlistentry> has role="usage-has-option-list". The option which + takes the values should be marked with role="usage-option-list". +--> + +<refentry lang="en"> + <refentryinfo> + <productname>RabbitMQ Server</productname> + <authorgroup> + <corpauthor>The RabbitMQ Team <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></corpauthor> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>rabbitmq-plugins</refentrytitle> + <manvolnum>1</manvolnum> + <refmiscinfo class="manual">RabbitMQ Service</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>rabbitmq-plugins</refname> + <refpurpose>command line tool for managing a RabbitMQ broker plugins</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>rabbitmq-plugins</command> + <arg choice="req"><replaceable>command</replaceable></arg> + <arg choice="opt" rep="repeat"><replaceable>command options</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + <para> + <command>rabbitmq-plugins</command> is a command line tool for + managing RabbitMQ broker plugins. It allows one to enable, + disable and browse plugins. Note that it must be run by a user + with write permissions to the RabbitMQ configuration directory. + </para> + </refsect1> + + <refsect1> + <title>Commands</title> + + <variablelist> + <varlistentry> + <term><cmdsynopsis><command>list</command> <arg choice="opt">-c</arg> <arg choice="opt"><replaceable>pattern</replaceable></arg></cmdsynopsis></term> + <listitem> + <variablelist> + <varlistentry> + <term>-c</term> + <listitem><para>List plugins compactly.</para></listitem> + </varlistentry> + <varlistentry> + <term>pattern</term> + <listitem><para>Pattern to filter the plugin names by.</para></listitem> + </varlistentry> + </variablelist> + <para> + Lists available plugins, their versions, dependencies + and descriptions. + </para> + <para> + If the optional pattern is given, only plugins whose + name mathes <command>pattern</command> are shown. + </para> + <para role="example-prefix">For example:</para> + <screen role="example">rabbitmq-plugins list</screen> + <para role="example"> + This command lists all the plugins available. + </para> + <screen role="example">rabbitmq-plugins list -c</screen> + <para role="example"> + This command lists all the plugins available, on one line each. + </para> + <screen role="example">rabbitmq-plugins list -c management</screen> + <para role="example"> + This command lists all the plugins available, on one + line each, but does not display plugins whose name does + not contain "management". + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><cmdsynopsis><command>enable</command> <arg choice="req"><replaceable>plugin</replaceable> ...</arg></cmdsynopsis></term> + <listitem> + <variablelist> + <varlistentry> + <term>plugin</term> + <listitem><para>One or more plugins to enable.</para></listitem> + </varlistentry> + </variablelist> + <para> + Enables the specified plugins and all their + dependencies. + </para> + + <para role="example-prefix">For example:</para> + <screen role="example">rabbitmq-plugins enable rabbitmq_shovel rabbitmq_management</screen> + <para role="example"> + This command enables the <command>shovel</command> and + <command>management</command> plugins and all their + dependencies. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><cmdsynopsis><command>disable</command> <arg choice="req"><replaceable>plugin</replaceable> ...</arg></cmdsynopsis></term> + <listitem> + <variablelist> + <varlistentry> + <term>plugin</term> + <listitem><para>One or more plugins to disable.</para></listitem> + </varlistentry> + </variablelist> + <para> + Disables the specified plugins and all plugins that + depend on them. + </para> + + <para role="example-prefix">For example:</para> + <screen role="example">rabbitmq-plugins disable amqp_client</screen> + <para role="example"> + This command disables <command>amqp_client</command> and + all plugins that depend on it. + </para> + </listitem> + </varlistentry> + </variablelist> + + </refsect1> + +</refentry> diff --git a/include/rabbit.hrl b/include/rabbit.hrl index ac6399c64e..a603886c4b 100644 --- a/include/rabbit.hrl +++ b/include/rabbit.hrl @@ -75,6 +75,13 @@ -record(message_properties, {expiry, needs_confirming = false}). +-record(plugin, {name, %% atom() + version, %% string() + description, %% string() + type, %% 'ez' or 'dir' + dependencies, %% [{atom(), string()}] + location}). %% string() + %%---------------------------------------------------------------------------- -define(COPYRIGHT_MESSAGE, "Copyright (C) 2007-2011 VMware, Inc."). diff --git a/packaging/RPMS/Fedora/Makefile b/packaging/RPMS/Fedora/Makefile index c67d8fd6e1..be37646234 100644 --- a/packaging/RPMS/Fedora/Makefile +++ b/packaging/RPMS/Fedora/Makefile @@ -2,6 +2,7 @@ TARBALL_DIR=../../../dist TARBALL=$(notdir $(wildcard $(TARBALL_DIR)/rabbitmq-server-[0-9.]*.tar.gz)) COMMON_DIR=../../common VERSION=$(shell echo $(TARBALL) | sed -e 's:rabbitmq-server-\(.*\)\.tar\.gz:\1:g') +PLUGINS_DIST_DIR= TOP_DIR=$(shell pwd) #Under debian we do not want to check build dependencies, since that diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec index 0c5aa96a1f..57174b239a 100644 --- a/packaging/RPMS/Fedora/rabbitmq-server.spec +++ b/packaging/RPMS/Fedora/rabbitmq-server.spec @@ -55,6 +55,7 @@ mkdir -p %{buildroot}%{_localstatedir}/log/rabbitmq install -p -D -m 0755 %{S:1} %{buildroot}%{_initrddir}/rabbitmq-server install -p -D -m 0755 %{_rabbit_wrapper} %{buildroot}%{_sbindir}/rabbitmqctl install -p -D -m 0755 %{_rabbit_wrapper} %{buildroot}%{_sbindir}/rabbitmq-server +install -p -D -m 0755 %{_rabbit_wrapper} %{buildroot}%{_sbindir}/rabbitmq-plugin install -p -D -m 0755 %{_rabbit_server_ocf} %{buildroot}%{_exec_prefix}/lib/ocf/resource.d/rabbitmq/rabbitmq-server install -p -D -m 0644 %{S:3} %{buildroot}%{_sysconfdir}/logrotate.d/rabbitmq-server @@ -85,12 +86,24 @@ if ! getent passwd rabbitmq >/dev/null; then -c "RabbitMQ messaging server" fi +chown -R rabbitmq:rabbitmq %{_rabbit_erllibdir}/plugins/ + %post /sbin/chkconfig --add %{name} if [ -f %{_sysconfdir}/rabbitmq/rabbitmq.conf ] && [ ! -f %{_sysconfdir}/rabbitmq/rabbitmq-env.conf ]; then mv %{_sysconfdir}/rabbitmq/rabbitmq.conf %{_sysconfdir}/rabbitmq/rabbitmq-env.conf fi +if [ $1 -gt 1 ]; then + # Upgrade - find the old enabled_plugins file, copy it to the new + # version and re-enable plugins + ENABLED_PLUGINS_FILE=find %{_rabbit_libdir} -name 'enabled_plugins' + if [ "x" != "x$ENABLED_PLUGINS_FILE" ]; then + cp $ENABLED_PLUGINS_FILE %{_maindir}/plugins/ + rabbitmq-plugin enable + fi +fi + %preun if [ $1 = 0 ]; then #Complete uninstall diff --git a/packaging/debs/Debian/Makefile b/packaging/debs/Debian/Makefile index 38c81134a2..1b2fdd9e20 100644 --- a/packaging/debs/Debian/Makefile +++ b/packaging/debs/Debian/Makefile @@ -2,6 +2,7 @@ TARBALL_DIR=../../../dist TARBALL=$(notdir $(wildcard $(TARBALL_DIR)/rabbitmq-server-[0-9.]*.tar.gz)) COMMON_DIR=../../common VERSION=$(shell echo $(TARBALL) | sed -e 's:rabbitmq-server-\(.*\)\.tar\.gz:\1:g') +PLUGINS_DIST_DIR= DEBIAN_ORIG_TARBALL=$(shell echo $(TARBALL) | sed -e 's:\(.*\)-\(.*\)\(\.tar\.gz\):\1_\2\.orig\3:g') UNPACKED_DIR=rabbitmq-server-$(VERSION) diff --git a/packaging/debs/Debian/debian/postinst b/packaging/debs/Debian/debian/postinst index b11340ef8a..8e8523b3ae 100644 --- a/packaging/debs/Debian/debian/postinst +++ b/packaging/debs/Debian/debian/postinst @@ -32,6 +32,7 @@ fi chown -R rabbitmq:rabbitmq /var/lib/rabbitmq chown -R rabbitmq:rabbitmq /var/log/rabbitmq +chown -R rabbitmq:rabbitmq /usr/lib/rabbitmq/lib/rabbitmq_server-*/plugins/ case "$1" in configure) @@ -39,6 +40,13 @@ case "$1" in [ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf fi + + ENABLED_PLUGINS_FILE="/usr/lib/rabbitmq/lib/rabbitmq_server-$2/plugins/enabled_plugins" + if [ -f "$ENABLED_PLUGINS_FILE" ]; then + RABBIT_LIB=$(ls -1td /usr/lib/rabbitmq/lib/rabbitmq_server-* | head -1) + cp $ENABLED_PLUGINS_FILE $RABBIT_LIB/plugins/ + rabbitmq-plugin enable + fi ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/packaging/debs/Debian/debian/rules b/packaging/debs/Debian/debian/rules index a785b292af..ffb4461680 100644 --- a/packaging/debs/Debian/debian/rules +++ b/packaging/debs/Debian/debian/rules @@ -14,7 +14,7 @@ DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/ install/rabbitmq-server:: mkdir -p $(DOCDIR) rm $(RABBIT_LIB)LICENSE* $(RABBIT_LIB)INSTALL* - for script in rabbitmqctl rabbitmq-server; do \ + for script in rabbitmqctl rabbitmq-server rabbitmq-plugin; do \ install -p -D -m 0755 debian/rabbitmq-script-wrapper $(DEB_DESTDIR)usr/sbin/$$script; \ done sed -e 's|@RABBIT_LIB@|/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)|g' <debian/postrm.in >debian/postrm diff --git a/packaging/generic-unix/Makefile b/packaging/generic-unix/Makefile index b5c342aad7..0f2a47b69a 100644 --- a/packaging/generic-unix/Makefile +++ b/packaging/generic-unix/Makefile @@ -2,6 +2,7 @@ VERSION=0.0.0 SOURCE_DIR=rabbitmq-server-$(VERSION) TARGET_DIR=rabbitmq_server-$(VERSION) TARGET_TARBALL=rabbitmq-server-generic-unix-$(VERSION) +PLUGINS_DIST_DIR= dist: tar -zxf ../../dist/$(SOURCE_DIR).tar.gz diff --git a/packaging/windows/Makefile b/packaging/windows/Makefile index a0be8d89e0..6abcafc543 100644 --- a/packaging/windows/Makefile +++ b/packaging/windows/Makefile @@ -2,6 +2,7 @@ VERSION=0.0.0 SOURCE_DIR=rabbitmq-server-$(VERSION) TARGET_DIR=rabbitmq_server-$(VERSION) TARGET_ZIP=rabbitmq-server-windows-$(VERSION) +PLUGINS_DIST_DIR= dist: tar -zxf ../../dist/$(SOURCE_DIR).tar.gz @@ -10,20 +11,25 @@ dist: mkdir $(SOURCE_DIR)/sbin mv $(SOURCE_DIR)/scripts/rabbitmq-server.bat $(SOURCE_DIR)/sbin mv $(SOURCE_DIR)/scripts/rabbitmq-service.bat $(SOURCE_DIR)/sbin + mv $(SOURCE_DIR)/scripts/rabbitmq-plugin.bat $(SOURCE_DIR)/sbin mv $(SOURCE_DIR)/scripts/rabbitmqctl.bat $(SOURCE_DIR)/sbin rm -rf $(SOURCE_DIR)/scripts - rm -rf $(SOURCE_DIR)/codegen* $(SOURCE_DIR)/Makefile + rm -rf $(SOURCE_DIR)/codegen* $(SOURCE_DIR)/Makefile $(SOURCE_DIR)/*mk rm -f $(SOURCE_DIR)/README rm -rf $(SOURCE_DIR)/docs + rm -rf $(SOURCE_DIR)/src + rm -rf $(SOURCE_DIR)/dist mv $(SOURCE_DIR) $(TARGET_DIR) mkdir -p $(TARGET_DIR) mkdir -p $(TARGET_DIR)/plugins - echo Put your .ez plugin files in this directory > $(TARGET_DIR)/plugins/README + echo Put your .ez plugin files in this directory > $(TARGET_DIR)/plugins/README.txt + mv $(TARGET_DIR)/plugins-src/README $(TARGET_DIR)/plugins-dist/README.txt xmlto -o . xhtml-nochunks ../../docs/rabbitmq-service.xml elinks -dump -no-references -no-numbering rabbitmq-service.html \ > $(TARGET_DIR)/readme-service.txt todos $(TARGET_DIR)/readme-service.txt + rm -rf $(TARGET_DIR)/plugins-src zip -q -r $(TARGET_ZIP).zip $(TARGET_DIR) rm -rf $(TARGET_DIR) rabbitmq-service.html diff --git a/scripts/rabbitmq-plugins b/scripts/rabbitmq-plugins new file mode 100755 index 0000000000..b3137a32de --- /dev/null +++ b/scripts/rabbitmq-plugins @@ -0,0 +1,32 @@ +#!/bin/sh +## The contents of this file are subject to the Mozilla Public License +## Version 1.1 (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License +## at http://www.mozilla.org/MPL/ +## +## Software distributed under the License is distributed on an "AS IS" +## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +## the License for the specific language governing rights and +## limitations under the License. +## +## The Original Code is RabbitMQ. +## +## The Initial Developer of the Original Code is VMware, Inc. +## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## + +. `dirname $0`/rabbitmq-env + +[ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=/etc/rabbitmq/enabled_plugins + +[ "x" = "x$RABBITMQ_PLUGINS_DIST_DIR" ] && RABBITMQ_PLUGINS_DIST_DIR="${RABBITMQ_HOME}/plugins-dist" + +exec erl \ + -pa "${RABBITMQ_HOME}/ebin" \ + -noinput \ + -hidden \ + -sname rabbitmq-plugins$$ \ + -s rabbit_plugins \ + -enabled_plugins_file "$RABBITMQ_ENABLED_PLUGINS_FILE" \ + -plugins_dist_dir "$RABBITMQ_PLUGINS_DIST_DIR" \ + -extra "$@" diff --git a/scripts/rabbitmq-plugins.bat b/scripts/rabbitmq-plugins.bat new file mode 100755 index 0000000000..8455a7dc90 --- /dev/null +++ b/scripts/rabbitmq-plugins.bat @@ -0,0 +1,47 @@ +@echo off
+REM The contents of this file are subject to the Mozilla Public License
+REM Version 1.1 (the "License"); you may not use this file except in
+REM compliance with the License. You may obtain a copy of the License
+REM at http://www.mozilla.org/MPL/
+REM
+REM Software distributed under the License is distributed on an "AS IS"
+REM basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+REM the License for the specific language governing rights and
+REM limitations under the License.
+REM
+REM The Original Code is RabbitMQ.
+REM
+REM The Initial Developer of the Original Code is VMware, Inc.
+REM Copyright (c) 2007-2011 VMware, Inc. All rights reserved.
+REM
+
+setlocal
+
+rem Preserve values that might contain exclamation marks before
+rem enabling delayed expansion
+set TDP0=%~dp0
+set STAR=%*
+setlocal enabledelayedexpansion
+
+if not exist "!ERLANG_HOME!\bin\erl.exe" (
+ echo.
+ echo ******************************
+ echo ERLANG_HOME not set correctly.
+ echo ******************************
+ echo.
+ echo Please either set ERLANG_HOME to point to your Erlang installation or place the
+ echo RabbitMQ server distribution in the Erlang lib folder.
+ echo.
+ exit /B
+)
+
+if "!RABBITMQ_ENABLED_PLUGINS_FILE!"=="" (
+ set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
+)
+
+set RABBITMQ_PLUGINS_DIST_DIR=!TDP0!..\plugins-dist
+
+"!ERLANG_HOME!\bin\erl.exe" -pa "!TDP0!..\ebin" -noinput -hidden -sname rabbitmq-plugins!RANDOM! -s rabbit_plugins -enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" -plugins_dist_dir "!RABBITMQ_PLUGINS_DIST_DIR:\=/!" -extra !STAR!
+
+endlocal
+endlocal
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server index 7176d80130..302eb92f39 100755 --- a/scripts/rabbitmq-server +++ b/scripts/rabbitmq-server @@ -52,7 +52,8 @@ fi [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${PLUGINS_EXPAND_DIR} [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-plugins-expand -[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR="${RABBITMQ_HOME}/plugins" +[ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=/etc/rabbitmq/enabled_plugins +[ "x" = "x$RABBITMQ_PLUGINS_DIST_DIR" ] && RABBITMQ_PLUGINS_DIST_DIR="${RABBITMQ_HOME}/plugins-dist" ## Log rotation [ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS=${LOGS} @@ -79,7 +80,7 @@ if [ "x" = "x$RABBITMQ_NODE_ONLY" ]; then -hidden \ -s rabbit_prelaunch \ -sname rabbitmqprelaunch$$ \ - -extra "$RABBITMQ_PLUGINS_DIR" "${RABBITMQ_PLUGINS_EXPAND_DIR}" "${RABBITMQ_NODENAME}" + -extra "$RABBITMQ_ENABLED_PLUGINS_FILE" "$RABBITMQ_PLUGINS_DIST_DIR" "${RABBITMQ_PLUGINS_EXPAND_DIR}" "${RABBITMQ_NODENAME}" then RABBITMQ_BOOT_FILE="${RABBITMQ_PLUGINS_EXPAND_DIR}/rabbit" RABBITMQ_EBIN_PATH="" diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat index 84d24c458b..df38013869 100644..100755 --- a/scripts/rabbitmq-server.bat +++ b/scripts/rabbitmq-server.bat @@ -93,7 +93,11 @@ if "!RABBITMQ_PLUGINS_EXPAND_DIR!"=="" ( set RABBITMQ_PLUGINS_EXPAND_DIR=!RABBITMQ_MNESIA_BASE!/!RABBITMQ_NODENAME!-plugins-expand
)
-set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins
+if "!RABBITMQ_ENABLED_PLUGINS_FILE!"=="" (
+ set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
+)
+
+set RABBITMQ_PLUGINS_DIST_DIR=!TDP0!..\plugins-dist
set RABBITMQ_EBIN_ROOT=!TDP0!..\ebin
"!ERLANG_HOME!\bin\erl.exe" ^
@@ -101,7 +105,8 @@ set RABBITMQ_EBIN_ROOT=!TDP0!..\ebin -noinput -hidden ^
-s rabbit_prelaunch ^
-sname rabbitmqprelaunch!RANDOM! ^
--extra "!RABBITMQ_PLUGINS_DIR:\=/!" ^
+-extra "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
+ "!RABBITMQ_PLUGINS_DIST_DIR:\=/!" ^
"!RABBITMQ_PLUGINS_EXPAND_DIR:\=/!" ^
"!RABBITMQ_NODENAME!"
diff --git a/scripts/rabbitmq-service.bat b/scripts/rabbitmq-service.bat index 60697d0b49..295a7d70d0 100644..100755 --- a/scripts/rabbitmq-service.bat +++ b/scripts/rabbitmq-service.bat @@ -162,14 +162,19 @@ if errorlevel 1 ( echo !RABBITMQ_SERVICENAME! service is already present - only updating service parameters
)
-set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins
+if "!RABBITMQ_ENABLED_PLUGINS_FILE!"=="" (
+ set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
+)
+
+set RABBITMQ_PLUGINS_DIST_DIR=!TDP0!..\plugins-dist
set RABBITMQ_EBIN_ROOT=!TDP0!..\ebin
"!ERLANG_HOME!\bin\erl.exe" ^
-pa "!RABBITMQ_EBIN_ROOT!" ^
-noinput -hidden ^
-s rabbit_prelaunch ^
--extra "!RABBITMQ_PLUGINS_DIR:\=/!" ^
+-extra "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
+ "!RABBITMQ_PLUGINS_DIST_DIR:\=/!" ^
"!RABBITMQ_PLUGINS_EXPAND_DIR:\=/!" ^
""
diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl index 1163ae9d86..b28748538e 100644 --- a/src/rabbit_control.erl +++ b/src/rabbit_control.erl @@ -86,24 +86,24 @@ start() -> true -> ok; false -> io:format("...done.~n") end, - quit(0); + rabbit_misc:quit(0); {'EXIT', {function_clause, [{?MODULE, action, _} | _]}} -> print_error("invalid command '~s'", [string:join([atom_to_list(Command) | Args], " ")]), usage(); {error, Reason} -> print_error("~p", [Reason]), - quit(2); + rabbit_misc:quit(2); {badrpc, {'EXIT', Reason}} -> print_error("~p", [Reason]), - quit(2); + rabbit_misc:quit(2); {badrpc, Reason} -> print_error("unable to connect to node ~w: ~w", [Node, Reason]), print_badrpc_diagnostics(Node), - quit(2); + rabbit_misc:quit(2); Other -> print_error("~p", [Other]), - quit(2) + rabbit_misc:quit(2) end. fmt_stderr(Format, Args) -> rabbit_misc:format_stderr(Format ++ "~n", Args). @@ -154,7 +154,7 @@ stop() -> usage() -> io:format("~s", [rabbit_ctl_usage:usage()]), - quit(1). + rabbit_misc:quit(1). %%---------------------------------------------------------------------------- @@ -506,10 +506,3 @@ prettify_typed_amqp_value(table, Value) -> prettify_amqp_table(Value); prettify_typed_amqp_value(array, Value) -> [prettify_typed_amqp_value(T, V) || {T, V} <- Value]; prettify_typed_amqp_value(_Type, Value) -> Value. - -%% the slower shutdown on windows required to flush stdout -quit(Status) -> - case os:type() of - {unix, _} -> halt(Status); - {win32, _} -> init:stop(Status) - end. diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl index d47041d669..f50730033c 100644 --- a/src/rabbit_misc.erl +++ b/src/rabbit_misc.erl @@ -54,6 +54,7 @@ -export([pget/2, pget/3, pget_or_die/2]). -export([format_message_queue/2]). -export([append_rpc_all_nodes/4]). +-export([quit/1]). %%---------------------------------------------------------------------------- @@ -191,6 +192,7 @@ -spec(pget_or_die/2 :: (term(), [term()]) -> term() | no_return()). -spec(format_message_queue/2 :: (any(), priority_queue:q()) -> term()). -spec(append_rpc_all_nodes/4 :: ([node()], atom(), atom(), [any()]) -> [any()]). +-spec(quit/1 :: (integer() | string()) -> no_return()). -endif. @@ -806,3 +808,10 @@ append_rpc_all_nodes(Nodes, M, F, A) -> {badrpc, _} -> []; _ -> Res end || Res <- ResL]). + +%% the slower shutdown on windows required to flush stdout +quit(Status) -> + case os:type() of + {unix, _} -> halt(Status); + {win32, _} -> init:stop(Status) + end. diff --git a/src/rabbit_plugins.erl b/src/rabbit_plugins.erl new file mode 100644 index 0000000000..b93b7bed99 --- /dev/null +++ b/src/rabbit_plugins.erl @@ -0,0 +1,315 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% + +-module(rabbit_plugins). +-include("rabbit.hrl"). + +-export([start/0, stop/0, find_plugins/1, read_enabled_plugins/1, + lookup_plugins/2, calculate_required_plugins/2]). + +-define(COMPACT_OPT, "-c"). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-spec(start/0 :: () -> no_return()). +-spec(stop/0 :: () -> 'ok'). + +-endif. + +%%---------------------------------------------------------------------------- + +start() -> + {ok, [[EnabledPluginsFile|_]|_]} = init:get_argument(enabled_plugins_file), + put(enabled_plugins_file, EnabledPluginsFile), + {ok, [[PluginsDistDir|_]|_]} = init:get_argument(plugins_dist_dir), + put(plugins_dist_dir, PluginsDistDir), + {[Command0 | Args], Opts} = + case rabbit_misc:get_options([{flag, ?COMPACT_OPT}], + init:get_plain_arguments()) of + {[], _Opts} -> usage(); + CmdArgsAndOpts -> CmdArgsAndOpts + end, + Command = list_to_atom(Command0), + + case catch action(Command, Args, Opts) of + ok -> + rabbit_misc:quit(0); + {'EXIT', {function_clause, [{?MODULE, action, _} | _]}} -> + print_error("invalid command '~s'", + [string:join([atom_to_list(Command) | Args], " ")]), + usage(); + {error, Reason} -> + print_error("~p", [Reason]), + rabbit_misc:quit(2); + Other -> + print_error("~p", [Other]), + rabbit_misc:quit(2) + end. + +stop() -> + ok. + +print_error(Format, Args) -> + rabbit_misc:format_stderr("Error: " ++ Format ++ "~n", Args). + +usage() -> + io:format("~s", [rabbit_plugins_usage:usage()]), + rabbit_misc:quit(1). + +%%---------------------------------------------------------------------------- + +action(list, [], Opts) -> + action(list, [".*"], Opts); +action(list, [Pat], Opts) -> + format_plugins(Pat, proplists:get_bool(?COMPACT_OPT, Opts)); + +action(enable, ToEnable0, _Opts) -> + AllPlugins = find_plugins(), + EnabledPlugins = lookup_plugins(read_enabled_plugins(), AllPlugins), + ToEnable = [list_to_atom(Name) || Name <- ToEnable0], + ToEnablePlugins = lookup_plugins(ToEnable, AllPlugins), + Missing = ToEnable -- plugin_names(ToEnablePlugins), + case Missing of + [] -> ok; + _ -> io:format("Warning: the following plugins could not be found: ~p~n", + [Missing]) + end, + NewEnabledPlugins = merge_plugin_lists(EnabledPlugins, ToEnablePlugins), + update_enabled_plugins(plugin_names(NewEnabledPlugins)); + +action(disable, ToDisable0, _Opts) -> + ToDisable = [list_to_atom(Name) || Name <- ToDisable0], + Enabled = read_enabled_plugins(), + AllPlugins = find_plugins(), + Missing = ToDisable -- plugin_names(AllPlugins), + case Missing of + [] -> ok; + _ -> io:format("Warning: the following plugins could not be found: ~p~n", + [Missing]) + end, + ToDisable1 = ToDisable -- Missing, + ToDisable2 = calculate_dependencies(true, ToDisable1, AllPlugins), + AlsoDisabled = sets:to_list( + sets:intersection(sets:from_list(ToDisable2 -- ToDisable1), + sets:from_list(Enabled))), + case AlsoDisabled of + [] -> ok; + _ -> io:format("Warning: the following plugins will also be disabled " + "because their dependencies are no longer met: ~p~n", + [AlsoDisabled]) + end, + update_enabled_plugins(Enabled -- ToDisable2). + +%%---------------------------------------------------------------------------- + +%% Get the #plugin{}s ready to be enabled. +find_plugins() -> + find_plugins(get(plugins_dist_dir)). +find_plugins(PluginsDistDir) -> + EZs = [{ez, EZ} || EZ <- filelib:wildcard("*.ez", PluginsDistDir)], + FreeApps = [{app, App} || + App <- filelib:wildcard("*/ebin/*.app", PluginsDistDir)], + {Plugins, Problems} = + lists:foldl(fun ({error, EZ, Reason}, {Plugins1, Problems1}) -> + {Plugins1, [{EZ, Reason} | Problems1]}; + (Plugin = #plugin{}, {Plugins1, Problems1}) -> + {[Plugin|Plugins1], Problems1} + end, {[], []}, + [get_plugin_info(PluginsDistDir, Plug) || + Plug <- EZs ++ FreeApps]), + case Problems of + [] -> ok; + _ -> io:format("Warning: Problem reading some plugins: ~p~n", [Problems]) + end, + Plugins. + +%% Get the #plugin{} from an .ez. +get_plugin_info(Base, {ez, EZ0}) -> + EZ = filename:join([Base, EZ0]), + case read_app_file(EZ) of + {application, Name, Props} -> + Version = proplists:get_value(vsn, Props, "0"), + Description = proplists:get_value(description, Props, ""), + Dependencies = + filter_applications(proplists:get_value(applications, Props, [])), + #plugin{name = Name, version = Version, description = Description, + dependencies = Dependencies, location = EZ, type = ez}; + {error, Reason} -> + {error, EZ, Reason} + end; +%% Get the #plugin{} from an .app. +get_plugin_info(Base, {app, App0}) -> + App = filename:join([Base, App0]), + case rabbit_file:read_term_file(App) of + {ok, [{application, Name, Props}]} -> + Version = proplists:get_value(vsn, Props, "0"), + Description = proplists:get_value(description, Props, ""), + Dependencies = + filter_applications(proplists:get_value(applications, Props, [])), + Location = filename:absname(filename:dirname(filename:dirname(App))), + #plugin{name = Name, version = Version, description = Description, + dependencies = Dependencies, location = Location, type = dir}; + {error, Reason} -> + {error, App, {invalid_app, Reason}} + end. + +%% Read the .app file from an ez. +read_app_file(EZ) -> + case zip:list_dir(EZ) of + {ok, [_|ZippedFiles]} -> + case find_app_files(ZippedFiles) of + [AppPath|_] -> + {ok, [{AppPath, AppFile}]} = + zip:extract(EZ, [{file_list, [AppPath]}, memory]), + parse_binary(AppFile); + [] -> + {error, no_app_file} + end; + {error, Reason} -> + {error, {invalid_ez, Reason}} + end. + +%% Return the path of the .app files in ebin/. +find_app_files(ZippedFiles) -> + {ok, RE} = re:compile("^.*/ebin/.*.app$"), + [Path || {zip_file, Path, _, _, _, _} <- ZippedFiles, + re:run(Path, RE, [{capture, none}]) =:= match]. + +%% Parse a binary into a term. +parse_binary(Bin) -> + try + {ok, Ts, _} = erl_scan:string(binary:bin_to_list(Bin)), + {ok, Term} = erl_parse:parse_term(Ts), + Term + catch + Err -> {error, {invalid_app, Err}} + end. + +%% Pretty print a list of plugins. +format_plugins(Pattern, Compact) -> + AvailablePlugins = find_plugins(), + EnabledExplicitly = read_enabled_plugins(), + EnabledImplicitly = + calculate_required_plugins(EnabledExplicitly, AvailablePlugins) -- + EnabledExplicitly, + {ok, RE} = re:compile(Pattern), + [ format_plugin(P, EnabledExplicitly, EnabledImplicitly, Compact) + || P = #plugin{name = Name} <- AvailablePlugins, + re:run(atom_to_list(Name), RE, [{capture, none}]) =:= match], + ok. + +format_plugin(#plugin{name = Name, version = Version, description = Description, + dependencies = Dependencies}, + EnabledExplicitly, EnabledImplicitly, Compact) -> + Glyph = case {lists:member(Name, EnabledExplicitly), + lists:member(Name, EnabledImplicitly)} of + {true, false} -> "[E]"; + {false, true} -> "[e]"; + _ -> "[A]" + end, + case Compact of + true -> + io:format("~s ~w-~s: ~s~n", [Glyph, Name, Version, Description]); + false -> + io:format("~s ~w~n", [Glyph, Name]), + io:format(" Version: \t~s~n", [Version]), + case Dependencies of + [] -> ok; + _ -> io:format(" Dependencies:\t~p~n", [Dependencies]) + end, + io:format(" Description:\t~s~n", [Description]), + io:format("~n") + end. + +usort_plugins(Plugins) -> + lists:usort(fun plugins_cmp/2, Plugins). + +%% Merge two plugin lists. In case of duplicates, only keep highest +%% version. +merge_plugin_lists(Ps1, Ps2) -> + filter_duplicates(usort_plugins(Ps1 ++ Ps2)). + +filter_duplicates([P1 = #plugin{name = N, version = V1}, + P2 = #plugin{name = N, version = V2} | Ps]) -> + if V1 < V2 -> filter_duplicates([P2 | Ps]); + true -> filter_duplicates([P1 | Ps]) + end; +filter_duplicates([P | Ps]) -> + [P | filter_duplicates(Ps)]; +filter_duplicates(Ps) -> + Ps. + +plugins_cmp(#plugin{name = N1, version = V1}, #plugin{name = N2, version = V2}) -> + {N1, V1} =< {N2, V2}. + +%% Filter applications that can be loaded *right now*. +filter_applications(Applications) -> + [Application || Application <- Applications, + case application:load(Application) of + {error, {already_loaded, _}} -> false; + ok -> application:unload(Application), + false; + _ -> true + end]. + +%% Return the names of the given plugins. +plugin_names(Plugins) -> + [Name || #plugin{name = Name} <- Plugins]. + +%% Find plugins by name in a list of plugins. +lookup_plugins(Names, AllPlugins) -> + AllPlugins1 = filter_duplicates(usort_plugins(AllPlugins)), + [P || P = #plugin{name = Name} <- AllPlugins1, lists:member(Name, Names)]. + +%% Read the enabled plugin names from disk. +read_enabled_plugins() -> + read_enabled_plugins(get(enabled_plugins_file)). + +read_enabled_plugins(FileName) -> + case rabbit_file:read_term_file(FileName) of + {ok, [Plugins]} -> Plugins; + {error, enoent} -> []; + {error, Reason} -> throw({error, {cannot_read_enabled_plugins_file, + FileName, Reason}}) + end. + +%% Update the enabled plugin names on disk. +update_enabled_plugins(Plugins) -> + FileName = get(enabled_plugins_file), + case rabbit_file:write_term_file(FileName, [Plugins]) of + ok -> ok; + {error, Reason} -> throw({error, {cannot_write_enabled_plugins_file, + FileName, Reason}}) + end. + +calculate_required_plugins(Sources, AllPlugins) -> + calculate_dependencies(false, Sources, AllPlugins). + +calculate_dependencies(Reverse, Sources, AllPlugins) -> + AllPlugins1 = filter_duplicates(usort_plugins(AllPlugins)), + {ok, G} = rabbit_misc:build_acyclic_graph( + fun (App, _Deps) -> [{App, App}] end, + fun (App, Deps) -> [{App, Dep} || Dep <- Deps] end, + [{Name, Deps} + || #plugin{name = Name, dependencies = Deps} <- AllPlugins1]), + Dests = case Reverse of + false -> digraph_utils:reachable(Sources, G); + true -> digraph_utils:reaching(Sources, G) + end, + true = digraph:delete(G), + Dests. diff --git a/src/rabbit_prelaunch.erl b/src/rabbit_prelaunch.erl index cd0c322b6d..e6c7344afe 100644 --- a/src/rabbit_prelaunch.erl +++ b/src/rabbit_prelaunch.erl @@ -18,6 +18,8 @@ -export([start/0, stop/0]). +-include("rabbit.hrl"). + -define(BaseApps, [rabbit]). -define(ERROR_CODE, 1). @@ -41,14 +43,14 @@ start() -> io:format("Activating RabbitMQ plugins ...~n"), %% Determine our various directories - [PluginDir, UnpackedPluginDir, NodeStr] = init:get_plain_arguments(), + [EnabledPluginsFile, PluginsDistDir, UnpackedPluginDir, NodeStr] = + init:get_plain_arguments(), RootName = UnpackedPluginDir ++ "/rabbit", - %% Unpack any .ez plugins - unpack_ez_plugins(PluginDir, UnpackedPluginDir), + prepare_plugins(EnabledPluginsFile, PluginsDistDir, UnpackedPluginDir), %% Build a list of required apps based on the fixed set, and any plugins - PluginApps = find_plugins(PluginDir) ++ find_plugins(UnpackedPluginDir), + PluginApps = find_plugins(UnpackedPluginDir), RequiredApps = ?BaseApps ++ PluginApps, %% Build the entire set of dependencies - this will load the @@ -145,7 +147,11 @@ delete_recursively(Fn) -> Error -> Error end. -unpack_ez_plugins(SrcDir, DestDir) -> +prepare_plugins(EnabledPluginsFile, PluginsDistDir, DestDir) -> + AllPlugins = rabbit_plugins:find_plugins(PluginsDistDir), + Enabled = rabbit_plugins:read_enabled_plugins(EnabledPluginsFile), + ToUnpack = rabbit_plugins:calculate_required_plugins(Enabled, AllPlugins), + %% Eliminate the contents of the destination directory case delete_recursively(DestDir) of ok -> ok; @@ -155,12 +161,15 @@ unpack_ez_plugins(SrcDir, DestDir) -> ok -> ok; {error, E2} -> terminate("Could not create dir ~s (~p)", [DestDir, E2]) end, - [unpack_ez_plugin(PluginName, DestDir) || - PluginName <- filelib:wildcard(SrcDir ++ "/*.ez")]. -unpack_ez_plugin(PluginFn, PluginDestDir) -> - zip:unzip(PluginFn, [{cwd, PluginDestDir}]), - ok. + [prepare_plugin(Plugin, DestDir) || + Plugin <- rabbit_plugins:lookup_plugins(ToUnpack, AllPlugins)]. + +prepare_plugin(#plugin{type = ez, location = Location}, PluginDestDir) -> + zip:unzip(Location, [{cwd, PluginDestDir}]); +prepare_plugin(#plugin{type = dir, name = Name, location = Location}, + PluginsDestDir) -> + file:make_symlink(Location, filename:join([PluginsDestDir, Name])). find_plugins(PluginDir) -> [prepare_dir_plugin(PluginName) || |
