[glom] Self-Hosting: Use the new ident configuration for PostgreSQL 8.4.



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]