[glom] glom_create_from_example: Support central-hosting too.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] glom_create_from_example: Support central-hosting too.
- Date: Mon, 10 Oct 2011 13:45:29 +0000 (UTC)
commit 0d2a94361d1ed353485adeb99c981a7ed48d94b2
Author: Murray Cumming <murrayc murrayc com>
Date: Mon Oct 10 15:45:07 2011 +0200
glom_create_from_example: Support central-hosting too.
* glom/glom_create_from_example.cc: Allow a host name, port, and username to
be specified, and the password to be entered on stdin.
* glom/libglom/db_utils.[h|cc]: Added get_unused_database_name():
* glom/frame_glom.cc: Added a TODO that we should use it here too instead of
the similar code that is mixed up with the dialog code.
* glom/libglom/connectionpool.h: Remove unused m_host member variable.
ChangeLog | 11 ++++
glom/frame_glom.cc | 1 +
glom/glom_create_from_example.cc | 104 ++++++++++++++++++++++++++++++++++----
glom/libglom/connectionpool.h | 2 +-
glom/libglom/db_utils.cc | 92 +++++++++++++++++++++++++++++----
glom/libglom/db_utils.h | 8 +++
6 files changed, 194 insertions(+), 24 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 0d45589..23cd799 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2011-10-10 Murray Cumming <murrayc murrayc com>
+ glom_create_from_example: Support central-hosting too.
+
+ * glom/glom_create_from_example.cc: Allow a host name, port, and username to
+ be specified, and the password to be entered on stdin.
+ * glom/libglom/db_utils.[h|cc]: Added get_unused_database_name():
+ * glom/frame_glom.cc: Added a TODO that we should use it here too instead of
+ the similar code that is mixed up with the dialog code.
+ * glom/libglom/connectionpool.h: Remove unused m_host member variable.
+
+2011-10-10 Murray Cumming <murrayc murrayc com>
+
Added the glom_create_from_example command-line utility.
* Makefile_libglom.am:
diff --git a/glom/frame_glom.cc b/glom/frame_glom.cc
index a57b45d..76748b2 100644
--- a/glom/frame_glom.cc
+++ b/glom/frame_glom.cc
@@ -2012,6 +2012,7 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
//std::cout << "debug: database_name to create=" << database_name << std::endl;
+ //TODO: Use DbUtils::get_unused_database_name() instead:
bool keep_trying = true;
size_t extra_num = 0;
while(keep_trying)
diff --git a/glom/glom_create_from_example.cc b/glom/glom_create_from_example.cc
index cda42f0..6c96189 100644
--- a/glom/glom_create_from_example.cc
+++ b/glom/glom_create_from_example.cc
@@ -26,6 +26,7 @@
#include <libglom/document/document.h>
#include <libglom/connectionpool.h>
#include <libglom/connectionpool_backends/postgres_self.h>
+#include <libglom/connectionpool_backends/postgres_central.h>
#include <libglom/init.h>
#include <libglom/privs.h>
#include <libglom/db_utils.h>
@@ -46,11 +47,18 @@ public:
std::string m_arg_filepath_dir_output;
std::string m_arg_filepath_name_output;
bool m_arg_version;
+
+ //If not using self-hosting:
+ Glib::ustring m_arg_server_hostname;
+ double m_arg_server_port;
+ Glib::ustring m_arg_server_username;
+ Glib::ustring m_arg_server_password;
};
GlomCreateOptionGroup::GlomCreateOptionGroup()
: Glib::OptionGroup("glom_create_from_example", _("Glom options"), _("Command-line options")),
- m_arg_version(false)
+ m_arg_version(false),
+ m_arg_server_port(0)
{
Glib::OptionEntry entry;
entry.set_long_name("input");
@@ -61,13 +69,13 @@ GlomCreateOptionGroup::GlomCreateOptionGroup()
Glib::OptionEntry entry2;
entry2.set_long_name("output-path");
entry2.set_short_name('o');
- entry2.set_description(_("The directory in which to save the created .glom file, or sub-directory if necessary, such as /home/someuser/"));
+ entry2.set_description(_("The directory in which to save the created .glom file, or sub-directory if necessary, such as /home/someuser/ ."));
add_entry_filename(entry2, m_arg_filepath_dir_output);
Glib::OptionEntry entry3;
entry3.set_long_name("output-name");
entry3.set_short_name('n');
- entry3.set_description(_("The name for the created .glom file, such as something.glom"));
+ entry3.set_description(_("The name for the created .glom file, such as something.glom ."));
add_entry_filename(entry3, m_arg_filepath_name_output);
Glib::OptionEntry entry_version;
@@ -75,6 +83,25 @@ GlomCreateOptionGroup::GlomCreateOptionGroup()
entry_version.set_short_name('V');
entry_version.set_description(_("The version of this application."));
add_entry(entry_version, m_arg_version);
+
+
+ Glib::OptionEntry entry4;
+ entry4.set_long_name("server-hostname");
+ entry4.set_short_name('h');
+ entry4.set_description(_("The hostname of the PostgreSQL server, such as localhost."));
+ add_entry(entry4, m_arg_server_hostname);
+
+ Glib::OptionEntry entry5;
+ entry5.set_long_name("server-port");
+ entry5.set_short_name('p');
+ entry5.set_description(_("The port of the PostgreSQL server, such as 5434."));
+ add_entry(entry5, m_arg_server_port);
+
+ Glib::OptionEntry entry6;
+ entry6.set_long_name("server-username");
+ entry6.set_short_name('u');
+ entry6.set_description(_("The username for the PostgreSQL server."));
+ add_entry(entry6, m_arg_server_username);
}
static void on_initialize_progress()
@@ -336,7 +363,19 @@ int main(int argc, char* argv[])
document.set_file_uri(file_uri);
- document.set_hosting_mode(Glom::Document::HOSTING_MODE_POSTGRES_SELF);
+
+ const bool self_hosting = group.m_arg_server_hostname.empty();
+ if(self_hosting)
+ {
+ std::cout << "Using self-hosting instead of a central PostgreSQL server." << std::endl;
+ document.set_hosting_mode(Glom::Document::HOSTING_MODE_POSTGRES_SELF);
+ }
+ else
+ {
+ std::cout << "Using the PostgreSQL server with host: " << group.m_arg_server_hostname << std::endl;
+ document.set_hosting_mode(Glom::Document::HOSTING_MODE_POSTGRES_CENTRAL);
+ }
+
document.set_is_example_file(false);
document.set_network_shared(false);
const bool saved = document.save();
@@ -346,12 +385,56 @@ int main(int argc, char* argv[])
connection_pool->setup_from_document(&document);
//We must specify a default username and password:
- Glib::ustring password;
- const Glib::ustring user = Glom::Privs::get_default_developer_user_name(password);
- connection_pool->set_user(user);
- connection_pool->set_password(password);
-
- //Create the self-hosting files:
+ if(self_hosting)
+ {
+ Glib::ustring password;
+ const Glib::ustring user = Glom::Privs::get_default_developer_user_name(password);
+ connection_pool->set_user(user);
+ connection_pool->set_password(password);
+ }
+ else
+ {
+ //Get the password from stdin.
+ //This is not a command-line option because then it would appear in logs.
+ //Other command-line utilities such as psql don't do this either.
+ //TODO: Support alternatives such as using a file.
+ const Glib::ustring prompt = Glib::ustring::compose(
+ _("Please enter the PostgreSQL server's password for the user %1: "), group.m_arg_server_username);
+ const char* password = ::getpass(prompt.c_str());
+
+ //Central hosting:
+ connection_pool->set_user(group.m_arg_server_username);
+ connection_pool->set_password(password); //TODO: Take this from stdin instead.
+
+ Glom::ConnectionPool::Backend* backend = connection_pool->get_backend();
+ Glom::ConnectionPoolBackends::PostgresCentralHosted* central =
+ dynamic_cast<Glom::ConnectionPoolBackends::PostgresCentralHosted*>(backend);
+ g_assert(central);
+
+ central->set_host(group.m_arg_server_hostname);
+
+ if(group.m_arg_server_port)
+ {
+ central->set_port(group.m_arg_server_port);
+ central->set_try_other_ports(false);
+ }
+ else
+ {
+ //Try all ports:
+ central->set_try_other_ports(false);
+ }
+
+ const Glib::ustring database_name =
+ Glom::DbUtils::get_unused_database_name(document.get_connection_database());
+ if(database_name.empty())
+ {
+ std::cerr << G_STRFUNC << ": Could not find an unused database name" << std::endl;
+ }
+ else
+ document.set_connection_database(database_name);
+ }
+
+ //Startup. For instance, create the self-hosting files if necessary:
const Glom::ConnectionPool::InitErrors initialized_errors =
connection_pool->initialize( sigc::ptr_fun(&on_initialize_progress) );
g_assert(initialized_errors == Glom::ConnectionPool::Backend::INITERROR_NONE);
@@ -370,7 +453,6 @@ int main(int argc, char* argv[])
if(!recreated)
cleanup();
g_assert(recreated);
-
//Tell the user where the file is:
std::string output_path_used;
diff --git a/glom/libglom/connectionpool.h b/glom/libglom/connectionpool.h
index 5678ec6..2cc2181 100644
--- a/glom/libglom/connectionpool.h
+++ b/glom/libglom/connectionpool.h
@@ -299,7 +299,7 @@ private:
Glib::RefPtr<Gnome::Gda::Connection> m_refGdaConnection;
guint m_sharedconnection_refcount;
bool m_ready_to_connect;
- Glib::ustring m_host, m_user, m_password, m_database;
+ Glib::ustring m_user, m_password, m_database;
FieldTypes* m_pFieldTypes;
bool m_show_debug_output, m_auto_server_shutdown;
diff --git a/glom/libglom/db_utils.cc b/glom/libglom/db_utils.cc
index fb93f6c..f71de1e 100644
--- a/glom/libglom/db_utils.cc
+++ b/glom/libglom/db_utils.cc
@@ -21,6 +21,7 @@
#include <libglom/db_utils.h>
#include <libglom/connectionpool.h>
#include <libglom/data_structure/glomconversions.h>
+#include <libglom/connectionpool_backends/postgres_central.h>
#include <libglom/standard_table_prefs_fields.h>
#include <libglom/privs.h>
#include <libglom/data_structure/parameternamegenerator.h>
@@ -171,6 +172,15 @@ bool create_database(Document* document, const Glib::ustring& database_name, con
}
progress();
+
+ //Save the port, if appropriate, so the document can be used to connect again:
+ Glom::ConnectionPool::Backend* backend = connection_pool->get_backend();
+ Glom::ConnectionPoolBackends::PostgresCentralHosted* central =
+ dynamic_cast<Glom::ConnectionPoolBackends::PostgresCentralHosted*>(backend);
+ if(central)
+ {
+ document->set_connection_port( central->get_port() );
+ }
return true;
}
@@ -183,7 +193,7 @@ bool create_database(Document* document, const Glib::ustring& database_name, con
bool recreate_database_from_document(Document* document, const sigc::slot<void>& progress)
{
- ConnectionPool* connection_pool = ConnectionPool::get_instance();
+ ConnectionPool* connection_pool = ConnectionPool::get_instance();
if(!connection_pool)
return false; //Impossible anyway.
@@ -197,23 +207,23 @@ bool recreate_database_from_document(Document* document, const sigc::slot<void>&
{
connection_pool->set_ready_to_connect(); //This has succeeded already.
sharedptr<SharedConnection> sharedconnection = connection_pool->connect();
- g_warning("Application::recreate_database(): Failed because database exists already.");
+ std::cerr << G_STRFUNC << ": Failed because database exists already." << std::endl;
- return false; //Connection to the database succeeded, because no exception was thrown. so the database exists already.
+ return false; //Connection to the database succeeded, because no exception was thrown. so the database exists already.
}
catch(const ExceptionConnection& ex)
{
- if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
- {
- g_warning("Application::recreate_database(): Failed because connection to server failed even without specifying a database.");
- return false;
- }
+ if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
+ {
+ std::cerr << G_STRFUNC << ": Application::recreate_database(): Failed because connection to server failed even without specifying a database." << std::endl;
+ return false;
+ }
//Otherwise continue, because we _expected_ connect() to fail if the db does not exist yet.
}
- //Create the database: (This will show a connection dialog)
+ //Create the database:
progress();
connection_pool->set_database( Glib::ustring() );
const bool db_created = create_database(document, db_name, document->get_database_title(), progress);
@@ -235,7 +245,7 @@ bool recreate_database_from_document(Document* document, const sigc::slot<void>&
}
catch(const ExceptionConnection& ex)
{
- g_warning("Application::recreate_database(): Failed to connect to the newly-created database.");
+ std::cerr << G_STRFUNC << ": Failed to connect to the newly-created database." << std::endl;
return false;
}
@@ -256,7 +266,7 @@ bool recreate_database_from_document(Document* document, const sigc::slot<void>&
progress();
if(!table_creation_succeeded)
{
- g_warning("Application::recreate_database(): CREATE TABLE failed with the newly-created database.");
+ std::cerr << G_STRFUNC << ": CREATE TABLE failed with the newly-created database." << std::endl;
return false;
}
}
@@ -284,7 +294,7 @@ bool recreate_database_from_document(Document* document, const sigc::slot<void>&
if(!table_insert_succeeded)
{
- g_warning("Application::recreate_database(): INSERT of example data failed with the newly-created database.");
+ std::cerr << G_STRFUNC << ": INSERT of example data failed with the newly-created database." << std::endl;
return false;
}
//}
@@ -1665,6 +1675,64 @@ bool layout_field_should_have_navigation(const Glib::ustring& table_name, const
return field_used_in_relationship_to_one || field_is_related_primary_key;
}
+Glib::ustring get_unused_database_name(const Glib::ustring& base_name)
+{
+ Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
+ if(!connection_pool)
+ return Glib::ustring();
+
+ bool keep_trying = true;
+ size_t extra_num = 0;
+ while(keep_trying)
+ {
+ Glib::ustring database_name_possible;
+ if(extra_num == 0)
+ {
+ //Try the original name first,
+ //removing any characters that are likely to cause problems when used in a SQL identifier name:
+ database_name_possible = Utils::trim_whitespace(base_name);
+ database_name_possible = Utils::string_replace(database_name_possible, "\"", "");
+ database_name_possible = Utils::string_replace(database_name_possible, "'", "");
+ database_name_possible = Utils::string_replace(database_name_possible, "\t", "");
+ database_name_possible = Utils::string_replace(database_name_possible, "\n", "");
+ }
+ else
+ {
+ //Create a new database name by appending a number to the original name:
+ const Glib::ustring pchExtraNum = Glib::ustring::compose("%1", extra_num);
+ database_name_possible = (base_name + pchExtraNum);
+ }
+ ++extra_num;
+
+ connection_pool->set_database(database_name_possible);
+ connection_pool->set_ready_to_connect();
+
+ Glom::sharedptr<Glom::SharedConnection> connection;
+
+ try
+ {
+ connection = ConnectionPool::get_and_connect();
+ }
+ catch(const ExceptionConnection& ex)
+ {
+ if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
+ {
+ //We couldn't even connect to the server,
+ //regardless of what database we try to connect to:
+ std::cerr << G_STRFUNC << ": Could not connect to the server." << std::endl;
+ return Glib::ustring();
+ }
+ else
+ {
+ //We assume that the connection failed because the database does not exist.
+ std::cout << "debug: " << G_STRFUNC << ": unused database name successfully found: " << database_name_possible << std::endl;
+ return database_name_possible;
+ }
+ }
+ }
+
+ return Glib::ustring();
+}
} //namespace DbUtils
diff --git a/glom/libglom/db_utils.h b/glom/libglom/db_utils.h
index a3439df..bb84037 100644
--- a/glom/libglom/db_utils.h
+++ b/glom/libglom/db_utils.h
@@ -117,6 +117,14 @@ void layout_item_fill_field_details(Document* document, const Glib::ustring& par
*/
bool layout_field_should_have_navigation(const Glib::ustring& table_name, const sharedptr<const LayoutItem_Field>& layout_item, const Document* document, sharedptr<Relationship>& field_used_in_relationship_to_one);
+/** Discover a database name that is not yet used.
+ * This assumes that all other connection details are correctly set.
+ *
+ * @param base_name The wished-for name, to be modified until an unused name is found.
+ * @result A database name that does not yet exist on the server.
+ */
+Glib::ustring get_unused_database_name(const Glib::ustring& base_name);
+
} //namespace DbUtils
} //namespace Glom
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]