[glom/feature_backup2] Added Developer/Restore Backup menu item.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom/feature_backup2] Added Developer/Restore Backup menu item.
- Date: Thu, 22 Jul 2010 13:24:25 +0000 (UTC)
commit 644a18a6f6d32104c6135d564e53cb3a64cf07b0
Author: Murray Cumming <murrayc murrayc com>
Date: Thu Jul 22 15:23:29 2010 +0200
Added Developer/Restore Backup menu item.
* glom/application.[h.cc]: Added a Developer/Restore Backup menu item,
which lets the user choose a .tar.gz, untars it in /tmp/ and opens it.
* tests/test_selfhosting_new_empty.cc:
* glom/libglom/utils.[h|cc]: Move delete_directory() to Utils.
Added get_directory_child_with_suffix(), used to find the .glom file inside
an untarred directory.
ChangeLog | 12 ++
glom/application.cc | 112 +++++++++++++++++++-
glom/application.h | 1 +
glom/libglom/connectionpool_backends/postgres.cc | 2 +-
glom/libglom/utils.cc | 97 +++++++++++++++--
glom/libglom/utils.h | 15 +++
glom/main.cc | 1 +
.../mode_design/translation/window_translations.cc | 2 +
tests/test_selfhosting_new_empty.cc | 48 +--------
9 files changed, 228 insertions(+), 62 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index bc2b7c5..626032c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2010-07-22 Murray Cumming <murrayc murrayc com>
+ Added Developer/Restore Backup menu item.
+
+ * glom/application.[h.cc]: Added a Developer/Restore Backup menu item,
+ which lets the user choose a .tar.gz, untars it in /tmp/ and opens it.
+
+ * tests/test_selfhosting_new_empty.cc:
+ * glom/libglom/utils.[h|cc]: Move delete_directory() to Utils.
+ Added get_directory_child_with_suffix(), used to find the .glom file inside
+ an untarred directory.
+
+2010-07-22 Murray Cumming <murrayc murrayc com>
+
Saving from a backup: Now works.
* glom/application.[h|cc]: on_document_load(): Simplify the code to
diff --git a/glom/application.cc b/glom/application.cc
index 5e2c90d..5e52aa8 100644
--- a/glom/application.cc
+++ b/glom/application.cc
@@ -563,6 +563,10 @@ void Application::init_menus()
m_listDeveloperActions.push_back(action);
m_refActionGroup_Others->add(action, sigc::mem_fun(*this, &Application::on_menu_developer_export_backup));
+ action = Gtk::Action::create("GlomAction_Menu_Developer_RestoreBackup", _("_Restore Backup"));
+ m_listDeveloperActions.push_back(action);
+ m_refActionGroup_Others->add(action, sigc::mem_fun(*this, &Application::on_menu_developer_restore_backup));
+
m_action_show_layout_toolbar = Gtk::ToggleAction::create("GlomAction_Menu_Developer_ShowLayoutToolbar", _("_Show Layout Toolbar"));
m_listDeveloperActions.push_back(m_action_show_layout_toolbar);
m_refActionGroup_Others->add(m_action_show_layout_toolbar, sigc::mem_fun(*this, &Application::on_menu_developer_show_layout_toolbar));
@@ -619,8 +623,10 @@ void Application::init_menus()
" <menuitem action='GlomAction_Menu_Developer_ActivePlatform_Normal' />"
" <menuitem action='GlomAction_Menu_Developer_ActivePlatform_Maemo' />"
" </menu>"
- " <menuitem action='GlomAction_Menu_Developer_ExportBackup' />"
" <menuitem action='GlomAction_Menu_Developer_ShowLayoutToolbar' />"
+ " <separator />"
+ " <menuitem action='GlomAction_Menu_Developer_ExportBackup' />"
+ " <menuitem action='GlomAction_Menu_Developer_RestoreBackup' />"
" </menu>"
#endif // !GLOM_ENABLE_CLIENT_ONLY
" </placeholder>"
@@ -1969,7 +1975,7 @@ bool Application::recreate_database_from_backup(const Glib::ustring& backup_uri,
}
//Restore the database from the backup:
- std::cout << "DEBUG: original_dir_path=" << original_dir_path << std::endl;
+ //std::cout << "DEBUG: original_dir_path=" << original_dir_path << std::endl;
const bool restored = connection_pool->convert_backup(
sigc::mem_fun(*this, &Application::on_connection_convert_backup_progress), original_dir_path);
@@ -2807,7 +2813,7 @@ void Application::on_menu_developer_export_backup()
if(saved)
{
-
+ std::cerr << G_STRFUNC << "tar failed with command:" << command_tar << std::endl;
}
if(m_dialog_progess_save_backup)
@@ -2822,6 +2828,106 @@ void Application::on_menu_developer_export_backup()
ui_warning(_("Export Backup failed."), _("There was an error while exporting the backup."));
}
+void Application::on_menu_developer_restore_backup()
+{
+ Gtk::FileChooserDialog file_dlg(_("Choose a backup file"), Gtk::FILE_CHOOSER_ACTION_OPEN);
+ file_dlg.set_transient_for(*this);
+ file_dlg.set_local_only(); //Because we can't untar remote files.
+
+ Gtk::FileFilter filter;
+ filter.set_name(_(".tar.gz Backup files"));
+ filter.add_pattern("*.tar.gz");
+ filter.add_pattern("*.tgz");
+ file_dlg.add_filter(filter);
+
+ file_dlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ file_dlg.add_button(_("Restore"), Gtk::RESPONSE_OK);
+
+ const int result = file_dlg.run();
+ file_dlg.hide();
+ if(result != Gtk::RESPONSE_OK)
+ return;
+
+ // We cannot use an uri here, because we cannot untar remote files.
+ const std::string filename_tarball = file_dlg.get_filename();
+ if(filename_tarball.empty())
+ return;
+
+ const std::string path_tar = Glib::find_program_in_path("tar");
+ if(path_tar.empty())
+ {
+ std::cerr << G_STRFUNC << ": The tar executable could not be found." << std::endl;
+ return;
+ }
+
+ //Create a temporary directory into which we will untar the tarball:
+ std::string path_tmp = Glib::build_filename(
+ Glib::get_tmp_dir(), Glib::path_get_basename(filename_tarball));
+ path_tmp += "_extracted";
+
+ //Make sure that the directory does not exist already:
+ const Glib::ustring uri_tmp = Glib::filename_to_uri(path_tmp);
+ if(!Utils::delete_directory(uri_tmp))
+ {
+ std::cerr << G_STRFUNC << "Error from Utils::delete_directory() while trying to remove directory: " << uri_tmp << std::endl;
+ return;
+ }
+
+ //Create the tmp directory:
+ const int mkdir_succeeded = g_mkdir_with_parents(path_tmp.c_str(), 0770);
+ if(mkdir_succeeded == -1)
+ {
+ std::cerr << G_STRFUNC << "Error from g_mkdir_with_parents() while trying to create directory: " << path_tmp << std::endl;
+ perror("Error from g_mkdir_with_parents");
+
+ return;
+ }
+
+ //Untar into the tmp directory:
+ //TODO: Find some way to do this without using the command-line,
+ //which feels fragile:
+ const std::string command_tar = "\"" + path_tar + "\"" +
+ " --force-local --no-wildcards" + //Avoid side-effects of special characters.
+ " -xzf"
+ " \"" + filename_tarball + "\"" +
+ " --directory \"" + path_tmp + "\"";
+
+ //std::cout << "DEBUG: command_tar=" << command_tar << std::endl;
+
+ const bool untarred = Glom::Spawn::execute_command_line_and_wait(command_tar,
+ sigc::mem_fun(*this, &Application::on_connection_convert_backup_progress));
+ if(!untarred)
+ {
+ std::cerr << G_STRFUNC << ": tar failed with command:" << command_tar << std::endl;
+ }
+
+ if(m_dialog_progess_convert_backup)
+ {
+ delete m_dialog_progess_convert_backup;
+ m_dialog_progess_convert_backup = 0;
+ }
+
+ if(!untarred)
+ ui_warning(_("Restore Backup failed."), _("There was an error while restoring the backup. The tar utility failed to extract the archive."));
+
+ //Open the .glom file that is in the tmp directory:
+ const Glib::ustring untarred_uri = Utils::get_directory_child_with_suffix(uri_tmp, ".glom", true /* recurse */);
+ if(untarred_uri.empty())
+ {
+ ui_warning(_("Restore Backup failed."), _("There was an error while restoring the backup. The .glom file could not be found."));
+ return;
+ }
+
+ //std::cout << "DEBUG: untarred_uri=" << untarred_uri << std::endl;
+ open_document(untarred_uri);
+
+ //Delete the temporary untarred directory:
+ //Actually, we just leave this here, where the system will clean it up anyway,
+ //because open_document() starts a new process,
+ //so we don't know when we can safely delete the files.
+ //Utils::delete_directory(uri_tmp);
+}
+
void Application::on_menu_developer_show_layout_toolbar()
{
m_pFrame->show_layout_toolbar(m_action_show_layout_toolbar->get_active());
diff --git a/glom/application.h b/glom/application.h
index 12104ee..0978b0b 100644
--- a/glom/application.h
+++ b/glom/application.h
@@ -172,6 +172,7 @@ private:
void on_menu_developer_active_platform_normal();
void on_menu_developer_active_platform_maemo();
void on_menu_developer_export_backup();
+ void on_menu_developer_restore_backup();
void on_menu_developer_show_layout_toolbar();
void on_window_translations_hide();
diff --git a/glom/libglom/connectionpool_backends/postgres.cc b/glom/libglom/connectionpool_backends/postgres.cc
index 91db725..58cc023 100644
--- a/glom/libglom/connectionpool_backends/postgres.cc
+++ b/glom/libglom/connectionpool_backends/postgres.cc
@@ -542,7 +542,7 @@ bool Postgres::save_password_to_pgpass(const Glib::ustring username, const Glib:
//Move any existing file out of the way:
if(file_exists_filepath(filepath_pgpass))
{
- std::cout << "DEBUG: File exists: " << filepath_pgpass << std::endl;
+ //std::cout << "DEBUG: File exists: " << filepath_pgpass << std::endl;
filepath_previous = filepath_pgpass + ".glombackup";
if(g_rename(filepath_pgpass.c_str(), filepath_previous.c_str()) != 0)
{
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index 86c7af7..059d6df 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -236,7 +236,7 @@ static void add_to_relationships_list(type_list_relationships& list_relationship
list_relationships.push_back(uses_rel);
}
-
+
}
@@ -307,7 +307,7 @@ Glib::ustring Utils::build_sql_select_fields_to_get(const Glib::ustring& table_n
return sql_part_fields;
}
- //LEFT OUTER JOIN will get the field values from the other tables,
+ //LEFT OUTER JOIN will get the field values from the other tables,
//and give us our fields for this table even if there is no corresponding value in the other table.
for(type_list_relationships::const_iterator iter = list_relationships.begin(); iter != list_relationships.end(); ++iter)
{
@@ -340,7 +340,7 @@ Glib::ustring Utils::build_sql_select_with_where_clause(const Glib::ustring& tab
table_name, fieldsToGet, sort_clause, sql_part_from, sql_part_leftouterjoin);
//Build the whole SQL statement:
- Glib::ustring result =
+ Glib::ustring result =
"SELECT " + sql_part_fields +
" FROM \"" + table_name + '\"';
@@ -488,7 +488,7 @@ Utils::type_list_values_with_second Utils::get_choice_values(const sharedptr<con
itempair.second = datamodel->get_value_at(1, row, error);
#endif
- list_values.push_back(itempair);
+ list_values.push_back(itempair);
}
}
else
@@ -521,7 +521,7 @@ Glib::ustring Utils::string_escape_underscores(const Glib::ustring& text)
return result;
}
-/** Get just the first part of a locale, such as de_DE,
+/** Get just the first part of a locale, such as de_DE,
* ignoring, for instance, .UTF-8 or \ euro at the end.
*/
Glib::ustring Utils::locale_simplify(const Glib::ustring& locale_id)
@@ -647,13 +647,13 @@ Utils::type_vec_strings Utils::string_separate(const Glib::ustring& str, const G
const Glib::ustring::size_type size_separator = separator.size();
//A stack of quotes, so that we can handle nested quotes, whether they are " or ':
- typedef std::stack<Glib::ustring> type_queue_quotes;
+ typedef std::stack<Glib::ustring> type_queue_quotes;
type_queue_quotes m_current_quotes;
Glib::ustring::size_type unprocessed_start = 0;
Glib::ustring::size_type item_start = 0;
while(unprocessed_start < size)
- {
+ {
//std::cout << "while unprocessed: un_processed_start=" << unprocessed_start << std::endl;
Glib::ustring::size_type posComma = str.find(separator, unprocessed_start);
@@ -666,18 +666,18 @@ Utils::type_vec_strings Utils::string_separate(const Glib::ustring& str, const G
if(ignore_quoted_separator)
{
//std::cout << " debug: attempting to ignore quoted separators: " << separator << std::endl;
-
+
Glib::ustring::size_type posLastQuote = unprocessed_start;
//std::cout << " debug: posLastQuote=" << posLastQuote << std::endl;
//std::cout << " debug: posComma=" << posComma << std::endl;
-
-
+
+
bool bContinue = true;
while(bContinue && (posLastQuote < posComma))
{
//std::cout << " continue" << std::endl;
- Glib::ustring closing_quote;
+ Glib::ustring closing_quote;
if(!m_current_quotes.empty())
closing_quote = m_current_quotes.top();
@@ -752,7 +752,7 @@ Utils::type_vec_strings Utils::string_separate(const Glib::ustring& str, const G
// Do not add this item to the result, because it was quoted.
continue;
}
-
+
unprocessed_start = posComma + size_separator; //The while loops stops when this is empty.
}
else //if no separator found:
@@ -841,5 +841,78 @@ bool Utils::file_exists(const Glib::ustring& uri)
}
}
+bool Utils::delete_directory(const Glib::RefPtr<Gio::File>& directory)
+{
+ if(!(directory->query_exists()))
+ return true;
+
+ //(Recursively) Delete any child files and directories,
+ //so we can delete this directory.
+ Glib::RefPtr<Gio::FileEnumerator> enumerator = directory->enumerate_children();
+
+ Glib::RefPtr<Gio::FileInfo> info = enumerator->next_file();
+ while(info)
+ {
+ Glib::RefPtr<Gio::File> child = directory->get_child(info->get_name());
+ bool removed_child = false;
+ if(child->query_file_type() == Gio::FILE_TYPE_DIRECTORY)
+ removed_child = delete_directory(child);
+ else
+ removed_child = child->remove();
+
+ if(!removed_child)
+ return false;
+
+ info = enumerator->next_file();
+ }
+
+ //Delete the actual directory:
+ if(!directory->remove())
+ return false;
+
+ return true;
+}
+
+bool Utils::delete_directory(const std::string& uri)
+{
+ Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(uri);
+ return delete_directory(file);
+}
+
+/** For instance, to find the first file in the directory with a .glom extension.
+ */
+Glib::ustring Utils::get_directory_child_with_suffix(const Glib::ustring& uri_directory, const std::string& suffix, bool recursive)
+{
+ Glib::RefPtr<Gio::File> directory = Gio::File::create_for_uri(uri_directory);
+ Glib::RefPtr<Gio::FileEnumerator> enumerator = directory->enumerate_children();
+
+ Glib::RefPtr<Gio::FileInfo> info = enumerator->next_file();
+ while(info)
+ {
+ Glib::RefPtr<const Gio::File> child = directory->get_child(info->get_name());
+
+ const Gio::FileType file_type = child->query_file_type();
+ if(file_type == Gio::FILE_TYPE_REGULAR)
+ {
+ //Check the filename:
+ const std::string basename = child->get_basename();
+ if(string_remove_suffix(basename, suffix) != basename)
+ return child->get_uri();
+ }
+ else if(recursive && file_type == Gio::FILE_TYPE_DIRECTORY)
+ {
+ //Look in sub-directories too:
+ const Glib::ustring result = get_directory_child_with_suffix(child->get_uri(), suffix, recursive);
+ if(!result.empty())
+ return result;
+ }
+
+ info = enumerator->next_file();
+ }
+
+ return Glib::ustring();
+}
+
+
} //namespace Glom
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index f46aade..4ab5b46 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -25,6 +25,7 @@
#include <libglom/data_structure/numeric_format.h>
#include <libglom/data_structure/layout/layoutitem_field.h>
+#include <giomm/file.h>
namespace Glom
{
@@ -131,6 +132,20 @@ Glib::ustring string_remove_suffix(const Glib::ustring& str, const Glib::ustring
bool file_exists(const Glib::ustring& uri);
+/** Delete a directory, if it exists, and its contents.
+ * Unlike g_file_delete(), this does not fail if the directory is not empty.
+ */
+bool delete_directory(const Glib::RefPtr<Gio::File>& directory);
+
+/** Delete a directory, if it exists, and its contents.
+ * Unlike g_file_delete(), this does not fail if the directory is not empty.
+ */
+bool delete_directory(const std::string& uri);
+
+/** For instance, to find the first file in the directory with a .glom extension.
+ */
+Glib::ustring get_directory_child_with_suffix(const Glib::ustring& uri_directory, const std::string& suffix, bool recursive);
+
} //namespace Utils
} //namespace Glom
diff --git a/glom/main.cc b/glom/main.cc
index 4535539..9ceb9b0 100644
--- a/glom/main.cc
+++ b/glom/main.cc
@@ -546,6 +546,7 @@ main(int argc, char* argv[])
if(!file->query_exists())
{
std::cerr << _("Glom: The file does not exist.") << std::endl;
+ std::cerr << "uri: " << input_uri << std::endl;
std::cerr << std::endl << context.get_help() << std::endl;
return -1;
diff --git a/glom/mode_design/translation/window_translations.cc b/glom/mode_design/translation/window_translations.cc
index 277ac26..f8f8cd4 100644
--- a/glom/mode_design/translation/window_translations.cc
+++ b/glom/mode_design/translation/window_translations.cc
@@ -495,6 +495,7 @@ void Window_Translations::on_button_export()
//Show the file-chooser dialog, to select an output .po file:
Gtk::FileChooserDialog file_dlg(_("Choose .po File Name"), Gtk::FILE_CHOOSER_ACTION_SAVE);
+ file_dlg.set_transient_for(*this);
file_dlg.set_do_overwrite_confirmation();
// Only po files
@@ -573,6 +574,7 @@ void Window_Translations::on_button_import()
return;
Gtk::FileChooserDialog file_dlg(_("Choose .po File Name"), Gtk::FILE_CHOOSER_ACTION_OPEN);
+ file_dlg.set_transient_for(*this);
// Only po files
Gtk::FileFilter filter;
diff --git a/tests/test_selfhosting_new_empty.cc b/tests/test_selfhosting_new_empty.cc
index f36cc81..f5a1e8f 100644
--- a/tests/test_selfhosting_new_empty.cc
+++ b/tests/test_selfhosting_new_empty.cc
@@ -40,50 +40,6 @@ static void on_cleanup_progress()
std::cout << "Database cleanup progress" << std::endl;
}
-/** Delete a directory, if it exists, and its contents.
- * Unlike g_file_delete(), this does not fail if the directory is not empty.
- */
-static bool delete_directory(const Glib::RefPtr<Gio::File>& directory)
-{
- if(!(directory->query_exists()))
- return true;
-
- //(Recursively) Delete any child files and directories,
- //so we can delete this directory.
- Glib::RefPtr<Gio::FileEnumerator> enumerator = directory->enumerate_children();
-
- Glib::RefPtr<Gio::FileInfo> info = enumerator->next_file();
- while(info)
- {
- Glib::RefPtr<Gio::File> child = directory->get_child(info->get_name());
- bool removed_child = false;
- if(child->query_file_type() == Gio::FILE_TYPE_DIRECTORY)
- removed_child = delete_directory(child);
- else
- removed_child = child->remove();
-
- if(!removed_child)
- return false;
-
- info = enumerator->next_file();
- }
-
- //Delete the actual directory:
- if(!directory->remove())
- return false;
-
- return true;
-}
-
-/** Delete a directory, if it exists, and its contents.
- * Unlike g_file_delete(), this does not fail if the directory is not empty.
- */
-static bool delete_directory(const std::string& uri)
-{
- Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(uri);
- return delete_directory(file);
-}
-
int main()
{
Glom::libglom_init();
@@ -139,7 +95,7 @@ int main()
//Make sure that the file does not exist yet:
{
const Glib::ustring uri = Glib::filename_to_uri(temp_filepath_dir);
- delete_directory(uri);
+ Glom::Utils::delete_directory(uri);
}
//Save the example as a real file:
@@ -177,7 +133,7 @@ int main()
//Make sure the directory is removed at the end,
{
const Glib::ustring uri = Glib::filename_to_uri(temp_filepath_dir);
- delete_directory(uri);
+ Glom::Utils::delete_directory(uri);
}
Glom::libglom_deinit();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]