glom r1681 - in trunk: . glom/libglom
- From: arminb svn gnome org
- To: svn-commits-list gnome org
- Subject: glom r1681 - in trunk: . glom/libglom
- Date: Tue, 9 Sep 2008 10:25:37 +0000 (UTC)
Author: arminb
Date: Tue Sep 9 10:25:37 2008
New Revision: 1681
URL: http://svn.gnome.org/viewvc/glom?rev=1681&view=rev
Log:
2008-09-09 Armin Burgmeier <armin openismus com>
* glom/libglom/spawn_with_feedback.cc: Refactored the code, removed
all blocking calls and use the CreateProcess() API on Windows to hide
the console window of child processes.
* glom/libglom/connectionpool.cc: Always call the spawn API with
double quotes for the path to the executable, because CreateProcess()
does not support single quotes.
Modified:
trunk/ChangeLog
trunk/glom/libglom/connectionpool.cc
trunk/glom/libglom/spawn_with_feedback.cc
Modified: trunk/glom/libglom/connectionpool.cc
==============================================================================
--- trunk/glom/libglom/connectionpool.cc (original)
+++ trunk/glom/libglom/connectionpool.cc Tue Sep 9 10:25:37 2008
@@ -865,7 +865,9 @@
// -c config_file= specifies the configuration file
// -k specifies a directory to use for the socket. This must be writable by us.
// POSTGRES_POSTMASTER_PATH is defined in config.h, based on the configure.
- const std::string command_postgres_start = Glib::shell_quote(get_path_to_postgres_executable("postmaster")) + " -D \"" + dbdir_data + "\" "
+ // Make sure to use double quotes for the executable path, because the
+ // CreateProcess() API used on Windows does not support single quotes.
+ const std::string command_postgres_start = "\"" + get_path_to_postgres_executable("postmaster") + "\" -D \"" + dbdir_data + "\" "
+ " -p " + port_as_text
+ " -i " //Equivalent to -h "*", which in turn is equivalent to listen_addresses in postgresql.conf. Listen to all IP addresses, so any client can connect (with a username+password)
+ " -c hba_file=\"" + dbdir + "/config/pg_hba.conf\""
@@ -873,7 +875,9 @@
+ " -k \"" + dbdir + "\""
+ " --external_pid_file=\"" + dbdir + "/pid\"";
- const std::string command_check_postgres_has_started = Glib::shell_quote(get_path_to_postgres_executable("pg_ctl")) + " status -D \"" + dbdir_data + "\"";
+ // Make sure to use double quotes for the executable path, because the
+ // CreateProcess() API used on Windows does not support single quotes.
+ const std::string command_check_postgres_has_started = "\"" + get_path_to_postgres_executable("pg_ctl") + "\" status -D \"" + dbdir_data + "\"";
//For postgres 8.1, this is "postmaster is running".
//For postgres 8.2, this is "server is running".
@@ -943,7 +947,9 @@
// POSTGRES_POSTMASTER_PATH is defined in config.h, based on the configure.
// We use "-m fast" instead of the default "-m smart" because that waits for clients to disconnect (and sometimes never succeeds).
// TODO: Warn about connected clients on other computers? Warn those other users?
- const std::string command_postgres_stop = Glib::shell_quote(get_path_to_postgres_executable("pg_ctl")) + " -D \"" + dbdir_data + "\" stop -m fast";
+ // Make sure to use double quotes for the executable path, because the
+ // CreateProcess() API used on Windows does not support single quotes.
+ const std::string command_postgres_stop = "\"" + get_path_to_postgres_executable("pg_ctl") + "\" -D \"" + dbdir_data + "\" stop -m fast";
const bool result = Glom::Spawn::execute_command_line_and_wait(command_postgres_stop, _("Stopping Database Server"), parent_window);
if(!result)
{
@@ -1052,7 +1058,9 @@
const bool pwfile_creation_succeeded = create_text_file(temp_pwfile_uri, get_password());
g_assert(pwfile_creation_succeeded);
- const std::string command_initdb = Glib::shell_quote(get_path_to_postgres_executable("initdb")) + " -D \"" + dbdir_data + "\"" +
+ // Make sure to use double quotes for the executable path, because the
+ // CreateProcess() API used on Windows does not support single quotes.
+ const std::string command_initdb = "\"" + get_path_to_postgres_executable("initdb") + "\" -D \"" + dbdir_data + "\"" +
" -U " + username + " --pwfile=\"" + temp_pwfile + "\"";
//Note that --pwfile takes the password from the first line of a file. It's an alternative to supplying it when prompted on stdin.
Modified: trunk/glom/libglom/spawn_with_feedback.cc
==============================================================================
--- trunk/glom/libglom/spawn_with_feedback.cc (original)
+++ trunk/glom/libglom/spawn_with_feedback.cc Tue Sep 9 10:25:37 2008
@@ -25,6 +25,13 @@
#include <glibmm/i18n.h>
#include <iostream>
+#ifdef G_OS_WIN32
+#define SAVE_DATADIR DATADIR
+#undef DATADIR
+#include <windows.h>
+#define DATADIR SAVE_DATADIR
+#endif
+
namespace Glom
{
@@ -41,95 +48,299 @@
bool* m_result;
};
+// This is a simple process launching API wrapping g_spawn_async on linux and
+// CreateProcess() on Windows. We need to use CreateProcess on Windows to be
+// able to suppress the console window.
+namespace Impl
+{
+
+static const unsigned int REDIRECT_STDOUT = 1;
+static const unsigned int REDIRECT_STDERR = 2;
-static void execute_command_line_on_thread_create(CommandLineThreadData* data)
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+class SpawnError: public std::runtime_error
{
- std::cout << " debug: thread start" << std::endl;
+public:
+ SpawnError(const std::string& error_message): std::runtime_error(error_message) {}
+};
+#endif
- int return_status = 0;
+class SpawnInfo: public sigc::trackable
+{
+private:
+ // Private platform-dependant helper functions
+#ifdef G_OS_WIN32
+ static std::string win32_error_message()
+ {
+ gchar* message = g_win32_error_message(GetLastError());
+ std::string msg = message;
+ g_free(message);
+ return msg;
+ }
+ // We redirect stdout and stderr output into a file, and read that file later.
+ // I would prefer to read child stderr directly, without using a temporary
+ // file, but that is probably not so easy since Glib::IOChannel does not
+ // support Windows file HANDLEs, but we need to pass a HANDLE to
+ // CreateProcess() for redirection.
+ static HANDLE create_redirect_file(std::string& filename)
+ {
+ static unsigned int redirect_seq = 0;
+ const gchar* appdata = getenv("APPDATA");
+ filename = Glib::ustring::compose("%1\\glom_spawn_redirect_%2.txt", std::string(appdata), ++ redirect_seq);
+
+ // Allow the redirect file to be inherited by the child process, so
+ // it can write to it.
+ SECURITY_ATTRIBUTES security_attr;
+ security_attr.nLength = sizeof(security_attr);
+ security_attr.lpSecurityDescriptor = NULL;
+ security_attr.bInheritHandle = TRUE;
+ HANDLE result = CreateFile(filename.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, &security_attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- Glib::spawn_command_line_sync(data->m_command, NULL, NULL, &return_status);
+ if(!result) throw SpawnError(win32_error_message());
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+ return result;
}
- catch(const Glib::SpawnError& ex)
+#else // G_OS_WIN32
+ bool on_io(Glib::IOCondition cond, Glib::RefPtr<Glib::IOChannel> channel, std::string& result)
{
- std::cerr << "Glom:: execute_command_line_on_thread_create() Exception while calling Glib::spawn_command_line_sync(): " << ex.what() << std::endl;
+ if(cond != Glib::IO_IN)
+ {
+ // Perhaps the pipe was closed or something. Ignore & Disconnect. If the
+ // this was because the child exited, then the on_child_watch() callback
+ // will be called anyway.
+ return false;
+ }
+ else
+ {
+ char buffer[1024 + 1];
+ gsize bytes_read;
+
+ Glib::IOStatus status;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ status = channel->read(buffer, 1024, bytes_read);
+ }
+ catch(const Glib::Exception& ex)
+ {
+ std::cerr << "Glom::Spawn::Impl::SpawnInfo::on_io: Error while reading from pipe: " << ex.what() << std::endl;
+ return false;
+ }
+#else
+ std::auto_ptr<Glib::Error> error;
+ status = channel->read(buffer, 1024, bytes_read, error);
+ if(error.get())
+ {
+ std::cerr << "Glom::Spawn::Impl::SpawnInfo::on_io: Error while reading from pipe: " << error->what() << std::endl;
+ return false;
+ }
+#endif
+
+ buffer[bytes_read] = '\0';
+ result += buffer;
+
+ return status == Glib::IO_STATUS_NORMAL || status == Glib::IO_STATUS_AGAIN;
+ }
}
+
+ void redirect_to_string(int fd, std::string& string)
+ {
+ Glib::RefPtr<Glib::IOChannel> channel = Glib::IOChannel::create_from_fd(fd);
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ channel->set_flags(Glib::IO_FLAG_NONBLOCK);
#else
- // TODO: I guess we can't find out whether this failed.
- // This might be a glibmm bug.
- Glib::spawn_command_line_sync(data->m_command, NULL, NULL, &return_status);
+ std::auto_ptr<Glib::Error> error;
+ channel->set_flags(Glib::IO_FLAG_NONBLOCK, error);
#endif // !GLIBMM_EXCEPTIONS_ENABLED
-
- std::cout << " debug: in thread: signalling condition" << std::endl;
- // TODO: Use WIFEXITED() and WEXITSTATUS()?
- *(data->m_result) = (return_status == 0);
+ channel->set_encoding("");
+ channel->set_buffered(false);
- data->m_mutex->lock(); //The documentation for g_cond_broadcast() says "It is good practice to lock the same mutex as the waiting threads, while calling this function, though not required."
- data->m_cond->broadcast(); //Allows the caller to continue.
- data->m_mutex->unlock();
+ Glib::signal_io().connect(sigc::bind(sigc::mem_fun(*this, &SpawnInfo::on_io), channel, sigc::ref(string)), channel, Glib::IO_IN);
+ }
+#endif // !G_OS_WIN32
- delete data; //Note that this doesn't delete the data pointed to by data->m_result.
-}
+public:
+ typedef sigc::signal<void> SignalFinished;
-static bool pulse_until_thread_finished(Dialog_ProgressCreating& dialog_progress, const std::string& command, const sigc::slot<void, CommandLineThreadData*>& thread_slot)
-{
- // Spawn the command in a thread, waiting for a condition to be signalled by that thread when it has finished.
- // This allows us to update the UI in this thread while we wait:
- Glib::Cond cond;
- Glib::Mutex cond_mutex;
-
- bool result = false;
-
- CommandLineThreadData* data = new CommandLineThreadData(); //This will be deleted by the slot when it has finished.
- data->m_command = command;
- data->m_cond = &cond;
- data->m_mutex = &cond_mutex;
- data->m_result = &result;
+ SpawnInfo(const Glib::ustring& command_line, int redirect):
+ running(false), return_status(0)
+ {
+#ifdef G_OS_WIN32
+ startup_info.cb = sizeof(startup_info);
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.lpReserved = NULL;
+ startup_info.lpDesktop = NULL;
+ startup_info.lpTitle = NULL;
+ startup_info.cbReserved2 = 0;
+ startup_info.lpReserved2 = NULL;
+ startup_info.hStdInput = INVALID_HANDLE_VALUE;
- // Create a thread, which will start by calling our slot
- // We use sigc::bind to pass extra information to that slot.
- //
- // The slot signals the condition when it has finished.
- // so the caller can repeatedly wait for the signal until the thread has finished.
- try
+ if(redirect & REDIRECT_STDOUT)
+ startup_info.hStdOutput = create_redirect_file(stdout_file);
+ else
+ startup_info.hStdOutput = INVALID_HANDLE_VALUE;
+
+ if(redirect & REDIRECT_STDERR)
+ startup_info.hStdError = create_redirect_file(stderr_file);
+ else
+ startup_info.hStdError = INVALID_HANDLE_VALUE;
+
+ // CreateProcess needs a non-const string, so we copy command_line to provide one.
+ std::vector<char> command(command_line.length() + 1);
+ std::copy(command_line.data(), command_line.data() + command_line.length(), command.begin());
+ command[command_line.length()] = '\0';
+
+ if(!CreateProcess(NULL, &command[0], NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startup_info, &process_info))
+ {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ throw SpawnError(win32_error_message());
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+ }
+#else // G_OS_WIN32
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+ {
+ std::vector<std::string> arguments = Glib::shell_parse_argv(command_line);
+ int child_stdout;
+ int child_stderr;
+ Glib::spawn_async_with_pipes(Glib::get_current_dir(), arguments, Glib::SPAWN_DO_NOT_REAP_CHILD, sigc::slot<void>(), &pid, NULL, redirect & REDIRECT_STDOUT ? &child_stdout : NULL, redirect & REDIRECT_STDERR ? &child_stderr : NULL);
+
+ if(redirect & REDIRECT_STDOUT)
+ redirect_to_string(child_stdout, stdout_text);
+ if(redirect & REDIRECT_STDERR)
+ redirect_to_string(child_stderr, stderr_text);
+ }
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ catch(Glib::Exception& ex)
+ {
+ throw SpawnError(ex.what());
+ }
+#endif // GLIBMM_EXCEPTIONS_ENABLED
+#endif // !G_OS_WIN32
+
+ Glib::signal_child_watch().connect(sigc::mem_fun(*this, &SpawnInfo::on_child_watch), get_pid());
+ }
+
+ ~SpawnInfo()
{
- Glib::Thread::create( sigc::bind(thread_slot, data), false /* joinable */);
+#ifdef G_OS_WIN32
+ // TODO: Is it allowed to close the process handle while the process is still running?
+ CloseHandle(process_info.hProcess);
+ CloseHandle(process_info.hThread);
+
+ if(!stdout_file.empty())
+ {
+ CloseHandle(startup_info.hStdOutput);
+ DeleteFile(stdout_file.c_str());
+ }
+
+ if(!stderr_file.empty())
+ {
+ CloseHandle(startup_info.hStdError);
+ DeleteFile(stderr_file.c_str());
+ }
+#else
+ // TODO: What happens with the process if the child exits, but the mainloop
+ // is not run anymore (and therefore our callback is not called) before
+ // Glom exits itself? Is the child properly closed, or does it remain as
+ // a zombie?
+ if(running)
+ Glib::signal_child_watch().connect(sigc::hide<1>(sigc::ptr_fun(Glib::spawn_close_pid)), pid);
+#endif
}
- catch(const Glib::ThreadError& ex)
+
+ Glib::Pid get_pid()
{
- std::cerr << "Glom::Spawn::execute_command_line_and_wait_do_work(): Glib::Thread::create() failed." << std::endl;
+#ifdef G_OS_WIN32
+ return process_info.hProcess;
+#else
+ return pid;
+#endif
}
+ bool is_running() const { return running; }
+ int get_return_status() const { g_assert(!running); return return_status; }
- // Loop, updating the UI, waiting for the condition to be signalled by the thread:
- cond_mutex.lock(); //The mutex used for timed_wait() must be locked.
- bool keep_waiting = true;
- while(keep_waiting)
+ void get_stdout(std::string& out) const
{
- Glib::TimeVal abs_time;
- abs_time.assign_current_time();
- abs_time.add_milliseconds(500); /* Check 2 times per second */
- if(cond.timed_wait(cond_mutex, abs_time))
- {
- keep_waiting = false;
- }
- else
- {
- dialog_progress.pulse();
+#ifdef G_OS_WIN32
+ out = Glib::file_get_contents(stdout_file);
+#else
+ out = stdout_text;
+#endif
+ }
- while(Gtk::Main::instance()->events_pending())
- Gtk::Main::instance()->iteration();
- }
+ void get_stderr(std::string& err) const
+ {
+#ifdef G_OS_WIN32
+ err = Glib::file_get_contents(stderr_file);
+#else
+ err = stderr_text;
+#endif
}
- cond_mutex.unlock();
- return result;
+ SignalFinished signal_finished() const { return m_signal_finished; }
+
+private:
+ void on_child_watch(Glib::Pid pid, int returned)
+ {
+ running = false;
+ return_status = returned;
+
+ m_signal_finished.emit();
+ }
+
+ bool running;
+ int return_status;
+ SignalFinished m_signal_finished;
+
+#ifdef G_OS_WIN32
+ PROCESS_INFORMATION process_info;
+ STARTUPINFO startup_info;
+ std::string stderr_file;
+ std::string stdout_file;
+#else
+ Glib::Pid pid;
+ std::string stdout_text;
+ std::string stderr_text;
+#endif
+};
+
+std::auto_ptr<const SpawnInfo> spawn_async(const Glib::ustring& command_line, int redirect)
+{
+ return std::auto_ptr<const SpawnInfo>(new SpawnInfo(command_line, redirect));
}
+bool spawn_async_end(std::auto_ptr<const SpawnInfo> info, std::string* stdout_text = NULL, std::string* stderr_text = NULL, int* return_status = NULL)
+{
+ if(stdout_text) info->get_stdout(*stdout_text);
+ if(stderr_text) info->get_stderr(*stderr_text);
+ if(return_status) *return_status = info->get_return_status();
+ return !info->is_running();
+}
+
+int spawn_sync(const Glib::ustring& command_line, std::string* stdout_text, std::string* stderr_text)
+{
+ int redirect_flags = 0;
+ if(stdout_text) redirect_flags |= REDIRECT_STDOUT;
+ if(stderr_text) redirect_flags |= REDIRECT_STDERR;
+
+ std::auto_ptr<const SpawnInfo> info = spawn_async(command_line, redirect_flags);
+ info->signal_finished().connect(sigc::ptr_fun(&Gtk::Main::quit));
+
+ // Wait for termination
+ Gtk::Main::run();
+
+ int return_status = 0;
+ bool returned = spawn_async_end(info, stdout_text, stderr_text, &return_status);
+ g_assert(returned);
+ return return_status;
+}
+
+} // namespace Impl
static Dialog_ProgressCreating* get_and_show_pulse_dialog(const Glib::ustring& message, Gtk::Window* parent_window)
{
@@ -158,10 +369,6 @@
dialog_progress->show();
- //Ensure that the dialog is shown, instead of waiting for the application to be idle:
- while(Gtk::Main::instance()->events_pending())
- Gtk::Main::instance()->iteration();
-
return dialog_progress;
}
}
@@ -183,66 +390,26 @@
std::auto_ptr<Dialog_ProgressCreating> dialog_progress;
dialog_progress.reset(dialog_temp);
- return pulse_until_thread_finished(*dialog_progress, command, sigc::ptr_fun(&execute_command_line_on_thread_create) );
+ std::auto_ptr<const Impl::SpawnInfo> info = Impl::spawn_async(command, 0);
+ info->signal_finished().connect(
+ sigc::bind(sigc::mem_fun(*dialog_progress, &Dialog_ProgressCreating::response), Gtk::RESPONSE_ACCEPT));
+
+ // Pulse two times a second
+ Glib::signal_timeout().connect(
+ sigc::bind_return(sigc::mem_fun(*dialog_progress, &Dialog_ProgressCreating::pulse), true),
+ 500);
+
+ dialog_progress->run();
+
+ int return_status;
+ bool returned = Impl::spawn_async_end(info, NULL, NULL, &return_status);
+ if(!returned) return false; // User closed the dialog prematurely?
+
+ return (return_status == 0);
}
// Callback handlers for execute_command_line_and_wait_until_second_command_returns_success
namespace {
- bool on_stderr_input(Glib::IOCondition cond, const Glib::RefPtr<Glib::IOChannel>& err, std::string& stderr_text)
- {
- if(cond != Glib::IO_IN)
- {
- // Perhaps the pipe was closed or something. Ignore & Disconnect. If the
- // this was because the child exited, then the on_child_watch() callback
- // will be called anyway.
- return false;
- }
- else
- {
- char buffer[1024 + 1];
- gsize bytes_read;
-
- Glib::IOStatus status;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- try
- {
- status = err->read(buffer, 1024, bytes_read);
- }
- catch(const Glib::Exception& ex)
- {
- std::cerr << "execute_command_line_and_wait_until_second_command_returns_success: Error while reading from child stderr pipe: " << ex.what() << std::endl;
- return false;
- }
-#else
- std::auto_ptr<Glib::Error> error;
- status = err->read(buffer, 1024, bytes_read, error);
- if(error.get())
- {
- std::cerr << "execute_command_line_and_wait_until_second_command_returns_success: Error while reading from child stderr pipe: " << ex.what() << std::endl;
- return false;
- }
-#endif
-
- buffer[bytes_read] = '\0';
- stderr_text += buffer;
-
- return status == Glib::IO_STATUS_NORMAL || status == Glib::IO_STATUS_AGAIN;
- }
- }
-
- void on_child_watch(GPid pid, int status, bool& child_exited, Dialog_ProgressCreating* dialog)
- {
- // Child did exit
- child_exited = true;
- // Cancel dialog (and thus the run() call in
- // execute_command_line_and_wait_until_second_command_returns_success) if
- // the child failed.
- if(status != 0)
- dialog->response(Gtk::RESPONSE_REJECT);
-
- Glib::spawn_close_pid(pid);
- }
-
bool on_timeout(const std::string& second_command, const std::string& success_text, Dialog_ProgressCreating* dialog_progress)
{
Glib::ustring stored_env_lang;
@@ -256,8 +423,6 @@
// is probably defined on the system already and that definition would override our LANG:
// (Note that we can not just do "LANG=C;the_command", as on the command line, because g_spawn() does not support that.)
- // TODO: If we would use g_spawn_sync instead of g_spawn_commandline_sync,
- // we could set envp. I don't know whether that would be better. armin.
std::cout << std::endl << "debug: temporarily setting LANG and LANGUAGE environment variables to \"C\"" << std::endl;
stored_env_lang = Glib::getenv("LANG");
stored_env_language = Glib::getenv("LANGUAGE");
@@ -272,18 +437,16 @@
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
- Glib::spawn_command_line_sync(second_command, &stdout_output, NULL, &return_status);
+ return_status = Impl::spawn_sync(second_command, &stdout_output, NULL);
}
- catch(const Glib::SpawnError& ex)
+ catch(const Impl::SpawnError& ex)
{
std::cerr << "Glom::execute_command_line_and_wait_until_second_command_returns_success() Exception while calling Glib::spawn_command_line_sync(): " << ex.what() << std::endl;
// TODO: We should cancel the whole call if this fails three times in
// a row or so.
}
#else
- // TODO: I guess we can't find out whether this failed.
- // This might be a glibmm bug.
- Glib::spawn_command_line_sync(second_command, &stdout_output, NULL, &return_status);
+ Impl::spawn_sync(second_commands, &stdout_output, NULL, &return_status);
#endif
if(!success_text.empty())
@@ -309,8 +472,8 @@
std::cout << "Success, do response" << std::endl;
// Exit from run() in execute_command_line_and_wait_until_second_command_returns_success().
dialog_progress->response(Gtk::RESPONSE_OK);
- // Cancel timeout. Actually, we also could return true here since
- // the signal is disconnect explicetely after run() anyway.
+ // Cancel timeout. Actually, we also could return true here since
+ // the signal is disconnect explicetely after run() anyway.
return false;
}
}
@@ -333,76 +496,18 @@
std::auto_ptr<Dialog_ProgressCreating> dialog_progress;
dialog_progress.reset(dialog_temp);
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- std::vector<std::string> arguments;
- try
- {
- arguments = Glib::shell_parse_argv(command);
- }
- catch(const Glib::ShellError& ex)
- {
- std::cerr << "Glom::Spawn::execute_command_line_and_wait_untils_second_command_returns_success: Exception while calling Glib::shell_parse_argv(): " << ex.what() << std::endl;
- return false;
- }
-#else
- // TODO: I guess we can't find out whether this failed.
- // This might be a glibmm bug.
- arguments = Glib::shell_parse_argv(command);
-#endif
-
- Glib::Pid child_pid;
- int child_stderr;
+ std::cout << "Command: " << command << std::endl;
- std::cout << std::endl << " debug: command_line: " << command << std::endl << std::endl;
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- // Execute the first thread asynchronously (so we don't wait for it):
- try
- {
- Glib::spawn_async_with_pipes(Glib::get_current_dir(), arguments, Glib::SPAWN_DO_NOT_REAP_CHILD, sigc::slot<void>(), &child_pid, NULL, NULL, &child_stderr);
- }
- catch(const Glib::SpawnError& ex)
- {
- std::cerr << "Glom::Spawn::pulse_until_second_command_succeed() Exception while calling Glib::spawn_command_line_async(): " << ex.what() << std::endl;
- return false;
- }
-#else
- // TODO: I guess we can't find out whether this failed.
- // This might be a glibmm bug.
- Glib::spawn_async_with_pipes(Glib::get_current_dir(), arguments, Glib::SPAWN_DO_NOT_REAP_CHILD, sigc::slot<void>(), &child_pid, NULL, NULL, &child_stderr);
-#endif
+ std::auto_ptr<const Impl::SpawnInfo> info = Impl::spawn_async(command, Impl::REDIRECT_STDERR);
// While we wait for the second command to finish we
// a) check whether the first command finished. If it did, and has a
// negative error code, we assume it failed and return directly.
// b) Get stderr data, to display an error message in case the command
// fails:
- // TODO: We also should return if the first command returned with successful
- // error code, because the second command is not likely to change its output
- // when the first command is no longer running.
- std::string stderr_text;
- bool child_exited = false;
- Glib::RefPtr<Glib::IOChannel> err = Glib::IOChannel::create_from_fd(child_stderr);
-
- // We need to set the channel to nonblocking to not block the whole
- // process waiting for input. This is not implemented on Windows, but
- // it works there anyway; I guess it is always nonblocking on Windows:
-#ifndef G_OS_WIN32
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- err->set_flags(Glib::IO_FLAG_NONBLOCK);
-#else
- std::auto_ptr<Glib::Error> error;
- err->set_flags(Glib::IO_FLAG_NONBLOCK, error);
-#endif // !GLIBMM_EXCEPTIONS_ENABLED
-#endif // !G_OS_WIN32
-
- err->set_encoding("");
- err->set_buffered(false);
-
- sigc::connection stderr_conn = Glib::signal_io().connect(sigc::bind(sigc::ptr_fun(&on_stderr_input), err, sigc::ref(stderr_text)), err, Glib::IO_IN);
-
- sigc::connection watch_conn = Glib::signal_child_watch().connect(sigc::bind(sigc::ptr_fun(&on_child_watch), sigc::ref(child_exited), dialog_temp), child_pid);
+ // Hide dialog when the first command finished for some reason
+ sigc::connection watch_conn = info->signal_finished().connect(sigc::bind(sigc::mem_fun(*dialog_temp, &Dialog_ProgressCreating::response), Gtk::RESPONSE_REJECT));
// Call the second command once every second
sigc::connection timeout_conn = Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&on_timeout), sigc::ref(second_command), sigc::ref(success_text), dialog_temp), 1000);
@@ -410,25 +515,15 @@
// Enter the main loop
int response = dialog_temp->run();
- // We are no longer interested in stderr
- stderr_conn.disconnect();
timeout_conn.disconnect();
-
- // We must still wait until the child exits, to call wait on it, so the
- // child does not become a zombie.
watch_conn.disconnect();
- if(!child_exited)
- Glib::signal_child_watch().connect(sigc::hide(sigc::ptr_fun(&Glib::spawn_close_pid)), child_pid);
- // TODO: What happens with the process if the child exits, but the mainloop
- // is not run anymore (and therefore our callback is not called) before
- // Glom exits itself? Is the child properly closed, or does it remain as
- // a zombie?
+ std::string stderr_text;
+
+ Impl::spawn_async_end(info, NULL, &stderr_text, NULL);
if(response == Gtk::RESPONSE_OK)
{
- // The second command succeeded.
-
//Sleep for a bit more, because I think that pg_ctl sometimes reports success too early.
Glib::signal_timeout().connect(sigc::bind_return(sigc::ptr_fun(&Gtk::Main::quit), false), 3000);
Gtk::Main::run();
@@ -437,7 +532,7 @@
}
else
{
- // The user either cancelled, or the first command failed
+ // The user either cancelled, or the first command failed, or exited prematurely
if(response == Gtk::RESPONSE_REJECT)
{
// Command failed
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]