[glom] Self-Hosting: Use the new ident configuration for PostgreSQL 8.4.
- From: Murray Cumming <murrayc src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glom] Self-Hosting: Use the new ident configuration for PostgreSQL 8.4.
- Date: Thu, 24 Sep 2009 17:25:12 +0000 (UTC)
commit 27ae914f8856f97490573ae18ca3a464ebf8f5d1
Author: Murray Cumming <murrayc murrayc com>
Date: Thu Sep 24 19:24:51 2009 +0200
Self-Hosting: Use the new ident configuration for PostgreSQL 8.4.
* glom/libglom/spawn_with_feedback.[h|cc]: Added an
execute_command_line_and_wait() overload that has an output parameter
for the stdout from the command.
* glom/libglom/connectionpool_backends/postgres_self.[h|cc]:
Added a get_postgresql_utils_version_as_number() utiltity method,
and use it in set_network_shared() to use a different syntax for
Postgres 8.4, hopefully fixing bug #595608
ChangeLog | 12 ++
.../connectionpool_backends/postgres_self.cc | 185 +++++++++++++++++++-
.../connectionpool_backends/postgres_self.h | 8 +
glom/libglom/document/document.cc | 2 +-
glom/libglom/spawn_with_feedback.cc | 52 ++++++-
glom/libglom/spawn_with_feedback.h | 8 +
6 files changed, 258 insertions(+), 9 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 8ebd957..11b6d00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2009-09-24 Murray Cumming <murrayc murrayc com>
+ Self-Hosting: Use the new ident configuration for PostgreSQL 8.4.
+
+ * glom/libglom/spawn_with_feedback.[h|cc]: Added an
+ execute_command_line_and_wait() overload that has an output parameter
+ for the stdout from the command.
+ * glom/libglom/connectionpool_backends/postgres_self.[h|cc]:
+ Added a get_postgresql_utils_version_as_number() utiltity method,
+ and use it in set_network_shared() to use a different syntax for
+ Postgres 8.4, hopefully fixing bug #595608
+
+2009-09-24 Murray Cumming <murrayc murrayc com>
+
Self-Hosting: Retry the connection just-long-enough.
* glom/libglom/connectionpool_backends/postgres.[h|cc]: attempt_connect():
diff --git a/glom/libglom/connectionpool_backends/postgres_self.cc b/glom/libglom/connectionpool_backends/postgres_self.cc
index f4f866a..eb775c6 100644
--- a/glom/libglom/connectionpool_backends/postgres_self.cc
+++ b/glom/libglom/connectionpool_backends/postgres_self.cc
@@ -68,7 +68,11 @@ namespace ConnectionPoolBackends
{
//TODO: Do we need these sameuser lines?
-#define DEFAULT_CONFIG_PG_HBA_LOCAL \
+
+// We need both <=8.3 and >=8.4 versions, because the ident line changed syntax
+// incompatibly: http://www.postgresql.org/about/press/features84#security
+
+#define DEFAULT_CONFIG_PG_HBA_LOCAL_8p3 \
"# TYPE DATABASE USER CIDR-ADDRESS METHOD\n\
\n\
# local is for Unix domain socket connections only\n\
@@ -82,9 +86,22 @@ host all all 127.0.0.1 255.255.255.255 md5\n\
# IPv6 local connections:\n\
host all all ::1/128 md5\n"
-#define DEFAULT_CONFIG_PG_HBA_REMOTE \
-"DEFAULT_CONFIG_PG_HBA_LOCAL \
+#define DEFAULT_CONFIG_PG_HBA_LOCAL_8p4 \
+"# TYPE DATABASE USER CIDR-ADDRESS METHOD\n\
+\n\
+# local is for Unix domain socket connections only\n\
+# trust allows connection from the current PC without a password:\n\
+local all all trust\n\
+local all all ident\n\
+local all all md5\n\
\n\
+# TCP connections from the same computer, with a password:\n\
+host all all 127.0.0.1 255.255.255.255 md5\n\
+# IPv6 local connections:\n\
+host all all ::1/128 md5\n"
+
+#define DEFAULT_CONFIG_PG_HBA_REMOTE_EXTRA \
+"\n\
# IPv4 local connections:\n\
host all all 0.0.0.0/0 md5\n\
# IPv6 local connections:\n\
@@ -93,6 +110,18 @@ host all all ::1/128 md5\n"
#define PORT_POSTGRESQL_SELF_HOSTED_START 5433
#define PORT_POSTGRESQL_SELF_HOSTED_END 5500
+
+#define DEFAULT_CONFIG_PG_HBA_REMOTE_8p3 \
+DEFAULT_CONFIG_PG_HBA_LOCAL_8p3 \
+DEFAULT_CONFIG_PG_HBA_REMOTE_EXTRA
+
+#define DEFAULT_CONFIG_PG_HBA_REMOTE_8p4 \
+DEFAULT_CONFIG_PG_HBA_LOCAL_8p3 \
+DEFAULT_CONFIG_PG_HBA_REMOTE_EXTRA
+
+#define PORT_POSTGRESQL_SELF_HOSTED_START 5433
+#define PORT_POSTGRESQL_SELF_HOSTED_END 5500
+
#define DEFAULT_CONFIG_PG_IDENT ""
PostgresSelfHosted::PostgresSelfHosted()
@@ -272,9 +301,138 @@ Backend::InitErrors PostgresSelfHosted::initialize(const SlotProgress& slot_prog
return result ? INITERROR_NONE : INITERROR_COULD_NOT_START_SERVER;
}
+Glib::ustring PostgresSelfHosted::get_postgresql_utils_version(const SlotProgress& slot_progress)
+{
+ Glib::ustring result;
+
+ const std::string command = "\"" + get_path_to_postgres_executable("pg_ctl") + "\" --version";
+
+ //The first command does not return, but the second command can check whether it succeeded:
+ std::string output;
+ const bool spawn_result = Glom::Spawn::execute_command_line_and_wait(command, slot_progress, output);
+ if(!spawn_result)
+ {
+ std::cerr << "Error while attempting to discover the pg_ctl version." << std::endl;
+ return result;
+ }
+
+ //Use a regex to get the version number:
+ Glib::RefPtr<Glib::Regex> regex;
+
+ //We want the characters at the end:
+ const gchar* VERSION_REGEX = "pg_ctl \\(PostgreSQL\\) (.*)";
+
+ #ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ regex = Glib::Regex::create(VERSION_REGEX);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << "Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
+ return result;
+ }
+ #else
+ std::auto_ptr<Glib::Error> ex;
+ regex = Glib::Regex::create(VERSION_REGEX, static_cast<Glib::RegexCompileFlags>(0), static_cast<Glib::RegexMatchFlags>(0), ex);
+ if(ex.get())
+ {
+ std::cerr << "Glom: Glib::Regex::create() failed: " << ex->what() << std::endl;
+ return result;
+ }
+ #endif
+
+ if(!regex)
+ return result;
+
+ typedef std::vector<Glib::ustring> type_vec_strings;
+ const type_vec_strings vec = regex->split(output, Glib::REGEX_MATCH_NOTEMPTY);
+ //std::cout << "DEBUG: output == " << output << std::endl;
+ //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
+
+ // We get, for instance, "\n" and 8.4.1" and "\n".
+ for(type_vec_strings::const_iterator iter = vec.begin();
+ iter != vec.end();
+ ++iter)
+ {
+ const Glib::ustring str = *iter;
+ if(!str.empty())
+ return str; //Found.
+ }
+
+ return result;
+}
+
+float PostgresSelfHosted::get_postgresql_utils_version_as_number(const SlotProgress& slot_progress)
+{
+ float result = 0;
+
+ const Glib::ustring version_str = get_postgresql_utils_version(slot_progress);
+
+ Glib::RefPtr<Glib::Regex> regex;
+
+ //We want the characters at the end:
+ const gchar* VERSION_REGEX = "^(\\d*)\\.(\\d*)";
+
+ #ifdef GLIBMM_EXCEPTIONS_ENABLED
+ try
+ {
+ regex = Glib::Regex::create(VERSION_REGEX);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << "Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
+ return result;
+ }
+ #else
+ std::auto_ptr<Glib::Error> ex;
+ regex = Glib::Regex::create(VERSION_REGEX, static_cast<Glib::RegexCompileFlags>(0), static_cast<Glib::RegexMatchFlags>(0), ex);
+ if(ex.get())
+ {
+ std::cerr << "Glom: Glib::Regex::create() failed: " << ex->what() << std::endl;
+ return result;
+ }
+ #endif
+
+ if(!regex)
+ return result;
+
+ typedef std::vector<Glib::ustring> type_vec_strings;
+ const type_vec_strings vec = regex->split(version_str, Glib::REGEX_MATCH_NOTEMPTY);
+ //std::cout << "DEBUG: str == " << version_str << std::endl;
+ //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
+
+ //We need to loop over the numbers because we get some "" items that we want to ignore:
+ guint count = 0; //We want 2 numbers.
+ for(type_vec_strings::const_iterator iter = vec.begin();
+ iter != vec.end();
+ ++iter)
+ {
+ //std::cout << "regex item: START" << *iter << "END" << std::endl;
+
+ const Glib::ustring str = *iter;
+ if(str.empty())
+ continue;
+
+ const float num = atoi(str.c_str());
+ if(count == 0)
+ result = num;
+ else if(count == 1)
+ {
+ result += (0.1 * num);
+ break;
+ }
+
+ ++count;
+ }
+
+ return result;
+}
+
+
bool PostgresSelfHosted::startup(const SlotProgress& slot_progress, bool network_shared)
{
- m_network_shared = network_shared;
+ m_network_shared = network_shared;
// Don't risk random crashes, although this really shouldn't be called
// twice of course.
@@ -405,7 +563,9 @@ void PostgresSelfHosted::cleanup(const SlotProgress& slot_progress)
m_port = 0;
}
-bool PostgresSelfHosted::set_network_shared(const SlotProgress& /* slot_progress */, bool network_shared)
+
+
+bool PostgresSelfHosted::set_network_shared(const SlotProgress& slot_progress, bool network_shared)
{
//TODO: Use slot_progress, while doing async IO for create_text_file().
@@ -415,7 +575,20 @@ bool PostgresSelfHosted::set_network_shared(const SlotProgress& /* slot_progress
const std::string dbdir = Glib::filename_from_uri(dbdir_uri);
const std::string dbdir_uri_config = dbdir_uri + "/config";
- const char* default_conf_contents = m_network_shared ? DEFAULT_CONFIG_PG_HBA_REMOTE : DEFAULT_CONFIG_PG_HBA_LOCAL;
+ const char* default_conf_contents = 0;
+
+ // Choose the configuration contents based on the postgresql version
+ // and whether we want to be network-shared:
+ const float postgresql_version = get_postgresql_utils_version_as_number(slot_progress);
+ //std::cout << "DEBUG: postgresql_version=" << postgresql_version << std::endl;
+
+ if(postgresql_version >= 8.4f)
+ default_conf_contents = m_network_shared ? DEFAULT_CONFIG_PG_HBA_REMOTE_8p4 : DEFAULT_CONFIG_PG_HBA_LOCAL_8p4;
+ else
+ default_conf_contents = m_network_shared ? DEFAULT_CONFIG_PG_HBA_REMOTE_8p3 : DEFAULT_CONFIG_PG_HBA_LOCAL_8p3;
+
+ //std::cout << "DEBUG: default_conf_contents=" << default_conf_contents << std::endl;
+
const bool hba_conf_creation_succeeded = create_text_file(dbdir_uri_config + "/pg_hba.conf", default_conf_contents);
g_assert(hba_conf_creation_succeeded);
if(!hba_conf_creation_succeeded)
diff --git a/glom/libglom/connectionpool_backends/postgres_self.h b/glom/libglom/connectionpool_backends/postgres_self.h
index 1b52d1a..17af78d 100644
--- a/glom/libglom/connectionpool_backends/postgres_self.h
+++ b/glom/libglom/connectionpool_backends/postgres_self.h
@@ -83,6 +83,14 @@ private:
//bool directory_exists_filepath(const std::string& filepath);
bool directory_exists_uri(const std::string& uri);
+ /** Run the command-line with the --version option to discover what version
+ * of PostgreSQL is installed, so we can use the appropriate configuration
+ * options when self-hosting.
+ */
+ Glib::ustring get_postgresql_utils_version(const SlotProgress& slot_progress);
+
+ float get_postgresql_utils_version_as_number(const SlotProgress& slot_progress);
+
std::string m_self_hosting_data_uri;
int m_port;
bool m_network_shared;
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 33b1362..96bd562 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -285,7 +285,7 @@ Document::HostingMode Document::get_hosting_mode() const
return m_hosting_mode;
}
-void Document:: set_network_shared(bool shared)
+void Document::set_network_shared(bool shared)
{
if(shared != m_network_shared)
{
diff --git a/glom/libglom/spawn_with_feedback.cc b/glom/libglom/spawn_with_feedback.cc
index 168fd9d..1db1e18 100644
--- a/glom/libglom/spawn_with_feedback.cc
+++ b/glom/libglom/spawn_with_feedback.cc
@@ -184,6 +184,8 @@ private:
public:
typedef sigc::signal<void> SignalFinished;
+ /** TODO: Document the redirect parameter.
+ */
SpawnInfo(const Glib::ustring& command_line, int redirect):
running(false), return_status(0)
{
@@ -380,7 +382,6 @@ int spawn_sync(const Glib::ustring& command_line, std::string* stdout_text, std:
} // namespace Impl
-
bool execute_command_line_and_wait(const std::string& command, const SlotProgress& slot_progress)
{
//Show UI progress feedback while we wait for the command to finish:
@@ -404,10 +405,57 @@ bool execute_command_line_and_wait(const std::string& command, const SlotProgres
timeout_connection.disconnect();
int return_status = false;
- const bool returned = Impl::spawn_async_end(info, NULL, NULL, &return_status);
+ const bool returned = Impl::spawn_async_end(info, 0, 0, &return_status);
+ if(!returned)
+ return false; // User closed the dialog prematurely?
+
+ return (return_status == 0);
+}
+
+bool execute_command_line_and_wait(const std::string& command, const SlotProgress& slot_progress, std::string& output)
+{
+ //Initialize output parameter:
+ output = std::string();
+
+ //Show UI progress feedback while we wait for the command to finish:
+
+ std::auto_ptr<const Impl::SpawnInfo> info = Impl::spawn_async(command, Impl::REDIRECT_STDOUT | Impl::REDIRECT_STDERR);
+
+ Glib::RefPtr<Glib::MainLoop> mainloop = Glib::MainLoop::create(false);
+ info->signal_finished().connect(
+ sigc::bind(sigc::ptr_fun(&on_spawn_info_finished), sigc::ref(mainloop) ) );
+
+ // Pulse two times a second:
+ sigc::connection timeout_connection = Glib::signal_timeout().connect(
+ sigc::bind_return( slot_progress, true),
+ 500);
+ slot_progress(); //Make sure it is called at least once.
+
+ //Block until signal_finished is called.
+ mainloop->run();
+
+ //Stop the timeout callback:
+ timeout_connection.disconnect();
+
+ int return_status = false;
+ std::string stdout_text, stderr_text;
+ const bool returned = Impl::spawn_async_end(info, &stdout_text, &stderr_text, &return_status);
if(!returned)
return false; // User closed the dialog prematurely?
+ //std::cout << "DEBUG: command=" << command << std::endl;
+ //std::cout << " DEBUG: stdout_text=" << stdout_text << std::endl;
+ //std::cout << " DEBUG: stderr_text=" << stderr_text << std::endl;
+
+ output = stdout_text;
+
+ if(!stderr_text.empty())
+ {
+ std::cerr << "Glom: execute_command_line_and_wait(): command produced stderr text: " << std::endl <<
+ " command: " << command << std::endl <<
+ " error text: " << stderr_text << std::endl;
+ }
+
return (return_status == 0);
}
diff --git a/glom/libglom/spawn_with_feedback.h b/glom/libglom/spawn_with_feedback.h
index e5a056f..8f9a7c3 100644
--- a/glom/libglom/spawn_with_feedback.h
+++ b/glom/libglom/spawn_with_feedback.h
@@ -42,6 +42,14 @@ typedef sigc::slot<void> SlotProgress;
*/
bool execute_command_line_and_wait(const std::string& command, const SlotProgress& slot_progress);
+/** Execute a command-line command, and wait for it to return.
+ * @param command The command-line command.
+ * @param message A human-readable message to be shown, for instance in a dialog, while waiting.
+ * @slot_progress A callback to call while the work is still happening.
+ * @output The stdout output of the command.
+ */
+bool execute_command_line_and_wait(const std::string& command, const SlotProgress& slot_progress, std::string& output);
+
/** Execute a command-line command, and repeatedly call a second command that tests whether the first command has finished.
* @param command The command-line command.
* @param message A human-readable message to be shown, for instance in a dialog, while waiting.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]