aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Fernando J. Pereda <ferdy@ferdyx.org> 2006-06-17 18:26:32 +0000
committerAvatar Fernando J. Pereda <ferdy@ferdyx.org> 2006-06-17 18:26:32 +0000
commit53416b0c1527604c730be5803701d4110f737d4f (patch)
tree685a4ee695d655868ff039a4f6c3a96e6772ac93
parentd9c88232ce9385af1f2b98df5192640a2ab60bf9 (diff)
downloadpaludis-53416b0c1527604c730be5803701d4110f737d4f.tar.gz
paludis-53416b0c1527604c730be5803701d4110f737d4f.tar.xz
Introduce run_command_in_directory and use it in GitSyncer::sync().
-rw-r--r--paludis/syncer.cc13
-rw-r--r--paludis/util/system.cc68
-rw-r--r--paludis/util/system.hh25
-rw-r--r--paludis/util/system_TEST.cc22
-rwxr-xr-xpaludis/util/system_TEST_cleanup.sh9
-rwxr-xr-xpaludis/util/system_TEST_setup.sh5
6 files changed, 118 insertions, 24 deletions
diff --git a/paludis/syncer.cc b/paludis/syncer.cc
index 1769cad..3f52dfe 100644
--- a/paludis/syncer.cc
+++ b/paludis/syncer.cc
@@ -203,18 +203,19 @@ GitSyncer::sync(const SyncOptions &) const
Context context("When performing sync via git from '" + _remote + "' to '"
+ _local + "':");
- std::string cmd;
- FSEntry git_dir(_local+"/.git");
+ FSEntry git_dir(_local + "/.git");
+ FSEntry repo_dir(_local);
+ int status;
- if (FSEntry(_local).is_directory() && ! git_dir.is_directory())
+ if (repo_dir.is_directory() && ! git_dir.is_directory())
throw SyncGitDirectoryExists(_local);
if (git_dir.is_directory())
- cmd = "cd '" + _local + "' && git pull";
+ status = run_command_in_directory("git pull", repo_dir);
else
- cmd = "git clone '"+ _remote + "' '" + _local + "'";
+ status = run_command("git clone '"+ _remote + "' '" + _local + "'");
- if (0 != run_command(make_env_command(cmd)("LC_ALL", "C")))
+ if (0 != status)
throw SyncFailedError(_local, _remote);
}
diff --git a/paludis/util/system.cc b/paludis/util/system.cc
index 7163cac..2ca6d7b 100644
--- a/paludis/util/system.cc
+++ b/paludis/util/system.cc
@@ -20,6 +20,8 @@
#include <cstdlib>
#include <paludis/util/system.hh>
#include <paludis/util/log.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -35,11 +37,53 @@
using namespace paludis;
+namespace
+{
+ /**
+ * Runs a command in a directory if needed, wait for it to terminate
+ * and return its exit status.
+ *
+ * \ingroup grpsystem
+ */
+ int
+ real_run_command(const std::string & cmd, const FSEntry * const fsentry)
+ {
+ pid_t child(fork());
+ if (0 == child)
+ {
+ if (fsentry)
+ if (-1 == chdir(stringify(*fsentry).c_str()))
+ throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
+
+ Log::get_instance()->message(ll_debug, "execl /bin/sh -c " + cmd);
+ execl("/bin/sh", "sh", "-c", cmd.c_str(), static_cast<char *>(0));
+ throw RunCommandError("execl /bin/sh -c '" + cmd + "' failed:"
+ + stringify(strerror(errno)));
+ }
+ else if (-1 == child)
+ throw RunCommandError("fork failed: " + stringify(strerror(errno)));
+ else
+ {
+ int status(-1);
+ if (-1 == wait(&status))
+ throw RunCommandError("wait failed: " + stringify(strerror(errno)));
+ return status;
+ }
+
+ throw InternalError(PALUDIS_HERE, "should never be reached");
+ }
+}
+
GetenvError::GetenvError(const std::string & key) throw () :
Exception("Environment variable '" + key + "' not set")
{
}
+RunCommandError::RunCommandError(const std::string & message) throw () :
+ Exception(message)
+{
+}
+
std::string
paludis::getenv_with_default(const std::string & key, const std::string & def)
{
@@ -82,25 +126,13 @@ paludis::kernel_version()
int
paludis::run_command(const std::string & cmd)
{
- pid_t child(fork());
- if (0 == child)
- {
- Log::get_instance()->message(ll_debug, "execl /bin/sh -c " + cmd);
- execl("/bin/sh", "sh", "-c", cmd.c_str(), static_cast<char *>(0));
- throw InternalError(PALUDIS_HERE, "execl /bin/sh -c '" + cmd + "' failed:"
- + stringify(strerror(errno)));
- }
- else if (-1 == child)
- throw InternalError(PALUDIS_HERE, "fork failed: " + stringify(strerror(errno)));
- else
- {
- int status(-1);
- if (-1 == wait(&status))
- throw InternalError(PALUDIS_HERE, "wait failed: " + stringify(strerror(errno)));
- return status;
- }
+ return real_run_command(cmd, 0);
+}
- throw InternalError(PALUDIS_HERE, "should never be reached");
+int
+paludis::run_command_in_directory(const std::string & cmd, const FSEntry & fsentry)
+{
+ return real_run_command(cmd, &fsentry);
}
MakeEnvCommand::MakeEnvCommand(const std::string & c,
diff --git a/paludis/util/system.hh b/paludis/util/system.hh
index cee7dc9..99b6881 100644
--- a/paludis/util/system.hh
+++ b/paludis/util/system.hh
@@ -31,6 +31,8 @@
namespace paludis
{
+ class FSEntry;
+
/**
* Thrown if getenv_or_error fails.
*
@@ -47,6 +49,21 @@ namespace paludis
};
/**
+ * Thrown if fork, wait or chdir fail when running a command.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpsystem
+ */
+ class RunCommandError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ RunCommandError(const std::string & message) throw ();
+ };
+
+ /**
* Fetch the value of environment variable key, or def if the variable is
* not defined.
*
@@ -79,6 +96,14 @@ namespace paludis
int run_command(const std::string & cmd);
/**
+ * Run a command in a directory, wait for it to terminate and return
+ * its exit status.
+ *
+ * \ingroup grpsystem
+ */
+ int run_command_in_directory(const std::string & cmd, const FSEntry & fsentry);
+
+ /**
* Make a command that's run in a particular environment.
*/
class MakeEnvCommand
diff --git a/paludis/util/system_TEST.cc b/paludis/util/system_TEST.cc
index 5c2b8a3..4e8100a 100644
--- a/paludis/util/system_TEST.cc
+++ b/paludis/util/system_TEST.cc
@@ -19,6 +19,7 @@
#include <paludis/util/system.hh>
#include <paludis/util/pstream.hh>
+#include <paludis/util/fs_entry.hh>
#include <test/test_framework.hh>
#include <test/test_runner.hh>
@@ -108,6 +109,27 @@ namespace test_cases
} test_run_command;
/**
+ * \test Test run_command_in_directory.
+ *
+ * \ingroup grptestcases
+ */
+ struct RunCommandInDirectoryTest : TestCase
+ {
+ RunCommandInDirectoryTest() : TestCase("run_command_in_directory") { }
+
+ void run()
+ {
+ FSEntry dir("system_TEST_dir");
+ TEST_CHECK(dir.is_directory());
+
+ run_command_in_directory("touch in_directory", dir);
+ TEST_CHECK(FSEntry(dir / "in_directory").exists());
+ run_command_in_directory("rm in_directory", dir);
+ TEST_CHECK(! FSEntry(dir / "in_directory").exists());
+ }
+ } test_run_command_in_directory;
+
+ /**
* \test Test make_env_command.
*
* \ingroup grptestcases
diff --git a/paludis/util/system_TEST_cleanup.sh b/paludis/util/system_TEST_cleanup.sh
new file mode 100755
index 0000000..1dca3c3
--- /dev/null
+++ b/paludis/util/system_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d system_TEST_dir ] ; then
+ rm -fr system_TEST_dir
+else
+ true
+fi
+
diff --git a/paludis/util/system_TEST_setup.sh b/paludis/util/system_TEST_setup.sh
new file mode 100755
index 0000000..d1c9e76
--- /dev/null
+++ b/paludis/util/system_TEST_setup.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir system_TEST_dir || exit 2
+cd system_TEST_dir || exit 3