[glom] Backup: Simplify the code and fix the problem with groups.



commit 93f8e43e4874fb17f5554627cd349cb6c33898d5
Author: Murray Cumming <murrayc murrayc com>
Date:   Tue Jan 28 10:56:44 2014 +0100

    Backup: Simplify the code and fix the problem with groups.
    
    * glom/libglom/connectionpool.[h|cc]: convert_backup():
      Take a path to the (postgres-specific) backup data file instead
      of a path to the parent directory, so we do not need to
      guess the actual path.
    * glom/libglom/connectionpool_backends/backend.h
    * glom/libglom/connectionpool_backends/mysql.[h|cc]:
    * glom/libglom/connectionpool_backends/postgres.[h|cc]:
    * glom/libglom/connectionpool_backends/sqlite.[h|cc]: convert_backup():
      Rename path_backup to backup_data_file_path to make it clearer.
    
    * glom/libglom/document/document.[h|cc]: extract_backup_file():
      Take a path to the (postgres-specific) backup data file,
    
    * glom/appwindow.[h|cc]:
      do_restore_backup(): Store the path to the backup data file in
      m_backup_data_filepath temporarily.
      on_document_load(): Pass m_backup_data_filepath to
      recreate_database_from_example().
      recreate_database_from_example(): Take a path to the backup data
      instead of a URI to the .glom file, and pass that path to
      ConnectionPool::convert_backup().
      Also add groups before restoring the backup data, because it needs
      these groups to exist already.
    * glom/libglom/db_utils.cc: add_group(): Do not fail if the
      autoincrements table does not exist yet, because this can happen
      while restoring data from a backup.
    
    * tests/test_selfhosting_new_then_backup_restore.cc: Adapted.

 glom/appwindow.cc                                 |   72 +++++---------
 glom/appwindow.h                                  |    5 +-
 glom/libglom/connectionpool.cc                    |   12 +--
 glom/libglom/connectionpool.h                     |    4 +-
 glom/libglom/connectionpool_backends/backend.h    |    2 +-
 glom/libglom/connectionpool_backends/mysql.cc     |    7 +-
 glom/libglom/connectionpool_backends/mysql.h      |    2 +-
 glom/libglom/connectionpool_backends/postgres.cc  |   11 +-
 glom/libglom/connectionpool_backends/postgres.h   |    3 +-
 glom/libglom/connectionpool_backends/sqlite.cc    |    2 +-
 glom/libglom/connectionpool_backends/sqlite.h     |    2 +-
 glom/libglom/db_utils.cc                          |    5 +
 glom/libglom/document/document.cc                 |  103 ++++++++++++++-------
 glom/libglom/document/document.h                  |    7 +-
 tests/test_selfhosting_new_then_backup_restore.cc |    8 +-
 15 files changed, 132 insertions(+), 113 deletions(-)
---
diff --git a/glom/appwindow.cc b/glom/appwindow.cc
index 7c2129d..de150ed 100644
--- a/glom/appwindow.cc
+++ b/glom/appwindow.cc
@@ -893,6 +893,9 @@ bool AppWindow::on_document_load()
     const bool is_example = pDocument->get_is_example_file();
     const bool is_backup = pDocument->get_is_backup_file();
 #endif // !GLOM_ENABLE_CLIENT_ONLY
+
+    //Note that the URI will be empty if we are loading from data,
+    //such as when loading a backup.
     const std::string original_uri = pDocument->get_file_uri();
 
     if(is_example || is_backup)
@@ -1070,7 +1073,10 @@ bool AppWindow::on_document_load()
         if(is_example)
           test = recreate_database_from_example(user_cancelled);
         else
-          test = recreate_database_from_backup(original_uri, user_cancelled);
+        {
+          test = recreate_database_from_backup(m_backup_data_filepath, user_cancelled);
+          m_backup_data_filepath.clear();
+        }
 
         if(!test)
         {
@@ -1668,8 +1674,14 @@ bool AppWindow::recreate_database_from_example(bool& user_cancelled)
 }
 
 //TODO: Remove duplication with recreate_database_from_example().
-bool AppWindow::recreate_database_from_backup(const Glib::ustring& backup_uri, bool& user_cancelled)
+bool AppWindow::recreate_database_from_backup(const std::string& backup_data_file_path, bool& user_cancelled)
 {
+  if(backup_data_file_path.empty())
+  {
+    std::cerr << G_STRFUNC << ": backup_data_file_path is empty." << std::endl;
+    return false;
+  }
+
   ShowProgressMessage progress_message(_("Creating Glom database from backup file."));
 
   //Create a database, based on the information in the current document:
@@ -1777,42 +1789,17 @@ bool AppWindow::recreate_database_from_backup(const Glib::ustring& backup_uri, b
 
   //m_pFrame->add_standard_tables(); //Add internal, hidden, tables.
 
-  //Restore the backup into the database:
-  std::string original_dir_path;
-
-  Glib::RefPtr<Gio::File> gio_file = Gio::File::create_for_uri(backup_uri);
-  if(gio_file)
-  {
-    Glib::RefPtr<Gio::File> parent = gio_file->get_parent();
-    if(parent)
-    {
-      try
-      {
-        original_dir_path = Glib::filename_from_uri(parent->get_uri());
-      }
-      catch(const Glib::Error& ex)
-      {
-        std::cerr << G_STRFUNC << ": Glib::filename_from_uri() failed: " << ex.what() << std::endl;
-      }
-    }
-  }
-
-  std::cout << G_STRFUNC << ": debug 6" << std::endl;
-
-  if(original_dir_path.empty())
-  {
-    std::cerr << G_STRFUNC << ": original_dir_path is empty." << std::endl;
+  //Add any extra groups from the example file.
+  //The backup file refers to these,
+  //so the restore will fail if they are not present.
+  pulse_progress_message();
+  test = DbUtils::add_groups_from_document(pDocument);
+  if(!test)
     return false;
-  }
-
-  std::cout << G_STRFUNC << ": debug b1" << std::endl;
 
-  //Restore the database from the backup:
-  //std::cout << "DEBUG: original_dir_path=" << original_dir_path << std::endl;
+  //Restore the backup into the database:
   const bool restored = connection_pool->convert_backup(
-    sigc::mem_fun(*this, &AppWindow::on_connection_convert_backup_progress), original_dir_path);
-
-  std::cout << G_STRFUNC << ": debug b2: result=" << restored << std::endl;
+    sigc::mem_fun(*this, &AppWindow::on_connection_convert_backup_progress), backup_data_file_path);
 
   if(!restored)
   {
@@ -1820,13 +1807,6 @@ bool AppWindow::recreate_database_from_backup(const Glib::ustring& backup_uri, b
     return false;
   }
 
-  //TODO: Is this necessary?
-  //Add any extra groups from the example file:
-  pulse_progress_message();
-  test = DbUtils::add_groups_from_document(pDocument);
-  if(!test)
-    return false;
-
   return true; //Restore successfully.
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
@@ -2500,17 +2480,17 @@ bool AppWindow::do_restore_backup(const Glib::ustring& backup_uri)
     return false;
     
   ShowProgressMessage progress_message(_("Restoring backup"));
-  const Glib::ustring backup_file_contents = Glom::Document::extract_backup_file(
-    backup_uri,
+  const Glib::ustring backup_glom_file_contents = Glom::Document::extract_backup_file(
+    backup_uri, m_backup_data_filepath,
     sigc::mem_fun(*this, &AppWindow::on_connection_convert_backup_progress));
 
-  if(backup_file_contents.empty())
+  if(backup_glom_file_contents.empty() || m_backup_data_filepath.empty())
   {
     ui_warning(_("Restore Backup failed."), _("There was an error while extracting the backup."));
     return false;
   }
 
-  return open_document_from_data((const guchar*)backup_file_contents.c_str(), backup_file_contents.bytes());
+  return open_document_from_data((const guchar*)backup_glom_file_contents.c_str(), 
backup_glom_file_contents.bytes());
 }
 
 void AppWindow::on_menu_developer_enable_layout_drag_and_drop()
diff --git a/glom/appwindow.h b/glom/appwindow.h
index 9fb5302..c7baa5d 100644
--- a/glom/appwindow.h
+++ b/glom/appwindow.h
@@ -260,7 +260,7 @@ private:
   Document* on_connection_pool_get_document();
 
   bool recreate_database_from_example(bool& user_cancelled); //return indicates success.
-  bool recreate_database_from_backup(const Glib::ustring& backup_uri, bool& user_cancelled); //return 
indicates success.
+  bool recreate_database_from_backup(const std::string& backup_data_file_path, bool& user_cancelled); 
//return indicates success.
   void on_recreate_database_progress();
 
   void stop_self_hosting_of_document_database();
@@ -349,6 +349,9 @@ private:
   //so we can use them again when connecting directly to the database:
   Glib::ustring m_temp_username, m_temp_password;
 
+  //This is set temporarily while restoring a backup.
+  std::string m_backup_data_filepath;
+
   bool m_show_sql_debug;
 
   static Glib::ustring m_current_locale, m_original_locale;
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index 9572c9e..8907f5d 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -455,19 +455,11 @@ bool ConnectionPool::save_backup(const SlotProgress& slot_progress, const std::s
   return result;
 }
 
-bool ConnectionPool::convert_backup(const SlotProgress& slot_progress, const std::string& path_dir)
+bool ConnectionPool::convert_backup(const SlotProgress& slot_progress, const std::string& 
backup_data_file_path)
 {
   g_assert(m_backend.get());
 
-  //TODO_MySQL:
-  //TODO: Avoid this copy/paste of the directory name:
-  std::string path_dir_to_use = path_dir;
-  if(!path_dir_to_use.empty())
-  {
-    path_dir_to_use = Glib::build_filename(path_dir, "glom_postgres_data");
-  }
-
-  const bool result = m_backend->convert_backup(slot_progress, path_dir_to_use, m_user, m_password, 
m_database);
+  const bool result = m_backend->convert_backup(slot_progress, backup_data_file_path, m_user, m_password, 
m_database);
   if(!result)
     return false;
 
diff --git a/glom/libglom/connectionpool.h b/glom/libglom/connectionpool.h
index b485a78..accd749 100644
--- a/glom/libglom/connectionpool.h
+++ b/glom/libglom/connectionpool.h
@@ -179,10 +179,10 @@ public:
   /** Use a backup of the database in a tarball to create tables and data in an existing empty database.
    * The database (server) should already have the necessary groups and users.
    *
-   * @param path_dir The top-level directory for the backup file, using the normal directory structure.
+   * @param path_dir The path to the database-server-specific backup file.
    * See save_backup().
    */
-  bool convert_backup(const SlotProgress& slot_progress, const std::string& path_dir);
+  bool convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path);
 
   void set_user(const Glib::ustring& value);
   void set_password(const Glib::ustring& value);
diff --git a/glom/libglom/connectionpool_backends/backend.h b/glom/libglom/connectionpool_backends/backend.h
index 7e23686..08e8ffa 100644
--- a/glom/libglom/connectionpool_backends/backend.h
+++ b/glom/libglom/connectionpool_backends/backend.h
@@ -195,7 +195,7 @@ protected:
    * The database (server) should already have the necessary groups and users.
    * See save_backup().
    */
-  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& base_directory_uri, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name) = 0;
+  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name) = 0;
 
 protected:
   std::string m_database_directory_uri;
diff --git a/glom/libglom/connectionpool_backends/mysql.cc b/glom/libglom/connectionpool_backends/mysql.cc
index e05d6be..87571c6 100644
--- a/glom/libglom/connectionpool_backends/mysql.cc
+++ b/glom/libglom/connectionpool_backends/mysql.cc
@@ -595,7 +595,7 @@ bool MySQL::save_backup(const SlotProgress& slot_progress, const Glib::ustring&
   return result;
 }
 
-bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const 
Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& /* database_name */)
+bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& /* database_name */)
 {
 /* TODO:
   if(m_network_shared && !running)
@@ -631,10 +631,9 @@ bool MySQL::convert_backup(const SlotProgress& slot_progress, const std::string&
   }
 
   //Make sure the path exists:
-  const std::string path_backup = get_self_hosting_backup_path(base_directory);
-  if(path_backup.empty() || !file_exists_filepath(path_backup))
+  if(backup_data_file_path.empty() || !file_exists_filepath(backup_data_file_path))
   {
-    std::cerr << G_STRFUNC << ": Backup file not found: " << path_backup << std::endl;
+    std::cerr << G_STRFUNC << ": Backup file not found: " << backup_data_file_path << std::endl;
     return false;
   }
 
diff --git a/glom/libglom/connectionpool_backends/mysql.h b/glom/libglom/connectionpool_backends/mysql.h
index 218cccc..59a7f82 100644
--- a/glom/libglom/connectionpool_backends/mysql.h
+++ b/glom/libglom/connectionpool_backends/mysql.h
@@ -49,7 +49,7 @@ public:
    */
   virtual bool save_backup(const SlotProgress& slot_progress, const Glib::ustring& username, const 
Glib::ustring& password, const Glib::ustring& database_name);
 
-  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const 
Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
+  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
 
   /** Return the quoted path to the specified PostgreSQL utility.
    */
diff --git a/glom/libglom/connectionpool_backends/postgres.cc 
b/glom/libglom/connectionpool_backends/postgres.cc
index 98f0770..04fe6c2 100644
--- a/glom/libglom/connectionpool_backends/postgres.cc
+++ b/glom/libglom/connectionpool_backends/postgres.cc
@@ -660,7 +660,7 @@ bool Postgres::save_backup(const SlotProgress& slot_progress, const Glib::ustrin
   return result;
 }
 
-bool Postgres::convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const 
Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name)
+bool Postgres::convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name)
 {
 /* TODO:
   if(m_network_shared && !running)
@@ -696,10 +696,9 @@ bool Postgres::convert_backup(const SlotProgress& slot_progress, const std::stri
   }
 
   //Make sure the path exists:
-  const std::string path_backup = get_self_hosting_backup_path(base_directory);
-  if(path_backup.empty() || !file_exists_filepath(path_backup))
+  if(backup_data_file_path.empty() || !file_exists_filepath(backup_data_file_path))
   {
-    std::cerr << G_STRFUNC << ": Backup file not found: " << path_backup << std::endl;
+    std::cerr << G_STRFUNC << ": Backup file not found: " << backup_data_file_path << std::endl;
     return false;
   }
 
@@ -720,9 +719,9 @@ bool Postgres::convert_backup(const SlotProgress& slot_progress, const std::stri
     " --host=" + Glib::shell_quote(m_host) +
     " --port=" + port_as_string(m_port) +
     " --username=" + Glib::shell_quote(username) +
-    " " + path_backup;
+    " " + backup_data_file_path;
 
-  std::cout << "DEBUG: command_restore=" << command_restore << std::endl;
+  std::cout << G_STRFUNC << "DEBUG: command_restore=" << command_restore << std::endl;
 
   //TODO: Put the password in .pgpass
 
diff --git a/glom/libglom/connectionpool_backends/postgres.h b/glom/libglom/connectionpool_backends/postgres.h
index d558612..8c84153 100644
--- a/glom/libglom/connectionpool_backends/postgres.h
+++ b/glom/libglom/connectionpool_backends/postgres.h
@@ -49,7 +49,7 @@ public:
    */
   virtual bool save_backup(const SlotProgress& slot_progress, const Glib::ustring& username, const 
Glib::ustring& password, const Glib::ustring& database_name);
 
-  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const 
Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
+  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
 
   /** Return the quoted path to the specified PostgreSQL utility.
    */
@@ -82,6 +82,7 @@ protected:
    */
   std::string get_self_hosting_data_path(bool create = false);
 
+  //TODO: Remove this?
   /** Get the path to the backup file, regardless of whether it exists.
    * @param base_directory Where to find the backup file, under a normal Glom directory structure.
    * If @a base_directory is empty then it uses get_database_directory_uri().
diff --git a/glom/libglom/connectionpool_backends/sqlite.cc b/glom/libglom/connectionpool_backends/sqlite.cc
index 272862b..86371e6 100644
--- a/glom/libglom/connectionpool_backends/sqlite.cc
+++ b/glom/libglom/connectionpool_backends/sqlite.cc
@@ -412,7 +412,7 @@ bool Sqlite::save_backup(const SlotProgress& /* slot_progress */, const Glib::us
   return false;
 }
 
-bool Sqlite::convert_backup(const SlotProgress& /* slot_progress */, const std::string& /* base_directory 
*/, const Glib::ustring& /* username */, const Glib::ustring& /* password */, const Glib::ustring& /* 
database_name */)
+bool Sqlite::convert_backup(const SlotProgress& /* slot_progress */, const std::string& /* 
backup_data_file_path */, const Glib::ustring& /* username */, const Glib::ustring& /* password */, const 
Glib::ustring& /* database_name */)
 {
   //TODO:
   std::cerr << G_STRFUNC << ": Not implemented.";
diff --git a/glom/libglom/connectionpool_backends/sqlite.h b/glom/libglom/connectionpool_backends/sqlite.h
index 6726743..b85de41 100644
--- a/glom/libglom/connectionpool_backends/sqlite.h
+++ b/glom/libglom/connectionpool_backends/sqlite.h
@@ -62,7 +62,7 @@ private:
   virtual bool create_database(const SlotProgress& slot_progress, const Glib::ustring& database_name, const 
Glib::ustring& username, const Glib::ustring& password);
 
   virtual bool save_backup(const SlotProgress& slot_progress, const Glib::ustring& username, const 
Glib::ustring& password, const Glib::ustring& database_name);
-  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& base_directory, const 
Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
+  virtual bool convert_backup(const SlotProgress& slot_progress, const std::string& backup_data_file_path, 
const Glib::ustring& username, const Glib::ustring& password, const Glib::ustring& database_name);
 };
 
 } //namespace ConnectionPoolBackends
diff --git a/glom/libglom/db_utils.cc b/glom/libglom/db_utils.cc
index 66b7847..6ce47d9 100644
--- a/glom/libglom/db_utils.cc
+++ b/glom/libglom/db_utils.cc
@@ -2202,6 +2202,10 @@ bool add_group(const Document* document, const Glib::ustring& group, bool superu
   }
 
   //Let them edit the autoincrements too:
+  //Do not fail if the autoincrements table does not yet exist, because this can happen during restoring of 
a backup.
+  if(std::find(table_list.begin(), table_list.end(), GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME) == 
table_list.end())
+    return true;
+    
   if(!Privs::set_table_privileges(group, GLOM_STANDARD_TABLE_AUTOINCREMENTS_TABLE_NAME, priv))
   {
     std::cerr << G_STRFUNC << "Privs::set_table_privileges() failed." << std::endl;
@@ -2211,6 +2215,7 @@ bool add_group(const Document* document, const Glib::ustring& group, bool superu
   return true;
 }
 
+
 bool remove_user(const Glib::ustring& user)
 {
   if(user.empty())
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 6a6dc72..1cb6dcd 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -37,6 +37,7 @@
 #include <libglom/translations_po.h>
 #include <giomm/file.h>
 #include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
 #include <glibmm/convert.h>
 
 #include <libglom/connectionpool.h>
@@ -5064,8 +5065,44 @@ Glib::ustring Document::save_backup_file(const Glib::ustring& uri, const SlotPro
   return Glib::filename_to_uri(tarball_path);
 }
 
-Glib::ustring Document::extract_backup_file(const Glib::ustring& backup_uri, const SlotProgress& 
slot_progress)
+namespace { //anonymous namespace
+
+void read_archive_entry_file_contents(archive* a, archive_entry* entry, std::string& file_contents)
+{
+  file_contents.clear();
+
+  const size_t size = archive_entry_size(entry);
+  const Glib::ScopedPtr<char> buf ((char*) g_malloc(size + 1));
+
+  const ssize_t r = archive_read_data(a, buf.get(), size);
+    
+  if((r == ARCHIVE_FATAL) || (r == ARCHIVE_WARN) ||
+    (r == ARCHIVE_RETRY)) //0 or a number of bytes read are the signs of success.
+  {
+      std::cerr << G_STRFUNC << ": Error while reading data from archive entry. r=" << r << std::endl;
+      handle_archive_error(a);
+      return;
+  }
+
+  try
+  {
+    //For std::string, size is number of characters. For ustring it would be number of characters.
+    file_contents += std::string(buf.get(), r);
+  }
+  catch(const std::exception& ex)
+  {
+    std::cerr << G_STRFUNC << ": std::exception error while concatenating archive data: "
+      << ex.what() << std::endl;
+    return;
+  }
+}
+
+} //anonymous namespaces
+
+Glib::ustring Document::extract_backup_file(const Glib::ustring& backup_uri, std::string& backup_path, const 
SlotProgress& slot_progress)
 {
+  backup_path.clear();
+
   // We cannot use an uri here, because we cannot untar remote files.
   const std::string filename_tarball = Glib::filename_from_uri(backup_uri);
 
@@ -5096,15 +5133,7 @@ Glib::ustring Document::extract_backup_file(const Glib::ustring& backup_uri, con
 
   slot_progress();
 
-  //We expect just one file:
-  struct archive_entry* entry = 0;
-  if(archive_read_next_header(a, &entry) != ARCHIVE_OK)
-  {
-    std::cerr << G_STRFUNC << ": Could not read next archive entry." << std::endl;
-    handle_archive_error(a);
-    return Glib::ustring();
-  }
-  
+
   //const char *name = archive_entry_pathname(entry);
   //std::cout << "debug: name=" << name << std::endl;
 
@@ -5115,37 +5144,43 @@ Glib::ustring Document::extract_backup_file(const Glib::ustring& backup_uri, con
   //Read the whole file in one go,
   //We'd have to keep it all in memory anyway as we concatentated it,
   //if we did it in chunks.
-  //TODO: Backup files will, of course, often have large amounts of (example) data.
-  //So we should, elsewhere, make it possible to load that data progressively,
-  //maybe discarding it during a first read, and adapt this code to that new API.
   slot_progress();
 
-  const size_t size = archive_entry_size(entry);
-  const Glib::ScopedPtr<char> buf ((char*) g_malloc(size + 1));
 
-  const ssize_t r = archive_read_data(a, buf.get(), size);
-    
-  if((r == ARCHIVE_FATAL) || (r == ARCHIVE_WARN) ||
-    (r == ARCHIVE_RETRY)) //0 or a number of bytes read are the signs of success.
-  {
-      std::cerr << G_STRFUNC << ": Error while reading data from archive entry. r=" << r << std::endl;
-      handle_archive_error(a);
-      return Glib::ustring();
-  }
 
-  try
-  {
-    //For std::string, size is number of characters. For ustring it would be number of characters.
-    contents += std::string(buf.get(), r);
-  }
-  catch(const std::exception& ex)
+  std::string contents_glom_file;
+
+  struct archive_entry* entry = 0;
+  while(archive_read_next_header(a, &entry) == ARCHIVE_OK)
   {
-    std::cerr << G_STRFUNC << ": std::exception error while concatenating archive data: "
-      << ex.what() << std::endl;
-    return Glib::ustring();
+    const char* pathname = archive_entry_pathname(entry);
+    if(!pathname)
+      continue;
+
+    const std::string basename = Glib::path_get_basename(pathname);
+    //std::cout << G_STRFUNC << ": debug: basename=" << basename << std::endl;
+
+    bool is_glom_file = false;
+    const std::string without_suffix = Glom::Utils::string_remove_suffix(basename, ".glom");
+    if(without_suffix != basename)
+      is_glom_file = true;
+
+    if(is_glom_file)
+    {
+      read_archive_entry_file_contents(a, entry, contents_glom_file);
+    }
+    else if(basename == "backup")
+    {
+      std::string contents_backup_file;
+      read_archive_entry_file_contents(a, entry, contents_backup_file);
+
+      backup_path = Utils::get_temp_file_path("glom_backup");
+      Glib::file_set_contents(backup_path, contents_backup_file);
+      //std::cout << "debug: backup data path: " << backup_path << std::endl;
+    }
   }
 
-  return contents;
+  return contents_glom_file;
 }
 
 
diff --git a/glom/libglom/document/document.h b/glom/libglom/document/document.h
index daacd57..3522ea9 100644
--- a/glom/libglom/document/document.h
+++ b/glom/libglom/document/document.h
@@ -464,11 +464,14 @@ public:
    */
   Glib::ustring save_backup_file(const Glib::ustring& uri, const SlotProgress& slot_progress);
   
-  /**
+  /** Extract the .glom file and backup data from a .tar.gz archive.
+   * The backup data must be stored temporarily on disk because pg_restore requires a file on disk.
+   *
    * @param backup_uri: The URI of a .tar.gz backup file.
+   * @param backup_path This will be set to the path of a temporary file for use with pg_restore.
    * @result The contents of the .glom file from the .tar.gz file.
    */
-  static Glib::ustring extract_backup_file(const Glib::ustring& backup_uri, const SlotProgress& 
slot_progress);
+  static Glib::ustring extract_backup_file(const Glib::ustring& backup_uri, std::string& backup_path, const 
SlotProgress& slot_progress);
   
 
 protected:
diff --git a/tests/test_selfhosting_new_then_backup_restore.cc 
b/tests/test_selfhosting_new_then_backup_restore.cc
index 0a21756..8a22c33 100644
--- a/tests/test_selfhosting_new_then_backup_restore.cc
+++ b/tests/test_selfhosting_new_then_backup_restore.cc
@@ -62,11 +62,13 @@ static bool test(Glom::Document::HostingMode hosting_mode)
   
   //Create a new document from the backup:
   {
-    const Glib::ustring backup_file_contents = 
+    std::string backup_data_file_path;
+    const Glib::ustring backup_glom_file_contents = 
       Glom::Document::extract_backup_file(
         backup_uri_tarball,
+        backup_data_file_path,
         sigc::ptr_fun(&on_backup_progress));
-    if(backup_file_contents.empty())
+    if(backup_glom_file_contents.empty())
     {
       std::cerr << G_STRFUNC << ": Extraction from the backup file failed." << std::endl;
       return false;
@@ -76,7 +78,7 @@ static bool test(Glom::Document::HostingMode hosting_mode)
     //std::cout << "debug: recreated_uri=" << recreated_uri << std::endl;
     Glom::Document document;
     const bool recreated = 
-      test_create_and_selfhost_from_data(backup_file_contents, document, hosting_mode);
+      test_create_and_selfhost_from_data(backup_glom_file_contents, document, hosting_mode);
     if(!recreated)
     {
       std::cerr << G_STRFUNC << ": Recreation from the backup failed." << std::endl;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]