[paludis-commits] r4121 - in trunk: . paludis/repositories/e paludis/repositories/e/eapis paludis/repositories/e/ebuild paludis/repositories/e/ebuild/exheres-0 paludis/repositories/e/ebuild/utils paludis/util

ciaranm at svn.pioto.org ciaranm at svn.pioto.org
Mon Dec 31 21:47:27 UTC 2007


Author: ciaranm
Date: 2007-12-31 21:47:26 +0000 (Mon, 31 Dec 2007)
New Revision: 4121

Added:
   trunk/paludis/repositories/e/ebuild/utils/locked_pipe_command.cc
Modified:
   trunk/ChangeLog
   trunk/paludis/repositories/e/e_repository_TEST.cc
   trunk/paludis/repositories/e/e_repository_TEST_setup.sh
   trunk/paludis/repositories/e/eapi-fwd.hh
   trunk/paludis/repositories/e/eapi.cc
   trunk/paludis/repositories/e/eapi.sr
   trunk/paludis/repositories/e/eapis/0.conf
   trunk/paludis/repositories/e/eapis/1.conf
   trunk/paludis/repositories/e/eapis/exheres-0.conf
   trunk/paludis/repositories/e/eapis/paludis-1.conf
   trunk/paludis/repositories/e/ebuild.cc
   trunk/paludis/repositories/e/ebuild.hh
   trunk/paludis/repositories/e/ebuild/ebuild.bash
   trunk/paludis/repositories/e/ebuild/echo_functions.bash.in
   trunk/paludis/repositories/e/ebuild/exheres-0/echo_functions.bash.in
   trunk/paludis/repositories/e/ebuild/exheres-0/portage_stubs.bash
   trunk/paludis/repositories/e/ebuild/portage_stubs.bash
   trunk/paludis/repositories/e/ebuild/run_test.bash
   trunk/paludis/repositories/e/ebuild/utils/Makefile.am
   trunk/paludis/util/system.cc
   trunk/paludis/util/system_TEST_setup.sh
Log:
Switch to using pipes to implement has_version etc.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/ChangeLog	2007-12-31 21:47:26 UTC (rev 4121)
@@ -7,6 +7,10 @@
 
 2007-12-31 Ciaran McCreesh
 
+	* paludis/: Switch to using pipes to implement has_version etc.
+
+2007-12-31 Ciaran McCreesh
+
 	* paludis/util/: Make LogLevel use a .se.
 
 2007-12-31 David Leverton

Modified: trunk/paludis/repositories/e/e_repository_TEST.cc
===================================================================
--- trunk/paludis/repositories/e/e_repository_TEST.cc	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/e_repository_TEST.cc	2007-12-31 21:47:26 UTC (rev 4121)
@@ -23,6 +23,8 @@
 #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/repository_maker.hh>
 #include <paludis/environments/test/test_environment.hh>
 #include <paludis/util/system.hh>
 #include <paludis/util/visitor-impl.hh>
@@ -1039,6 +1041,7 @@
         void run()
         {
             TestEnvironment env;
+
             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");
@@ -1054,8 +1057,16 @@
             env.package_database()->add_repository(1, repo);
 
             tr1::shared_ptr<FakeInstalledRepository> installed_repo(new FakeInstalledRepository(&env, RepositoryName("installed")));
+            installed_repo->add_version("cat", "pretend-installed", "0")->provide_key()->set_from_string("virtual/virtual-pretend-installed");
+            installed_repo->add_version("cat", "pretend-installed", "1")->provide_key()->set_from_string("virtual/virtual-pretend-installed");
             env.package_database()->add_repository(2, installed_repo);
 
+            tr1::shared_ptr<Map<std::string, std::string> > iv_keys(new Map<std::string, std::string>);
+            iv_keys->insert("root", "/");
+            env.package_database()->add_repository(-2, RepositoryMaker::get_instance()->find_maker("installed_virtuals")(&env, iv_keys));
+            env.package_database()->add_repository(-2, RepositoryMaker::get_instance()->find_maker("virtuals")(&env,
+                        tr1::shared_ptr<Map<std::string, std::string> >()));
+
             InstallAction action(InstallActionOptions::create()
                     .debug_build(iado_none)
                     .checks(iaco_default)
@@ -1064,6 +1075,13 @@
                     );
 
             {
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=virtual/virtual-pretend-installed-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+            }
+
+            {
                 TestMessageSuffix suffix("in-ebuild die", true);
                 const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
                                 PackageDepSpec(parse_user_package_dep_spec("cat/in-ebuild-die",
@@ -1117,6 +1135,33 @@
                 TEST_CHECK_EQUAL(visitor_cast<const MetadataStringKey>(**id->find_metadata("EAPI"))->value(), "0");
                 TEST_CHECK_THROWS(id->perform_action(action), InstallActionError);
             }
+
+            {
+                TestMessageSuffix suffix("best version", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/best-version-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                id->perform_action(action);
+            }
+
+            {
+                TestMessageSuffix suffix("has version", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/has-version-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                id->perform_action(action);
+            }
+
+            {
+                TestMessageSuffix suffix("match", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/match-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                id->perform_action(action);
+            }
         }
     } test_e_repository_install_eapi_0;
 
@@ -1195,8 +1240,16 @@
             env.package_database()->add_repository(1, repo);
 
             tr1::shared_ptr<FakeInstalledRepository> installed_repo(new FakeInstalledRepository(&env, RepositoryName("installed")));
+            installed_repo->add_version("cat", "pretend-installed", "0")->provide_key()->set_from_string("virtual/virtual-pretend-installed");
+            installed_repo->add_version("cat", "pretend-installed", "1")->provide_key()->set_from_string("virtual/virtual-pretend-installed");
             env.package_database()->add_repository(2, installed_repo);
 
+            tr1::shared_ptr<Map<std::string, std::string> > iv_keys(new Map<std::string, std::string>);
+            iv_keys->insert("root", "/");
+            env.package_database()->add_repository(-2, RepositoryMaker::get_instance()->find_maker("installed_virtuals")(&env, iv_keys));
+            env.package_database()->add_repository(-2, RepositoryMaker::get_instance()->find_maker("virtuals")(&env,
+                        tr1::shared_ptr<Map<std::string, std::string> >()));
+
             InstallAction action(InstallActionOptions::create()
                     .debug_build(iado_none)
                     .checks(iaco_default)
@@ -1248,6 +1301,33 @@
                 TEST_CHECK(id);
                 TEST_CHECK_THROWS(id->perform_action(action), InstallActionError);
             }
+
+            {
+                TestMessageSuffix suffix("best version", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/best-version-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                id->perform_action(action);
+            }
+
+            {
+                TestMessageSuffix suffix("has version", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/has-version-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                id->perform_action(action);
+            }
+
+            {
+                TestMessageSuffix suffix("match", true);
+                const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+                                PackageDepSpec(parse_user_package_dep_spec("=cat/match-0",
+                                        UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+                TEST_CHECK(id);
+                TEST_CHECK_THROWS(id->perform_action(action), InstallActionError);
+            }
         }
     } test_e_repository_install_exheres_0;
 }

Modified: trunk/paludis/repositories/e/e_repository_TEST_setup.sh
===================================================================
--- trunk/paludis/repositories/e/e_repository_TEST_setup.sh	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/e_repository_TEST_setup.sh	2007-12-31 21:47:26 UTC (rev 4121)
@@ -4,6 +4,9 @@
 mkdir e_repository_TEST_dir || exit 1
 cd e_repository_TEST_dir || exit 1
 
+mkdir -p vdb
+touch vdb/THISISTHEVDB
+
 mkdir -p build
 
 mkdir -p distdir
@@ -477,6 +480,10 @@
 cd repo13 || exit 1
 echo "test-repo-13" >> profiles/repo_name || exit 1
 echo "cat" >> profiles/categories || exit 1
+cat <<END > profiles/profile/virtuals
+virtual/virtual-pretend-installed cat/pretend-installed
+virtual/virtual-doesnotexist cat/doesnotexist
+END
 cat <<END > profiles/profile/make.defaults
 ARCH="test"
 USERLAND="GNU"
@@ -556,6 +563,20 @@
     emake monkey
 }
 END
+mkdir -p "cat/pretend-installed"
+cat <<END > cat/pretend-installed/pretend-installed-2.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+IUSE="spork"
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+src_compile() {
+    die "not supposed to install this"
+}
+END
 mkdir -p "cat/econf-source"
 cat <<END > cat/econf-source/econf-source-0.ebuild || exit 1
 EAPI="\${PV}"
@@ -582,11 +603,107 @@
 }
 END
 cp cat/econf-source/econf-source-{0,1}.ebuild || exit 1
+mkdir -p "cat/best-version"
+cat <<'END' > cat/best-version/best-version-0.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+IUSE="spork"
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+pkg_setup() {
+    if ! best_version cat/pretend-installed >/dev/null ; then
+        die "failed cat/pretend-installed"
+    fi
+
+    BV1=$(best_version cat/pretend-installed )
+    [[ "$BV1" == "cat/pretend-installed-1" ]] || die "BV1 is $BV1"
+
+    if best_version cat/doesnotexist >/dev/null ; then
+        die "not failed cat/doesnotexist"
+    fi
+
+    BV2=$(best_version cat/doesnotexist )
+    [[ "$BV2" == "" ]] || die "BV2 is $BV2"
+
+    if ! best_version virtual/virtual-pretend-installed >/dev/null ; then
+        die "failed virtual/virtual-pretend-installed"
+    fi
+
+    BV3=$(best_version virtual/virtual-pretend-installed )
+    [[ "$BV3" == "cat/pretend-installed-1" ]] || die "BV3 is $BV3"
+
+    if best_version virtual/virtual-doesnotexist >/dev/null ; then
+        die "not failed virtual/virtual-doesnotexist"
+    fi
+
+    BV2=$(best_version virtual/virtual-doesnotexist )
+    [[ "$BV4" == "" ]] || die "BV4 is $BV4"
+}
+END
+mkdir -p "cat/has-version"
+cat <<'END' > cat/has-version/has-version-0.ebuild || exit 1
+EAPI="${PV}"
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+IUSE="spork"
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+pkg_setup() {
+    if ! has_version cat/pretend-installed ; then
+        die "failed cat/pretend-installed"
+    fi
+
+    if has_version cat/doesnotexist >/dev/null ; then
+        die "not failed cat/doesnotexist"
+    fi
+}
+END
+mkdir -p "cat/match"
+cat <<'END' > cat/match/match-0.ebuild || exit 1
+EAPI="${PV}"
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+IUSE="spork"
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+pkg_setup() {
+    if ! portageq match "${ROOT}" cat/pretend-installed >/dev/null ; then
+        die "failed cat/pretend-installed"
+    fi
+
+    cat <<'DONE' > ${T}/expected
+cat/pretend-installed-0
+cat/pretend-installed-1
+DONE
+    portageq match "${ROOT}" cat/pretend-installed > ${T}/got
+    cmp ${T}/expected ${T}/got || die "oops"
+
+    if portageq match "${ROOT}" cat/doesnotexist >/dev/null ; then
+        die "not failed cat/doesnotexist"
+    fi
+
+    BV2=$(portageq match "${ROOT}" cat/doesnotexist )
+    [[ "$BV2" == "" ]] || die "BV2 is $BV2"
+}
+END
 cd ..
 
 mkdir -p repo14/{profiles/profile,metadata,eclass} || exit 1
 cd repo14 || exit 1
 echo "test-repo-14" >> profiles/repo_name || exit 1
+cat <<END > profiles/profile/virtuals
+virtual/virtual-pretend-installed cat/pretend-installed
+virtual/virtual-doesnotexist cat/doesnotexist
+END
 echo "cat" >> metadata/categories.conf || exit 1
 cat <<END > profiles/profile/make.defaults
 CHOST="i286-badger-linux-gnu"
@@ -663,6 +780,83 @@
     emake monkey
 }
 END
+mkdir -p "packages/cat/best-version"
+cat <<'END' > packages/cat/best-version/best-version-0.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+MYOPTIONS="spork"
+LICENSE="GPL-2"
+PLATFORMS="test"
+
+pkg_setup() {
+    if ! best_version cat/pretend-installed >/dev/null ; then
+        die "failed cat/pretend-installed"
+    fi
+
+    BV1=$(best_version cat/pretend-installed )
+    [[ "$BV1" == "cat/pretend-installed-1:0::installed" ]] || die "BV1 is $BV1"
+
+    if best_version cat/doesnotexist >/dev/null ; then
+        die "not failed cat/doesnotexist"
+    fi
+
+    BV2=$(best_version cat/doesnotexist )
+    [[ "$BV2" == "" ]] || die "BV2 is $BV2"
+
+    if ! best_version virtual/virtual-pretend-installed >/dev/null ; then
+        die "failed virtual/virtual-pretend-installed"
+    fi
+
+    BV3=$(best_version virtual/virtual-pretend-installed )
+    [[ "$BV3" == "virtual/virtual-pretend-installed-1::installed-virtuals (virtual for cat/pretend-installed-1:0::installed)" ]] \
+        || die "BV3 is $BV3"
+
+    if best_version virtual/virtual-doesnotexist >/dev/null ; then
+        die "not failed virtual/virtual-doesnotexist"
+    fi
+
+    BV2=$(best_version virtual/virtual-doesnotexist )
+    [[ "$BV4" == "" ]] || die "BV4 is $BV4"
+}
+END
+mkdir -p "packages/cat/has-version"
+cat <<'END' > packages/cat/has-version/has-version-0.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+MYOPTIONS="spork"
+LICENSE="GPL-2"
+PLATFORMS="test"
+
+pkg_setup() {
+    if ! has_version cat/pretend-installed ; then
+        die "failed cat/pretend-installed"
+    fi
+
+    if has_version cat/doesnotexist >/dev/null ; then
+        die "not failed cat/doesnotexist"
+    fi
+}
+END
+mkdir -p "packages/cat/match"
+cat <<'END' > packages/cat/match/match-0.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+MYOPTIONS="spork"
+LICENSE="GPL-2"
+PLATFORM="test"
+
+pkg_setup() {
+    portageq match "${ROOT}" cat/foo | while read a ; do
+        einfo moo
+    done
+}
+END
 cd ..
 
 mkdir -p repo15/{eclass,distfiles,profiles/profile/subprofile} || exit 1

Modified: trunk/paludis/repositories/e/eapi-fwd.hh
===================================================================
--- trunk/paludis/repositories/e/eapi-fwd.hh	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapi-fwd.hh	2007-12-31 21:47:26 UTC (rev 4121)
@@ -33,6 +33,7 @@
         class EAPIEbuildEnvironmentVariables;
         class EAPIEbuildOptions;
         class EAPILabels;
+        class EAPIPipeCommands;
     }
 }
 

Modified: trunk/paludis/repositories/e/eapi.cc
===================================================================
--- trunk/paludis/repositories/e/eapi.cc	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapi.cc	2007-12-31 21:47:26 UTC (rev 4121)
@@ -122,6 +122,11 @@
                                                 .restrict_primaryuri(make_shared_ptr(new Set<std::string>))
                                                 )))
 
+                                                .pipe_commands(make_shared_ptr(new EAPIPipeCommands(
+                                                                EAPIPipeCommands::create()
+                                                                .rewrite_virtuals(destringify<bool>(k.get("pipe_commands_rewrite_virtuals")))
+                                                                .no_slot_or_repo(destringify<bool>(k.get("pipe_commands_no_slot_or_repo"))))))
+
                                                 .ebuild_phases(make_shared_ptr(new EAPIEbuildPhases(
                                                                 EAPIEbuildPhases::create()
                                                                 .ebuild_install(k.get("ebuild_install"))

Modified: trunk/paludis/repositories/e/eapi.sr
===================================================================
--- trunk/paludis/repositories/e/eapi.sr	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapi.sr	2007-12-31 21:47:26 UTC (rev 4121)
@@ -148,6 +148,15 @@
 END
 }
 
+make_class_EAPIPipeCommands()
+{
+    visible
+    allow_named_args cc
+
+    key rewrite_virtuals bool
+    key no_slot_or_repo bool
+}
+
 make_class_SupportedEAPI()
 {
     visible
@@ -166,6 +175,7 @@
     key ebuild_environment_variables  "tr1::shared_ptr<const EAPIEbuildEnvironmentVariables>"
     key uri_labels                    "tr1::shared_ptr<const EAPILabels>"
     key dependency_labels             "tr1::shared_ptr<const EAPILabels>"
+    key pipe_commands                 "tr1::shared_ptr<const EAPIPipeCommands>"
 
     doxygen_comment << "END"
         /**

Modified: trunk/paludis/repositories/e/eapis/0.conf
===================================================================
--- trunk/paludis/repositories/e/eapis/0.conf	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapis/0.conf	2007-12-31 21:47:26 UTC (rev 4121)
@@ -154,3 +154,6 @@
 restrict_fetch = fetch nofetch
 restrict_primaryuri = primaryuri
 
+pipe_commands_rewrite_virtuals = true
+pipe_commands_no_slot_or_repo = true
+

Modified: trunk/paludis/repositories/e/eapis/1.conf
===================================================================
--- trunk/paludis/repositories/e/eapis/1.conf	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapis/1.conf	2007-12-31 21:47:26 UTC (rev 4121)
@@ -154,4 +154,6 @@
 restrict_fetch = fetch nofetch
 restrict_primaryuri = primaryuri
 
+pipe_commands_rewrite_virtuals = true
+pipe_commands_no_slot_or_repo = true
 

Modified: trunk/paludis/repositories/e/eapis/exheres-0.conf
===================================================================
--- trunk/paludis/repositories/e/eapis/exheres-0.conf	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapis/exheres-0.conf	2007-12-31 21:47:26 UTC (rev 4121)
@@ -174,3 +174,6 @@
 restrict_fetch = fetch
 restrict_primaryuri =
 
+pipe_commands_rewrite_virtuals = false
+pipe_commands_no_slot_or_repo = false
+

Modified: trunk/paludis/repositories/e/eapis/paludis-1.conf
===================================================================
--- trunk/paludis/repositories/e/eapis/paludis-1.conf	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/eapis/paludis-1.conf	2007-12-31 21:47:26 UTC (rev 4121)
@@ -169,3 +169,6 @@
 restrict_fetch = fetch
 restrict_primaryuri =
 
+pipe_commands_rewrite_virtuals = true
+pipe_commands_no_slot_or_repo = false
+

Modified: trunk/paludis/repositories/e/ebuild/ebuild.bash
===================================================================
--- trunk/paludis/repositories/e/ebuild/ebuild.bash	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/ebuild.bash	2007-12-31 21:47:26 UTC (rev 4121)
@@ -94,6 +94,38 @@
     exit 123
 }
 
+paludis_pipe_command()
+{
+    [[ -n "${PALUDIS_SKIP_PIPE_COMMAND_CHECK}" ]] && return
+
+    [[ -z "${PALUDIS_PIPE_COMMAND_WRITE_FD}" ]] && die "PALUDIS_PIPE_COMMAND_WRITE_FD unset"
+    [[ -z "${PALUDIS_PIPE_COMMAND_READ_FD}" ]] && die "PALUDIS_PIPE_COMMAND_READ_FD unset"
+
+    local r r1 rest
+    r="$(echo "$@" | {
+        if ! locked_pipe_command "${PALUDIS_PIPE_COMMAND_WRITE_FD}" "${PALUDIS_PIPE_COMMAND_READ_FD}" ; then
+            # die might not be available yet
+            die "locked_pipe_command failed"
+
+            echo "!!! locked_pipe_command failed, and no die available yet" 1>&2
+            kill -s SIGUSR1 "${EBUILD_KILL_PID}"
+            exit 249
+        fi
+    })"
+
+    r1="${r:0:1}"
+    rest="${r:1}"
+    if [[ "${r1}" != "O" ]] ; then
+        die "paludis_pipe_command returned error '${r1}' with text '${rest}'"
+
+        echo "!!! paludis_pipe_command returned error '${r1}' with text '${rest}', and no die available yet" 1>&2
+        kill -s SIGUSR1 "${EBUILD_KILL_PID}"
+        exit 249
+    fi
+
+    echo "$rest"
+}
+
 ebuild_load_module die_functions
 ebuild_load_module echo_functions
 ebuild_load_module kernel_functions
@@ -107,6 +139,11 @@
 ebuild_load_module exlib_functions
 ebuild_load_module source_functions
 
+if [[ -z "${PALUDIS_SKIP_PIPE_COMMAND_CHECK}" ]] ; then
+    pcr=$(paludis_pipe_command PING DUNNOYET $$ )
+    [[ "$pcr" == "PONG $$" ]] || die "paludis_pipe_command isn't working (got '$pcr')"
+fi
+
 export PALUDIS_HOME="$(canonicalise ${PALUDIS_HOME:-${HOME}} )"
 
 ebuild_source_profile()
@@ -203,7 +240,7 @@
         ebuild_safe_source "${1}" PATH PALUDIS_SOURCE_MERGED_VARIABLES || exit 1
 
         unset -f diefunc perform_hook inherit builtin_loadenv builtin_saveenv
-        unset -f ebuild_safe_source portageq best_version has_version
+        unset -f ebuild_safe_source portageq best_version has_version paludis_pipe_command
 
         unset -v ROOTPATH T HOME TMPDIR PALUDIS_TMPDIR PALUDIS_EBUILD_LOG_LEVEL
         unset -v PORTDIR FILESDIR ECLASSDIR DISTDIR PALUDIS_EBUILD_DIR

Modified: trunk/paludis/repositories/e/ebuild/echo_functions.bash.in
===================================================================
--- trunk/paludis/repositories/e/ebuild/echo_functions.bash.in	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/echo_functions.bash.in	2007-12-31 21:47:26 UTC (rev 4121)
@@ -189,46 +189,9 @@
     fi
 }
 
-ebuild_notice_level()
-{
-    case "$1" in
-        debug)
-            echo "1";
-            ;;
-
-        qa)
-            echo "2";
-            ;;
-
-        warning)
-            echo "3";
-            ;;
-
-        silent)
-            echo "4";
-            ;;
-
-        *)
-            echo "[WARNING.EBUILD] Bad value '$1' for qa level" 1>&2
-            echo "2";
-            ;;
-    esac
-}
-
 ebuild_notice()
 {
-    local level="$1"
-    shift
-
-    local level_num=$(ebuild_notice_level "${level}" )
-    local min_level_num=$(ebuild_notice_level "${PALUDIS_EBUILD_LOG_LEVEL}" )
-
-    if [[ "${level_num}" -ge "${min_level_num}" ]] ; then
-        local upper_level=$(echo ${level} | ${ebuild_real_tr:-tr} '[:lower:]' '[:upper:]' )
-        echo -n "${EBUILD_PROGRAM_NAME:-ebuild.bash}@$(${ebuild_real_date:-date} +%s ): " 1>&2
-        echo "[${upper_level}.EBUILD] $* (from ${EBUILD:-?})" 1>&2
-    fi
-    true
+    paludis_pipe_command LOG "$EAPI" "$@" >/dev/null
 }
 
 ebuild_section()

Modified: trunk/paludis/repositories/e/ebuild/exheres-0/echo_functions.bash.in
===================================================================
--- trunk/paludis/repositories/e/ebuild/exheres-0/echo_functions.bash.in	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/exheres-0/echo_functions.bash.in	2007-12-31 21:47:26 UTC (rev 4121)
@@ -199,46 +199,9 @@
     fi
 }
 
-ebuild_notice_level()
-{
-    case "$1" in
-        debug)
-            echo "1";
-            ;;
-
-        qa)
-            echo "2";
-            ;;
-
-        warning)
-            echo "3";
-            ;;
-
-        silent)
-            echo "4";
-            ;;
-
-        *)
-            echo "[WARNING.EBUILD] Bad value '$1' for qa level" 1>&2
-            echo "2";
-            ;;
-    esac
-}
-
 ebuild_notice()
 {
-    local level="$1"
-    shift
-
-    local level_num=$(ebuild_notice_level "${level}" )
-    local min_level_num=$(ebuild_notice_level "${PALUDIS_EBUILD_LOG_LEVEL}" )
-
-    if [[ "${level_num}" -ge "${min_level_num}" ]] ; then
-        local upper_level=$(echo ${level} | ${ebuild_real_tr:-tr} '[:lower:]' '[:upper:]' )
-        echo -n "${EBUILD_PROGRAM_NAME:-ebuild.bash}@$(${ebuild_real_date:-date} +%s ): " 1>&2
-        echo "[${upper_level}.EBUILD] $* (from ${EBUILD:-?})" 1>&2
-    fi
-    true
+    paludis_pipe_command LOG "$EAPI" "$@" >/dev/null
 }
 
 ebuild_section()

Modified: trunk/paludis/repositories/e/ebuild/exheres-0/portage_stubs.bash
===================================================================
--- trunk/paludis/repositories/e/ebuild/exheres-0/portage_stubs.bash	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/exheres-0/portage_stubs.bash	2007-12-31 21:47:26 UTC (rev 4121)
@@ -22,7 +22,9 @@
 
 has_version()
 {
-    ${PALUDIS_COMMAND} --has-version "$@"
+    [[ "${#@}" -ne 1 ]] && die "$0 should take exactly one arg"
+    local r=$(paludis_pipe_command HAS_VERSION "$EAPI" "$1" )
+    return ${r%%;*}
 }
 
 portageq()
@@ -32,7 +34,10 @@
 
 best_version()
 {
-    ${PALUDIS_COMMAND} --best-version "$@"
+    [[ "${#@}" -ne 1 ]] && die "$0 should take exactly one arg"
+    local r=$(paludis_pipe_command BEST_VERSION "$EAPI" "$1" )
+    echo ${r#*;}
+    return ${r%%;*}
 }
 
 vdb_path()

Modified: trunk/paludis/repositories/e/ebuild/portage_stubs.bash
===================================================================
--- trunk/paludis/repositories/e/ebuild/portage_stubs.bash	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/portage_stubs.bash	2007-12-31 21:47:26 UTC (rev 4121)
@@ -20,11 +20,6 @@
 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 # Place, Suite 330, Boston, MA  02111-1307  USA
 
-has_version()
-{
-    ${PALUDIS_COMMAND} --has-version "$@"
-}
-
 portageq()
 {
     # \todo Make this suck less...
@@ -52,7 +47,10 @@
             die "portageq match emulation only works on current ROOT"
         else
             shift ; shift
-            ${PALUDIS_COMMAND} --match "$@"
+            [[ "${#@}" -ne 1 ]] && die "match should take exactly one arg"
+            local r=$(paludis_pipe_command MATCH "$EAPI" "$1" ) m=""
+            echo "${r#*;}"
+            return ${r%%;*}
         fi
     else
         eerror "Error emulating 'portageq $@':"
@@ -62,14 +60,25 @@
 
 best_version()
 {
-    ${PALUDIS_COMMAND} --best-version "$@"
+    [[ "${#@}" -ne 1 ]] && die "$0 should take exactly one arg"
+    local r=$(paludis_pipe_command BEST_VERSION "$EAPI" "$1" )
+    echo ${r#*;}
+    return ${r%%;*}
 }
 
+has_version()
+{
+    [[ "${#@}" -ne 1 ]] && die "$0 should take exactly one arg"
+    local r=$(paludis_pipe_command HAS_VERSION "$EAPI" "$1" )
+    return ${r%%;*}
+}
+
 vdb_path()
 {
-    if ! ${PALUDIS_COMMAND} --configuration-variable installed location ; then
-        die "Could not find vdb_path"
-    fi
+    [[ "${#@}" -ne 0 ]] && die "vdb_path should take exactly zero args"
+    local r=$(paludis_pipe_command VDB_PATH "$EAPI" "$1" )
+    echo ${r#*;}
+    return ${r%%;*}
 }
 
 check_KV()

Modified: trunk/paludis/repositories/e/ebuild/run_test.bash
===================================================================
--- trunk/paludis/repositories/e/ebuild/run_test.bash	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/run_test.bash	2007-12-31 21:47:26 UTC (rev 4121)
@@ -32,10 +32,20 @@
     fi
 }
 
+export PALUDIS_PIPE_COMMAND_WRITE_FD=
+export PALUDIS_PIPE_COMMAND_READ_FD=
+export PALUDIS_SKIP_PIPE_COMMAND_CHECK=yes
+
 echo "Test program ${1}:"
 source "$(dirname ${1} )/ebuild.bash" || exit 200
 source "${1}" || exit 200
 
+paludis_pipe_command()
+{
+    echo "No paludis_pipe_command here"
+    exit 127
+}
+
 for testname in $(set | grep '_TEST *() *$' ) ; do
     [[ ${testname/()} != ${testname} ]] && continue
     echo -n "* ${testname%_TEST}: "

Modified: trunk/paludis/repositories/e/ebuild/utils/Makefile.am
===================================================================
--- trunk/paludis/repositories/e/ebuild/utils/Makefile.am	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild/utils/Makefile.am	2007-12-31 21:47:26 UTC (rev 4121)
@@ -58,9 +58,12 @@
 	patch
 
 libexecbindir = $(libexecdir)/paludis/utils
-libexecbin_PROGRAMS = print_exports
+libexecbin_PROGRAMS = \
+	print_exports \
+	locked_pipe_command
 
 print_exports_SOURCES = print_exports.cc
+locked_pipe_command_SOURCES = locked_pipe_command.cc
 
 AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
 

Added: trunk/paludis/repositories/e/ebuild/utils/locked_pipe_command.cc
===================================================================
--- trunk/paludis/repositories/e/ebuild/utils/locked_pipe_command.cc	                        (rev 0)
+++ trunk/paludis/repositories/e/ebuild/utils/locked_pipe_command.cc	2007-12-31 21:47:26 UTC (rev 4121)
@@ -0,0 +1,107 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh
+ *
+ * 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 <cstdlib>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <iostream>
+
+int
+main(int argc, char *argv[])
+{
+    if (argc != 3)
+    {
+        std::cerr << "Usage: " << argv[0] << " write_fd read_fd" << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    int write_fd(std::atoi(argv[1])), read_fd(std::atoi(argv[2]));
+    if (0 != ::lockf(write_fd, F_LOCK, 0))
+    {
+        std::cerr << "Error: " << argv[0] << ": lockf failed with " << ::strerror(errno) << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    /* copy stdin to the pipe read buffer */
+    char buf[1024];
+    int c, w;
+    while (((c = read(0, buf, 1024))) > 0)
+    {
+        char * buf_p(buf);
+        while (((w = write(write_fd, buf_p, c))) > 0)
+        {
+            buf_p += w;
+            c -= w;
+            if (c == 0)
+                break;
+        }
+        if (w == -1)
+        {
+            std::cerr << "Error: " << argv[0] << ": write failed with " << ::strerror(errno) << std::endl;
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (c == -1)
+    {
+        std::cerr << "Error: " << argv[0] << ": read failed with " << ::strerror(errno) << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    /* append null to the pipe read buffer */
+    buf[0] = '\0';
+    while (((w = write(write_fd, buf, 1))) == 0)
+        sleep(0);
+    if (w == -1)
+    {
+        std::cerr << "Error: " << argv[0] << ": write failed with " << ::strerror(errno) << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    /* copy write buffer to stdout until we get a null, and discard that null */
+    while (((c = read(read_fd, buf, 1))) > 0)
+    {
+        if (buf[0] == '\0')
+            break;
+
+        while (((w = write(1, buf, c))) == 0)
+            sleep(0);
+        if (w == -1)
+        {
+            std::cerr << "Error: " << argv[0] << ": write failed with " << ::strerror(errno) << std::endl;
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (c == -1)
+    {
+        std::cerr << "Error: " << argv[0] << ": read failed with " << ::strerror(errno) << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    if (0 != ::lockf(write_fd, F_ULOCK, 0))
+    {
+        std::cerr << "Error: " << argv[0] << ": lockf unlock failed with " << ::strerror(errno) << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
+

Modified: trunk/paludis/repositories/e/ebuild.cc
===================================================================
--- trunk/paludis/repositories/e/ebuild.cc	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild.cc	2007-12-31 21:47:26 UTC (rev 4121)
@@ -22,6 +22,7 @@
 #include <paludis/repositories/e/e_repository.hh>
 #include <paludis/repositories/e/eapi.hh>
 #include <paludis/repositories/e/dep_parser.hh>
+#include <paludis/repositories/e/package_dep_spec.hh>
 
 #include <paludis/util/system.hh>
 #include <paludis/util/strip.hh>
@@ -33,6 +34,13 @@
 #include <paludis/util/tokeniser.hh>
 #include <paludis/util/wrapped_forward_iterator.hh>
 #include <paludis/util/wrapped_output_iterator.hh>
+#include <paludis/util/tr1_functional.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/visitor_cast.hh>
+#include <paludis/util/visitor-impl.hh>
+#include <paludis/util/set.hh>
 
 #include <paludis/about.hh>
 #include <paludis/environment.hh>
@@ -46,6 +54,7 @@
 #include <unistd.h>
 
 #include <list>
+#include <vector>
 
 #include "config.h"
 
@@ -93,6 +102,8 @@
     if (params.userpriv)
         cmd.with_uid_gid(params.environment->reduced_uid(), params.environment->reduced_gid());
 
+    using namespace tr1::placeholders;
+    cmd.with_pipe_command_handler(tr1::bind(tr1::mem_fn(&EbuildCommand::pipe_command_handler), this, _1));
 
     tr1::shared_ptr<const FSEntrySequence> syncers_dirs(params.environment->syncers_dirs());
     tr1::shared_ptr<const FSEntrySequence> bashrc_files(params.environment->bashrc_files());
@@ -217,6 +228,201 @@
     return 0 == run_command(cmd);
 }
 
+namespace
+{
+    std::string name_and_version(const PackageID & id)
+    {
+        return stringify(id.name()) + "-" + stringify(id.version());
+    }
+}
+
+std::string
+EbuildCommand::pipe_command_handler(const std::string & s) const
+{
+    Context context("In ebuild pipe command handler for '" + s + "':");
+
+    try
+    {
+        std::vector<std::string> tokens;
+        tokenise_whitespace(s, std::back_inserter(tokens));
+        if (tokens.empty())
+        {
+            Log::get_instance()->message(ll_warning, lc_context) << "Got empty pipe command";
+            return "Eempty pipe command";
+        }
+
+        if (tokens[0] == "PING")
+        {
+            if (tokens.size() != 3)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got bad PING command";
+                return "Ebad PING command";
+            }
+            else
+                return "OPONG " + tokens[2];
+        }
+        else if (tokens[0] == "LOG")
+        {
+            if (tokens.size() < 4)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got too short LOG pipe command";
+                return "Ebad LOG command";
+            }
+            else
+            {
+                Log::get_instance()->message(destringify<LogLevel>(tokens[2]), lc_context) << join(next(next(next(tokens.begin()))),
+                        tokens.end(), " ");
+                return "O";
+            }
+        }
+        else if (tokens[0] == "BEST_VERSION")
+        {
+            if (tokens.size() != 3)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got bad BEST_VERSION pipe command";
+                return "Ebad BEST_VERSION command";
+            }
+            else
+            {
+                tr1::shared_ptr<const EAPI> eapi(EAPIData::get_instance()->eapi_from_string(tokens[1]));
+                if (! eapi->supported)
+                    return "EBEST_VERSION EAPI " + tokens[1] + " unsupported";
+
+                PackageDepSpec spec(erepository::parse_e_package_dep_spec(tokens[2], *eapi, params.package_id));
+                tr1::shared_ptr<const PackageIDSequence> entries(params.environment->package_database()->query(
+                            query::Matches(spec) & query::InstalledAtRoot(params.environment->root()), qo_order_by_version));
+                if (eapi->supported->pipe_commands->rewrite_virtuals && (! entries->empty()) &&
+                        (*entries->last())->virtual_for_key())
+                {
+                    Log::get_instance()->message(ll_qa, lc_context) << "best-version of '" << spec <<
+                        "' resolves to '" << **entries->last() << "', which is a virtual for '"
+                        << *(*entries->last())->virtual_for_key()->value() << "'. This will break with "
+                        "new style virtuals.";
+                    tr1::shared_ptr<PackageIDSequence> new_entries(new PackageIDSequence);
+                    new_entries->push_back((*entries->last())->virtual_for_key()->value());
+                    entries = new_entries;
+                }
+
+                if (entries->empty())
+                    return "O1;";
+                else
+                {
+                    if (eapi->supported->pipe_commands->no_slot_or_repo)
+                        return "O0;" + name_and_version(**entries->last());
+                    else
+                        return "O0;" + stringify(**entries->last());
+                }
+            }
+        }
+        else if (tokens[0] == "HAS_VERSION")
+        {
+            if (tokens.size() != 3)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got bad HAS_VERSION pipe command";
+                return "Ebad HAS_VERSION command";
+            }
+            else
+            {
+                tr1::shared_ptr<const EAPI> eapi(EAPIData::get_instance()->eapi_from_string(tokens[1]));
+                if (! eapi->supported)
+                    return "EHAS_VERSION EAPI " + tokens[1] + " unsupported";
+
+                PackageDepSpec spec(erepository::parse_e_package_dep_spec(tokens[2], *eapi, params.package_id));
+                tr1::shared_ptr<const PackageIDSequence> entries(params.environment->package_database()->query(
+                            query::Matches(spec) & query::InstalledAtRoot(params.environment->root()), qo_order_by_version));
+                if (entries->empty())
+                    return "O1;";
+                else
+                    return "O0;";
+            }
+        }
+        else if (tokens[0] == "MATCH")
+        {
+            if (tokens.size() != 3)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got bad MATCH pipe command";
+                return "Ebad MATCH command";
+            }
+            else
+            {
+                tr1::shared_ptr<const EAPI> eapi(EAPIData::get_instance()->eapi_from_string(tokens[1]));
+                if (! eapi->supported)
+                    return "EMATCH EAPI " + tokens[1] + " unsupported";
+
+                PackageDepSpec spec(erepository::parse_e_package_dep_spec(tokens[2], *eapi, params.package_id));
+                tr1::shared_ptr<const PackageIDSequence> entries(params.environment->package_database()->query(
+                            query::Matches(spec) & query::InstalledAtRoot(params.environment->root()), qo_order_by_version));
+                if (eapi->supported->pipe_commands->rewrite_virtuals && (! entries->empty()))
+                {
+                    tr1::shared_ptr<PackageIDSequence> new_entries(new PackageIDSequence);
+                    for (PackageIDSequence::ConstIterator i(entries->begin()), i_end(entries->end()) ;
+                            i != i_end ; ++i)
+                    {
+                        if ((*i)->virtual_for_key())
+                        {
+                            Log::get_instance()->message(ll_qa, lc_context) << "match of '" << spec <<
+                                "' resolves to '" << **i << "', which is a virtual for '"
+                                << *(*i)->virtual_for_key()->value() << "'. This will break with "
+                                "new style virtuals.";
+                            new_entries->push_back((*i)->virtual_for_key()->value());
+                        }
+                        else
+                            new_entries->push_back(*i);
+                    }
+                    entries = new_entries;
+                }
+
+                if (entries->empty())
+                    return "O1;";
+                else
+                {
+                    if (eapi->supported->pipe_commands->no_slot_or_repo)
+                        return "O0;" + join(indirect_iterator(entries->begin()), indirect_iterator(entries->end()), "\n", &name_and_version);
+                    else
+                        return "O0;" + join(indirect_iterator(entries->begin()), indirect_iterator(entries->end()), "\n");
+                }
+            }
+        }
+        else if (tokens[0] == "VDB_PATH")
+        {
+            if (tokens.size() != 2)
+            {
+                Log::get_instance()->message(ll_warning, lc_context) << "Got bad VDB_PATH pipe command";
+                return "Ebad VDB_PATH command";
+            }
+            else
+            {
+                if (! params.environment->package_database()->has_repository_named(RepositoryName("installed")))
+                    return "Eno installed repository available";
+                tr1::shared_ptr<const Repository> repo(params.environment->package_database()->fetch_repository(RepositoryName("installed")));
+                Repository::MetadataConstIterator key(repo->find_metadata("location"));
+                if (repo->end_metadata() == key)
+                    return "Einstalled repository has no location key";
+                if (! visitor_cast<const MetadataFSEntryKey>(**key))
+                    return "Einstalled repository location key is not a MetadataFSEntryKey";
+                return "O0;" + stringify(visitor_cast<const MetadataFSEntryKey>(**key)->value());
+            }
+        }
+        else
+        {
+            Log::get_instance()->message(ll_warning, lc_context) << "Got unknown ebuild pipe command '" + s + "'";
+            return "Eunknown pipe command";
+        }
+    }
+    catch (const Exception & e)
+    {
+        return "Eexception '" + e.message() + "' (" + e.what() + ")";
+    }
+    catch (const std::exception & e)
+    {
+        return "Eexception " + stringify(e.what());
+    }
+    catch (...)
+    {
+        return "Eexception ???";
+    }
+}
+
 EbuildMetadataCommand::EbuildMetadataCommand(const EbuildCommandParams & p) :
     EbuildCommand(p)
 {

Modified: trunk/paludis/repositories/e/ebuild.hh
===================================================================
--- trunk/paludis/repositories/e/ebuild.hh	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/repositories/e/ebuild.hh	2007-12-31 21:47:26 UTC (rev 4121)
@@ -112,6 +112,11 @@
                  */
                 virtual Command extend_command(const Command &) = 0;
 
+                /**
+                 * Pipe command handler.
+                 */
+                virtual std::string pipe_command_handler(const std::string &) const;
+
             public:
                 /**
                  * Destructor.

Modified: trunk/paludis/util/system.cc
===================================================================
--- trunk/paludis/util/system.cc	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/util/system.cc	2007-12-31 21:47:26 UTC (rev 4121)
@@ -570,7 +570,7 @@
 
             while (! pipe_command_buffer.empty())
             {
-                std::string::size_type n_p(pipe_command_buffer.find('\n'));
+                std::string::size_type n_p(pipe_command_buffer.find('\0'));
                 if (std::string::npos == n_p)
                     break;
 
@@ -588,7 +588,6 @@
                     Log::get_instance()->message(ll_warning, lc_context) << "Pipe command op '" << op <<
                         "' was requested but no handler defined. This is probably a bug...";
 
-                response = strip_trailing(response, "\n") + "\n";
                 ssize_t n(0);
                 while (! response.empty())
                 {
@@ -598,6 +597,11 @@
                     else
                         response.erase(0, n);
                 }
+
+                char c(0);
+                n = write(pipe_command_response->write_fd(), &c, 1);
+                if (1 != n)
+                    throw InternalError(PALUDIS_HERE, "write failed: " + stringify(strerror(errno)));
             }
 
             while (! internal_command_buffer.empty())

Modified: trunk/paludis/util/system_TEST_setup.sh
===================================================================
--- trunk/paludis/util/system_TEST_setup.sh	2007-12-31 21:47:15 UTC (rev 4120)
+++ trunk/paludis/util/system_TEST_setup.sh	2007-12-31 21:47:26 UTC (rev 4121)
@@ -7,11 +7,21 @@
 cat <<'END' > pipe_test.bash
 #!/bin/bash
 
-echo $1 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
-read -u$PALUDIS_PIPE_COMMAND_READ_FD response1
+echo "$1" | tr "\n" "\0" 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+response1=
+while true ; do
+    c=$(head -c1 <&$PALUDIS_PIPE_COMMAND_READ_FD )
+    [[ "$c" == $'\0' ]] && break
+    response1="${response1}${c}"
+done
 
-echo $2 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
-read -u$PALUDIS_PIPE_COMMAND_READ_FD response2
+echo "$2" | tr "\n" "\0" 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+response2=
+while true ; do
+    c=$(head -c1 <&$PALUDIS_PIPE_COMMAND_READ_FD )
+    [[ "$c" == $'\0' ]] && break
+    response2="${response2}${c}"
+done
 
 exit $response1$response2
 END
@@ -19,14 +29,29 @@
 cat <<'END' > captured_pipe_test.bash
 #!/bin/bash
 
-echo $1 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
-read -u$PALUDIS_PIPE_COMMAND_READ_FD response1
+echo "$1" | tr "\n" "\0" 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+response1=
+while true ; do
+    c=$(head -c1 <&$PALUDIS_PIPE_COMMAND_READ_FD )
+    [[ "$c" == $'\0' ]] && break
+    response1="${response1}${c}"
+done
 
-echo $2 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
-read -u$PALUDIS_PIPE_COMMAND_READ_FD response2
+echo "$2" | tr "\n" "\0" 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+response2=
+while true ; do
+    c=$(head -c1 <&$PALUDIS_PIPE_COMMAND_READ_FD )
+    [[ "$c" == $'\0' ]] && break
+    response2="${response2}${c}"
+done
 
-echo $3 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
-read -u$PALUDIS_PIPE_COMMAND_READ_FD response3
+echo "$3" | tr "\n" "\0" 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+response3=
+while true ; do
+    c=$(head -c1 <&$PALUDIS_PIPE_COMMAND_READ_FD )
+    [[ "$c" == $'\0' ]] && break
+    response3="${response3}${c}"
+done
 
 echo $response2
 



More information about the paludis-commits mailing list