Now it's also possible to supply arrays via e.g.:

    require foo [ bar=[ 1 2 "3 3" ] ]

or equivalently:

    require foo [[ bar=[[ 1 2 "3 3" ]] ]]

Allowing the latter notation makes it possible to have a regular variable with 
the value "[":

    require foo [[ bar=[ ]]

Arrays must be declared either as required via e.g.:

    myexparam bar[]

or as optional with a default value via e.g.:

    myexparam bar=[ 1 2 "3 3" ]

Furthermore unit tests are now included in the attached patch.

Unfortunately due to a limitation in bash and the way this is implemented, 
using exparam to access a variable in a subshell from a function that is 
called outside global scope will not work. So this code for example:

foo_pkg_setup() {
    var=$(exparam bar)
}

will result in the error message "exparam is banned outside exlibs". Therefore 
this patch allows us to access a variable with this code:

foo_pkg_setup() {
    exparam -v var bar
}

which assigns the value of bar (or bar[0] in case bar is an exlib array) to 
the variable var. To access an array one can either use an index (exparam 
bar[0], exparam bar[1], etc.) or transfer all elements of bar to an array:

foo_pkg_setup() {
    exparam -a array bar[*]
}

The number of elements can be retrieved via exparam bar[#] and exparam bar is 
equivalent to exparam bar[0]. Any exparam command allows -v or -a arguments to 
assign the output to a variable or an array.

-- 
Bo Andresen

diff --git a/paludis/repositories/e/Makefile.am b/paludis/repositories/e/Makefile.am
index 402a30e..033741e 100644
--- a/paludis/repositories/e/Makefile.am
+++ b/paludis/repositories/e/Makefile.am
@@ -177,6 +177,20 @@ e_repository_TEST_ever_LDADD = \
 
 e_repository_TEST_ever_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) @PALUDIS_CXXFLAGS_NO_DEBUGGING@
 
+e_repository_TEST_exlibs = e_repository_TEST_exlibs.cc
+
+e_repository_TEST_exlibs_LDADD = \
+	libpaludisereposito...@[email protected] \
+	$(top_builddir)/paludis/repositories/fake/libpaludisfakereposito...@[email protected] \
+	$(top_builddir)/paludis/util/libpaludisut...@[email protected] \
+	$(top_builddir)/paludis/util/test_extras.o \
+	$(top_builddir)/paludis/libpalud...@[email protected] \
+	$(top_builddir)/paludis/environments/test/libpaludistestenvironme...@[email protected] \
+	$(top_builddir)/test/libtest.a \
+	$(DYNAMIC_LD_LIBS)
+
+e_repository_TEST_exlibs_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) @PALUDIS_CXXFLAGS_NO_DEBUGGING@
+
 vdb_repository_TEST_SOURCES = vdb_repository_TEST.cc
 
 vdb_repository_TEST_LDADD = \
@@ -357,6 +371,9 @@ EXTRA_DIST = \
 	e_repository_TEST_ever.cc \
 	e_repository_TEST_ever_setup.sh \
 	e_repository_TEST_ever_cleanup.sh \
+	e_repository_TEST_exlibs.cc \
+	e_repository_TEST_exlibs_setup.sh \
+	e_repository_TEST_exlibs_cleanup.sh \
 	e_repository_params-se.hh \
 	e_repository_params-se.cc \
 	e_repository_params.se \
@@ -401,6 +418,7 @@ BUILT_SOURCES = \
 check_SCRIPTS = \
 	e_repository_TEST_setup.sh e_repository_TEST_cleanup.sh \
 	e_repository_TEST_ever_setup.sh e_repository_TEST_ever_cleanup.sh \
+	e_repository_TEST_exlibs_setup.sh e_repository_TEST_exlibs_cleanup.sh \
 	xml_things_TEST_setup.sh xml_things_TEST_cleanup.sh \
 	vdb_repository_TEST_setup.sh vdb_repository_TEST_cleanup.sh \
 	exndbam_repository_TEST_setup.sh exndbam_repository_TEST_cleanup.sh \
@@ -488,6 +506,7 @@ TESTS = \
 	dep_spec_pretty_printer_TEST \
 	e_repository_TEST \
 	e_repository_TEST_ever \
+	e_repository_TEST_exlibs \
 	e_repository_sets_TEST \
 	ebuild_flat_metadata_cache_TEST \
 	exndbam_repository_TEST \
diff --git a/paludis/repositories/e/e_repository_TEST_exlibs.cc b/paludis/repositories/e/e_repository_TEST_exlibs.cc
new file mode 100644
index 0000000..8ac1b8a
--- /dev/null
+++ b/paludis/repositories/e/e_repository_TEST_exlibs.cc
@@ -0,0 +1,182 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008, 2009 Ciaran McCreesh
+ * Copyright (c) 2009 Bo Ørsted Andresen
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <paludis/repositories/e/e_repository.hh>
+#include <paludis/repositories/e/e_repository_exceptions.hh>
+#include <paludis/repositories/e/e_repository_id.hh>
+#include <paludis/repositories/e/vdb_repository.hh>
+#include <paludis/repositories/e/eapi.hh>
+#include <paludis/repositories/e/dep_spec_pretty_printer.hh>
+#include <paludis/repositories/fake/fake_installed_repository.hh>
+#include <paludis/repositories/fake/fake_package_id.hh>
+#include <paludis/environments/test/test_environment.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/simple_visitor_cast.hh>
+#include <paludis/util/map.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/set.hh>
+#include <paludis/package_id.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/action.hh>
+#include <paludis/stringify_formatter.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/generator.hh>
+#include <paludis/filter.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/selection.hh>
+#include <paludis/repository_factory.hh>
+#include <paludis/choice.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <tr1/functional>
+#include <set>
+#include <string>
+
+#include "config.h"
+
+using namespace test;
+using namespace paludis;
+
+namespace
+{
+    std::string from_keys(const std::tr1::shared_ptr<const Map<std::string, std::string> > & m,
+            const std::string & k)
+    {
+        Map<std::string, std::string>::ConstIterator mm(m->find(k));
+        if (m->end() == mm)
+            return "";
+        else
+            return mm->second;
+    }
+
+    void dummy_used_this_for_config_protect(const std::string &)
+    {
+    }
+
+    WantPhase want_all_phases(const std::string &)
+    {
+        return wp_yes;
+    }
+
+    enum ExpectedResult
+    {
+        success,
+        throws_UnsupportedActionError,
+        throws_InstallActionError
+    };
+
+    struct ExlibsTest : TestCase
+    {
+        const std::string test;
+        int expected_result;
+
+        ExlibsTest(const std::string & s, const ExpectedResult e) :
+            TestCase(s),
+            test(s),
+            expected_result(e)
+        {
+        }
+
+        unsigned max_run_time() const
+        {
+            return 3000;
+        }
+
+        bool repeatable() const
+        {
+            return false;
+        }
+
+        void run()
+        {
+            TestEnvironment env;
+            env.set_paludis_command("/bin/false");
+            std::tr1::shared_ptr<Map<std::string, std::string> > keys(new Map<std::string, std::string>);
+            keys->insert("format", "ebuild");
+            keys->insert("names_cache", "/var/empty");
+            keys->insert("location", stringify(FSEntry::cwd() / "e_repository_TEST_exlibs_dir" / "repo1"));
+            keys->insert("profiles", stringify(FSEntry::cwd() / "e_repository_TEST_exlibs_dir" / "repo1/profiles/profile"));
+            keys->insert("layout", "exheres");
+            keys->insert("eapi_when_unknown", "exheres-0");
+            keys->insert("eapi_when_unspecified", "exheres-0");
+            keys->insert("profile_eapi", "exheres-0");
+            keys->insert("distdir", stringify(FSEntry::cwd() / "e_repository_TEST_exlibs_dir" / "distdir"));
+            keys->insert("builddir", stringify(FSEntry::cwd() / "e_repository_TEST_exlibs_dir" / "build"));
+            std::tr1::shared_ptr<Repository> repo(ERepository::repository_factory_create(&env,
+                        std::tr1::bind(from_keys, keys, std::tr1::placeholders::_1)));
+            env.package_database()->add_repository(1, repo);
+
+            std::tr1::shared_ptr<FakeInstalledRepository> installed_repo(new FakeInstalledRepository(&env, RepositoryName("installed")));
+            env.package_database()->add_repository(2, installed_repo);
+
+            InstallAction action(make_named_values<InstallActionOptions>(
+                        value_for<n::destination>(installed_repo),
+                        value_for<n::used_this_for_config_protect>(&dummy_used_this_for_config_protect),
+                        value_for<n::want_phase>(&want_all_phases)
+                    ));
+
+            const std::tr1::shared_ptr<const PackageID> id(*env[selection::RequireExactlyOne(generator::Matches(
+                            PackageDepSpec(parse_user_package_dep_spec("cat/" + test,
+                                    &env, UserPackageDepSpecOptions())), MatchPackageOptions()))]->last());
+            TEST_CHECK(id);
+            switch (expected_result)
+            {
+                case success:
+                    id->perform_action(action);
+                    break;
+                case throws_InstallActionError:
+                    TEST_CHECK_THROWS(id->perform_action(action), InstallActionError);
+                    break;
+                case throws_UnsupportedActionError:
+                    TEST_CHECK_THROWS(id->perform_action(action), UnsupportedActionError);
+                    break;
+            }
+        }
+    };
+}
+
+namespace test_cases
+{
+    ExlibsTest test_require_success("require-success", success);
+    ExlibsTest test_require_fail("require-fail", throws_UnsupportedActionError);
+    ExlibsTest test_require_param("require-param", success);
+    ExlibsTest test_require_param_empty("require-param-empty", success);
+    ExlibsTest test_require_param_missing("require-param-missing", throws_UnsupportedActionError);
+    ExlibsTest test_require_param_undeclared("require-param-undeclared", throws_UnsupportedActionError);
+    ExlibsTest test_require_params("require-params", success);
+    ExlibsTest test_require_params_unaligned("require-params-unaligned", throws_UnsupportedActionError);
+    ExlibsTest test_require_multiple_params("require-multiple-params", success);
+    ExlibsTest test_require_multiple_params_spaces("require-multiple-params-spaces", success);
+    ExlibsTest test_require_param_default("require-param-default", success);
+    ExlibsTest test_require_param_default_spaces("require-multiple-params-default-spaces", success);
+    ExlibsTest test_exparam_banned("exparam-banned", throws_UnsupportedActionError);
+    ExlibsTest test_exparam_undeclared("exparam-undeclared", throws_InstallActionError);
+    ExlibsTest test_exparam_subshell("exparam-subshell", throws_InstallActionError); // cookies to he who finds a way to make this test succeed :(
+    ExlibsTest test_exarray("exarray", success);
+    ExlibsTest test_exarray_spaces("exarray-spaces", success);
+    ExlibsTest test_exarray_default("exarray-default", success);
+    ExlibsTest test_exarray_default_spaces("exarray-default-spaces", success);
+    ExlibsTest test_noarray("noarray", success);
+    ExlibsTest test_noarray_bad("noarray-bad", throws_UnsupportedActionError);
+    ExlibsTest test_scalar_required("scalar-required", throws_UnsupportedActionError);
+    ExlibsTest test_array_required("array-required", throws_UnsupportedActionError);
+}
+
diff --git a/paludis/repositories/e/e_repository_TEST_exlibs_cleanup.sh b/paludis/repositories/e/e_repository_TEST_exlibs_cleanup.sh
new file mode 100755
index 0000000..df39b52
--- /dev/null
+++ b/paludis/repositories/e/e_repository_TEST_exlibs_cleanup.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d e_repository_TEST_exlibs_dir ] ; then
+    rm -fr e_repository_TEST_exlibs_dir
+else
+    true
+fi
+
diff --git a/paludis/repositories/e/e_repository_TEST_exlibs_setup.sh b/paludis/repositories/e/e_repository_TEST_exlibs_setup.sh
new file mode 100755
index 0000000..f1099fd
--- /dev/null
+++ b/paludis/repositories/e/e_repository_TEST_exlibs_setup.sh
@@ -0,0 +1,381 @@
+#!/usr/bin/env bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir e_repository_TEST_exlibs_dir || exit 1
+cd e_repository_TEST_exlibs_dir || exit 1
+
+mkdir -p root/etc
+
+mkdir -p vdb
+touch vdb/THISISTHEVDB
+
+mkdir -p build
+ln -s build symlinked_build
+
+mkdir -p distdir
+
+mkdir -p repo1/{profiles/profile,metadata,eclass} || exit 1
+cd repo1 || exit 1
+echo "test-repo-1" >> profiles/repo_name || exit 1
+echo "cat" >> metadata/categories.conf || exit 1
+cat <<END > profiles/profile/make.defaults
+CHOST="i286-badger-linux-gnu"
+SUBOPTIONS="LINGUAS"
+LINGUAS="en en_GB en...@utf-8"
+USERLAND="GNU"
+OPTIONS="weasel spinach"
+END
+mkdir -p "packages/cat/require-success"
+cat <<'END' > packages/cat/require-success/foo.exlib || exit 1
+DESCRIPTION="The Long Description"
+SUMMARY="The Short Description"
+HOMEPAGE="http://example.com/";
+SLOT="0"
+LICENCES="GPL-2"
+export_exlib_phases src_unpack
+
+foo_src_unpack() {
+    [[ ${FOO} == true ]] || die "FOO unset"
+    touch ${PN}.foo
+}
+END
+cat <<'END' > packages/cat/require-success/require-success-1.ebuild || exit 1
+require foo
+PLATFORMS="test"
+FOO=true
+
+src_install() {
+    [[ ${SUMMARY} == "The Short Description" ]] || die "Bad SUMMARY"
+    [[ -e ${PN}.foo ]] || die "foo_src_unpack did not run"
+}
+END
+mkdir -p "packages/cat/require-fail"
+cat <<'END' > packages/cat/require-fail/require-fail-1.ebuild || exit 1
+require non-existant
+PLATFORMS="test"
+END
+mkdir -p "exlibs"
+cat <<'END' > exlibs/foo.exlib || exit 1
+SUMMARY="Short description"
+SLOT="0"
+END
+cat <<'END' > exlibs/foo-bar.exlib || exit 1
+SLOT="0"
+myexparam bar
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > exlibs/foo-bar-baz.exlib || exit 1
+SLOT="0"
+myexparam bar=baz
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > exlibs/monkey.exlib
+myexparam blah
+DESCRIPTION=$(exparam blah)
+END
+mkdir -p "packages/cat/require-param"
+cat <<'END' > packages/cat/require-param/require-param-1.ebuild || exit 1
+require foo-bar [ bar=baz ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == baz ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/require-param-empty"
+cat <<'END' > packages/cat/require-param-empty/require-param-empty-1.ebuild || exit 1
+require foo-bar [ bar= ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ -z ${SUMMARY} && ${SUMMARY+set} == set ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/require-param-missing"
+cat <<'END' > packages/cat/require-param-missing/require-param-missing-1.ebuild || exit 1
+require foo-bar
+PLATFORMS="test"
+END
+mkdir -p "packages/cat/require-param-undeclared"
+cat <<'END' > packages/cat/require-param-undeclared/require-param-undeclared-1.ebuild || exit 1
+require foo [ bar=baz ]
+PLATFORMS="test"
+END
+mkdir -p "packages/cat/require-params"
+cat <<'END' > packages/cat/require-params/require-params-1.ebuild || exit 1
+require foo-bar [[[ bar=baz ]]] monkey [ blah=bleh ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == baz ]] || die "Bad SUMMARY"
+    [[ ${DESCRIPTION} == bleh ]] || die "Bad DESCRIPTION"
+}
+END
+mkdir -p "packages/cat/require-params-unaligned"
+cat <<'END' > packages/cat/require-params-unaligned/require-params-unaligned-1.ebuild || exit 1
+require foo-bar [[[ bar=baz ] monkey [ blah=bleh ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == baz ]] || die "Bad SUMMARY"
+    [[ ${DESCRIPTION} == bleh ]] || die "Bad DESCRIPTION"
+}
+END
+mkdir -p "packages/cat/require-multiple-params"
+cat <<'END' > packages/cat/require-multiple-params/foo.exlib || exit 1
+myexparam foo
+myexparam bar
+SUMMARY=$(exparam foo)$(exparam bar)
+END
+cat <<'END' > packages/cat/require-multiple-params/require-multiple-params-1.ebuild || exit 1
+require foo [ foo=1 bar=2 ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == 12 ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/require-multiple-params-spaces"
+cat <<'END' > packages/cat/require-multiple-params-spaces/foo.exlib || exit 1
+myexparam foo
+myexparam bar
+SUMMARY=$(exparam foo)-$(exparam bar)
+END
+cat <<'END' > packages/cat/require-multiple-params-spaces/require-multiple-params-spaces-1.ebuild || exit 1
+require foo [ foo="f o o " bar=" b a r" ]
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == "f o o - b a r" ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/require-param-default"
+cat <<'END' > packages/cat/require-param-default/require-param-default-1.ebuild || exit 1
+require foo-bar-baz
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == baz ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/require-multiple-params-default-spaces"
+cat <<'END' > packages/cat/require-multiple-params-default-spaces/foo.exlib || exit 1
+myexparam foo="f o o "
+myexparam bar=" b a r"
+SUMMARY=$(exparam foo)-$(exparam bar)
+END
+cat <<'END' > packages/cat/require-multiple-params-default-spaces/require-multiple-params-default-spaces-1.ebuild || exit 1
+require foo
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ ${SUMMARY} == "f o o - b a r" ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/exparam-banned"
+cat <<'END' > packages/cat/exparam-banned/exparam-banned-1.ebuild || exit 1
+PLATFORMS="test"
+exparam foo
+END
+mkdir -p "packages/cat/exparam-undeclared"
+cat <<'END' > packages/cat/exparam-undeclared/foo.exlib || exit 1
+get_bar() {
+    exparam bar
+}
+END
+cat <<'END' > packages/cat/exparam-undeclared/exparam-undeclared-1.ebuild || exit 1
+require foo
+PLATFORMS="test"
+
+pkg_setup() {
+    [[ $(get_bar) == baz ]]
+}
+END
+mkdir -p "packages/cat/exparam-subshell"
+cat <<'END' > packages/cat/exparam-subshell/foo.exlib || exit 1
+myexparam bar
+check_bar() {
+    [[ $(exparam bar) == baz ]] || die "exparam in subshell failed"
+}
+END
+cat <<'END' > packages/cat/exparam-subshell/exparam-subshell-1.ebuild || exit 1
+require foo [ bar=baz ]
+
+pkg_setup() {
+    check_bar
+}
+END
+mkdir -p "packages/cat/exarray"
+cat <<'END' > packages/cat/exarray/foo.exlib || exit 1
+myexparam bar[]
+
+check_foo() {
+    exparam bar[#] | grep -q ^3$ || die "Bad bar[#]"
+    exparam bar[0] | grep -q ^1$ || die "Bad bar[0]"
+    exparam bar[1] | grep -q ^2$ || die "Bad bar[1]"
+    exparam bar[2] | grep -q ^3$ || die "Bad bar[2]"
+    exparam bar[3] | grep -q ^$ || die "Bad bar[3]"
+    exparam -a FOOA  bar[*]
+    exparam -v FOOV  bar[*]
+    exparam -a FOOA0 bar
+    exparam -v FOO   bar
+    exparam -v FOO0  bar[0]
+    exparam -v FOO1  bar[1]
+    exparam -v FOO2  bar[2]
+    exparam -v FOO3  bar[3]
+    exparam -v FOOC  bar[#]
+}
+END
+cat <<'END' > packages/cat/exarray/exarray-1.ebuild || exit 1
+require foo [ bar=[ 1 2 3 ] ]
+PLATFORMS="test"
+
+pkg_setup() {
+    check_foo || die "check_foo returned errror"
+    [[ ${#fo...@]} -eq 3 ]] || die "Wrong number of elements, ${#fo...@]} in fo...@]"
+    [[ ${FOOA[0]} == 1 ]] || die "Bad FOOA[0]"
+    [[ ${FOOA[1]} == 2 ]] || die "Bad FOOA[1]"
+    [[ ${FOOA[2]} == 3 ]] || die "Bad FOOA[2]"
+    [[ ${fo...@]} == "1 2 3" ]] || die "fo...@] != 1 2 3"
+    [[ ${#fo...@]} -eq 1 ]] || die "Wrong number of elements, ${#fo...@]} in fo...@]"
+    [[ ${fo...@]} == "1 2 3" ]] || die "fo...@] != 1 2 3"
+    [[ ${FOOA0} == 1 ]] || die "Bad FOOA0"
+    [[ $(declare -p FOOA0) == declare\ -a\ FOOA0=* ]] || die "FOOA0 is not an array"
+    [[ ${FOO} == 1 ]] || die "Bad FOO"
+    [[ ${FOO0} == 1 ]] || die "Bad FOO0"
+    [[ ${FOO1} == 2 ]] || die "Bad FOO1"
+    [[ ${FOO2} == 3 ]] || die "Bad FOO2"
+    [[ -z ${FOO3} ]] || die "Bad FOO3"
+    [[ ${FOOC} -eq 3 ]] || die "Bad FOOC"
+}
+END
+mkdir -p "packages/cat/exarray-spaces"
+cat <<'END' > packages/cat/exarray-spaces/foo.exlib || exit 1
+myexparam bar[]
+
+check_foo() {
+    exparam bar[#] | grep -q ^3$ || die "Bad bar[#]"
+    exparam bar[0] | grep -q '^1 1$' || die "Bad bar[0]"
+    exparam bar[1] | grep -q '^2 2$' || die "Bad bar[1]"
+    exparam bar[2] | grep -q '^3 3$' || die "Bad bar[2]"
+    exparam bar[3] | grep -q ^$ || die "Bad bar[3]"
+    exparam -a FOO bar[*]
+}
+END
+cat <<'END' > packages/cat/exarray-spaces/exarray-spaces-1.ebuild || exit 1
+require foo [ bar=[ "1 1" "2 2" "3 3" ] ]
+PLATFORMS="test"
+
+pkg_setup() {
+    check_foo || die "check_foo returned errror"
+    [[ ${#f...@]} -eq 3 ]] || die "Wrong number of elements, ${#f...@]} in f...@]"
+    [[ ${FOO[0]} == "1 1" ]] || die "Bad FOO[0]"
+    [[ ${FOO[1]} == "2 2" ]] || die "Bad FOO[1]"
+    [[ ${FOO[2]} == "3 3" ]] || die "Bad FOO[2]"
+    [[ ${f...@]} == "1 1 2 2 3 3" ]] || die "f...@] != 1 1 2 2 3 3"
+}
+END
+mkdir -p "packages/cat/exarray-default"
+cat <<'END' > packages/cat/exarray-default/foo.exlib || exit 1
+myexparam bar=[ 1 2 3 ]
+
+check_foo() {
+    exparam bar[#] | grep -q ^3$ || die "Bad bar[#]"
+    exparam bar[0] | grep -q ^1$ || die "Bad bar[0]"
+    exparam bar[1] | grep -q ^2$ || die "Bad bar[1]"
+    exparam bar[2] | grep -q ^3$ || die "Bad bar[2]"
+    exparam bar[3] | grep -q ^$ || die "Bad bar[3]"
+    exparam -a FOO bar[*]
+}
+END
+cat <<'END' > packages/cat/exarray-default/exarray-default-1.ebuild || exit 1
+require foo
+PLATFORMS="test"
+
+pkg_setup() {
+    check_foo || die "check_foo returned errror"
+    [[ ${#f...@]} -eq 3 ]] || die "Wrong number of elements, ${#f...@]} in f...@]"
+    [[ ${FOO[0]} == 1 ]] || die "Bad FOO[0]"
+    [[ ${FOO[1]} == 2 ]] || die "Bad FOO[1]"
+    [[ ${FOO[2]} == 3 ]] || die "Bad FOO[2]"
+    [[ ${f...@]} == "1 2 3" ]] || die "f...@] != 1 2 3"
+}
+END
+mkdir -p "packages/cat/exarray-default-spaces"
+cat <<'END' > packages/cat/exarray-default-spaces/foo.exlib || exit 1
+myexparam bar=[ "1 1" "2 2" "3 3" ]
+
+check_foo() {
+    exparam bar[#] | grep -q ^3$ || die "Bad bar[#]"
+    exparam bar[0] | grep -q '^1 1$' || die "Bad bar[0]"
+    exparam bar[1] | grep -q '^2 2$' || die "Bad bar[1]"
+    exparam bar[2] | grep -q '^3 3$' || die "Bad bar[2]"
+    exparam bar[3] | grep -q ^$ || die "Bad bar[3]"
+    exparam -a FOO bar[*]
+}
+END
+cat <<'END' > packages/cat/exarray-default-spaces/exarray-default-spaces-1.ebuild || exit 1
+require foo
+PLATFORMS="test"
+
+pkg_setup() {
+    check_foo || die "check_foo returned errror"
+    [[ ${#f...@]} -eq 3 ]] || die "Wrong number of elements, ${#f...@]} in f...@]"
+    [[ ${FOO[0]} == "1 1" ]] || die "Bad FOO[0]"
+    [[ ${FOO[1]} == "2 2" ]] || die "Bad FOO[1]"
+    [[ ${FOO[2]} == "3 3" ]] || die "Bad FOO[2]"
+    [[ ${f...@]} == "1 1 2 2 3 3" ]] || die "f...@] != 1 1 2 2 3 3"
+}
+END
+mkdir -p "packages/cat/noarray"
+cat <<'END' > packages/cat/noarray/foo.exlib || exit 1
+myexparam bar
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > packages/cat/noarray/noarray-1.ebuild || exit 1
+require foo [[ bar=[ ]]
+
+pkg_setup() {
+    [[ ${SUMMARY} == "[" ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/noarray-bad"
+cat <<'END' > packages/cat/noarray-bad/foo.exlib || exit 1
+myexparam bar
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > packages/cat/noarray-bad/noarray-bad-1.ebuild || exit 1
+require foo [ bar=[ ]
+
+pkg_setup() {
+    [[ ${SUMMARY} == "[" ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/scalar-required"
+cat <<'END' > packages/cat/scalar-required/foo.exlib || exit 1
+myexparam bar
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > packages/cat/scalar-required/scalar-required-1.ebuild || exit 1
+require foo [ bar=[ baz ] ]
+
+pkg_setup() {
+    [[ ${SUMMARY} == "baz" ]] || die "Bad SUMMARY"
+}
+END
+mkdir -p "packages/cat/array-required"
+cat <<'END' > packages/cat/array-required/foo.exlib || exit 1
+myexparam bar[]
+SUMMARY=$(exparam bar)
+END
+cat <<'END' > packages/cat/array-required/array-required-1.ebuild || exit 1
+require foo [ bar=baz ]
+
+pkg_setup() {
+    [[ ${SUMMARY} == "baz" ]] || die "Bad SUMMARY"
+}
+END
+cd ..
+
+cd ..
+
diff --git a/paludis/repositories/e/ebuild/ebuild.bash b/paludis/repositories/e/ebuild/ebuild.bash
index 7853237..8fa7ca6 100755
--- a/paludis/repositories/e/ebuild/ebuild.bash
+++ b/paludis/repositories/e/ebuild/ebuild.bash
@@ -285,6 +285,7 @@ ebuild_scrub_environment()
                 echo E_${v}
             done )
         unset -v ${!PALUDIS_*}
+        unset -v ${!EXPARAMVAR_*}
 
         unset -v $(
             for v in ${!SANDBOX_*}; do
diff --git a/paludis/repositories/e/ebuild/exheres-0/exlib_functions.bash b/paludis/repositories/e/ebuild/exheres-0/exlib_functions.bash
index 2cae338..b750d7c 100644
--- a/paludis/repositories/e/ebuild/exheres-0/exlib_functions.bash
+++ b/paludis/repositories/e/ebuild/exheres-0/exlib_functions.bash
@@ -2,6 +2,7 @@
 # vim: set sw=4 sts=4 et :
 
 # Copyright (c) 2007, 2008 Ciaran McCreesh
+# Copyright (c) 2009 Bo Ørsted Andresen
 #
 # This file is part of the Paludis package manager. Paludis is free software;
 # you can redistribute it and/or modify it under the terms of the GNU General
@@ -29,17 +30,124 @@ export_exlib_phases()
     done
 }
 
+exparam()
+{
+    die "exparam is banned outside exlibs"
+}
+
+exparam_var_name()
+{
+    echo EXPARAMVAR_${1//-/__dash__}
+}
+
+exparam_print()
+{
+    case "${1}" in
+        -a) eval "${2}=( \"\${${3}}\" )" ;;
+        -v) eval "${2}=\"\${${3}}\""      ;;
+        *)  eval "echo \"\${${1}}\""     ;;
+    esac
+}
+
+exparam_internal()
+{
+    local i e=${1} a to_var v a_v=$(exparam_var_name ${1})__ALLDECLS__
+    shift
+    if [[ ${1} == -[av] ]]; then
+        [[ ${#} -eq 3 ]] || die "exparam ${1} requires exactly three arguments"
+        a=${1}
+        to_var=${2}
+        shift 2
+    else
+        [[ ${#} -eq 1 ]] || die "exparam requires exactly one argument"
+    fi
+    v=$(exparam_var_name ${e})_${1%\[*}
+    if [[ ${1} == *\[*\] ]]; then
+        has "${1%\[*}[]" ${!a_v} || die "${e}.exlib has no ${1%\[*} array"
+        i=${1#*\[}
+        i=${i%\]}
+        case "${i}" in
+            "#")            exparam_print ${to_var:+${a} "${to_var}"} "#${v}[*]"   ;;
+            "*")            exparam_print ${to_var:+${a} "${to_var}"} "${...@]"    ;;
+            +([[:digit:]])) exparam_print ${to_var:+${a} "${to_var}"} "${v}[${i}]" ;;
+            *)              die "Invalid index in exparam ${1}"          ;;
+        esac
+    else
+        has "${1}" ${!a_v%\[\]} || die "${e}.exlib has no ${1} parameter"
+        exparam_print ${to_var:+${a} "${to_var}"} "${v}"
+    fi
+}
+
+myexparam()
+{
+    [[ -z "${CURRENT_EXLIB}" ]] && die "myexparam called but CURRENT_EXLIB undefined"
+
+    local v=${1%%=*} a_v="$(exparam_var_name ${CURRENT_EXLIB})__ALLDECLS__"
+    [[ ${1} == *=\[ && ${#} -gt 1 ]] && v+="[]"
+    printf -v "${a_v}" "%s %s" "${!a_v}" "${v}"
+
+    v=$(exparam_var_name ${CURRENT_EXLIB})_${v%\[\]}
+    if [[ -z ${!v+set} && ${1} == *=* ]]; then
+        if [[ ${1} == *=\[ && ${#} -gt 1 ]]; then
+            shift
+            local i a=()
+            while [[ ${#} -gt 1 ]]; do
+                a+=( "${1}" )
+                shift
+            done
+            [[ ${1} == \] ]] || die "Array encountered with no closing ]"
+            eval "${v}=( \"\$...@]}\" )"
+        else
+            printf -v "${v}" "%s" "${1#*=}"
+        fi
+    fi
+}
+
 require()
 {
     ebuild_notice "debug" "Command 'require $...@}', using EXLIBSDIRS '${EXLIBSDIRS}'"
-    local e ee location v v_qa
-    for e in "$@" ; do
+    local exlibs e ee p a=() location v a_v v_qa
+    # parse exlib parameters
+    while [[ -n $@ ]]; do
+        if [[ ${1} == +(\[) ]]; then
+            [[ -z ${e} ]] && die "\"${1}\" encountered with no preceding exlib"
+            p=${1}
+            shift
+            while [[ -n ${1} && ${1} != ${p//\[/\]} ]]; do
+                v="${1%%=*}"
+                if [[ ${1#*=} == ${p} ]]; then
+                    v+="[]"
+                    a=()
+                    shift
+                    while [[ -n ${1} && ${1} != ${p//\[/\]} ]]; do
+                        a+=( "${1}" )
+                        shift
+                    done
+                    [[ ${1} == ${p//\[/\]} ]] || die "\"${p}\" encountered with no closing \"${p//\[/\]}\" for array ${v}"
+                    eval "$(exparam_var_name ${e})_${v%\[\]}=( \"\$...@]}\" )"
+                else
+                    printf -v "$(exparam_var_name ${e})_${1%%=*}" "%s" "${1#*=}"
+                fi
+                a_v="$(exparam_var_name ${e})__ALL__"
+                printf -v "${a_v}" "%s %s" "${!a_v}" "${v}"
+                shift
+            done
+            [[ ${1} == ${p//\[/\]} ]] || die "\"${p}\" encountered with no closing \"${p//\[/\]}\""
+        else
+            e=${1}
+            exlibs+=" ${e}"
+        fi
+        shift
+    done
+    # source exlibs
+    for e in ${exlibs}; do
         location=
         for ee in ${EXLIBSDIRS} ; do
             [[ -f "${ee}/${e}.exlib" ]] && location="${ee}/${e}.exlib"
         done
         local old_CURRENT_EXLIB="${CURRENT_EXLIB}"
         export CURRENT_EXLIB="${e}"
+        alias exparam="exparam_internal ${CURRENT_EXLIB}"
 
         for v in ${PALUDIS_SOURCE_MERGED_VARIABLES} ${PALUDIS_BRACKET_MERGED_VARIABLES} ; do
             local c_v="current_${v}" u_v="unset_${v}"
@@ -88,7 +196,34 @@ require()
             fi
         done
 
+        # die on required exlib parameters that haven't been supplied
+        local c_v v
+        a_v=$(exparam_var_name ${CURRENT_EXLIB})__ALLDECLS__
+        for v in ${!a_v}; do
+            c_v=$(exparam_var_name ${CURRENT_EXLIB})_${v%\[\]}
+            if [[ -n ${!c_v+set} ]]; then
+                if [[ $(eval "declare -p ${c_v}") == declare\ -a\ ${c_v}=* ]]; then
+                    [[ ${v} == *\[\] ]] || die "${CURRENT_EXLIB}.exlib requires a scalar ${v} parameter but got an array"
+                else
+                    [[ ${v} != *\[\] ]] || die "${CURRENT_EXLIB}.exlib requires an array ${v} but got a scalar"
+                fi
+            else
+                die "${CURRENT_EXLIB}.exlib requires a ${v} parameter"
+            fi
+        done
+
+        # die on supplied exlib parameters which haven't been declared
+        v=$(exparam_var_name ${CURRENT_EXLIB})__ALL__
+        for v in ${!v}; do
+            has ${v} ${!a_v} || die "${CURRENT_EXLIB}.exlib takes no ${v} parameter"
+        done
+
         export CURRENT_EXLIB="${old_CURRENT_EXLIB}"
+        if [[ -n ${CURRENT_EXLIB} ]]; then
+            alias exparam="exparam_internal ${CURRENT_EXLIB}"
+        else
+            unalias exparam
+        fi
     done
 }
 
_______________________________________________
Exherbo-dev mailing list
[email protected]
http://lists.exherbo.org/mailman/listinfo/exherbo-dev

Reply via email to