Look for user editable config files in gnc_userconfig_dir instead of gnc_userdata_dir

At present these are
- log.conf
- config-user.scm (previously config.user-2.0)

Implement one-time migration of these files to the proper directory if they previously exist
Look for a log.conf file in gnc_userconfig_dir instead of gnc_userdata_dir

Note this commit also uses boost::locale::translate for the first time.
We may need to fine-tune our use, but in the current state strings marked
for translation using that function are already picked up for gnucash.pot.
This commit is contained in:
Geert Janssens 2018-02-20 00:48:28 +01:00
parent beff795130
commit 61a21d12c6
6 changed files with 183 additions and 29 deletions

View File

@ -148,7 +148,6 @@ static GOptionEntry options[] =
{ NULL }
};
static gboolean userdata_migrated = FALSE;
static gchar *userdata_migration_msg = NULL;
static void
@ -387,11 +386,6 @@ load_user_config(void)
{
/* Don't continue adding to this list. When 2.0 rolls around bump
the 1.4 (unnumbered) files off the list. */
static const gchar *user_config_files[] =
{
"config-2.0.user", "config-1.8.user", "config-1.6.user",
"config.user", NULL
};
static const gchar *saved_report_files[] =
{
SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
@ -404,7 +398,14 @@ load_user_config(void)
else is_user_config_loaded = TRUE;
update_message("loading user configuration");
try_load_config_array(user_config_files);
{
gchar *config_filename;
config_filename = g_build_filename (gnc_userconfig_dir (),
"config-user.scm", (char *)NULL);
gfec_try_load(config_filename);
g_free(config_filename);
}
update_message("loading saved reports");
try_load_config_array(saved_report_files);
update_message("loading stylesheets");
@ -647,7 +648,7 @@ inner_main (void *closure, int argc, char **argv)
gnc_ui_new_user_dialog();
}
if (userdata_migrated)
if (userdata_migration_msg)
{
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
@ -657,6 +658,7 @@ inner_main (void *closure, int argc, char **argv)
gnc_destroy_splash_screen();
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy (dialog);
g_free (userdata_migration_msg);
}
/* Ensure temporary preferences are temporary */
gnc_prefs_reset_group (GNC_PREFS_GROUP_WARNINGS_TEMP);
@ -703,7 +705,8 @@ gnc_log_init()
{
gchar *log_config_filename;
log_config_filename = gnc_build_userdata_path("log.conf");
log_config_filename = g_build_filename (gnc_userconfig_dir (),
"log.conf", (char *)NULL);
if (g_file_test(log_config_filename, G_FILE_TEST_EXISTS))
qof_log_parse_log_config(log_config_filename);
g_free(log_config_filename);
@ -784,15 +787,8 @@ main(int argc, char ** argv)
/* Make sure gnucash' user data directory is properly set up
This must be done before any guile code is called as that would
fail the migration message */
userdata_migrated = gnc_filepath_init();
/* Translators: the message below will be completed with two directory names. */
userdata_migration_msg = g_strdup_printf (
_("Notice\n\nYour gnucash metadata has been migrated.\n\n"
"Old location: %s%s\n"
"New location: %s\n\n"
"If you no longer intend to run " PACKAGE_NAME " 2.6.x or older on this system you can safely remove the old directory."),
g_get_home_dir(), G_DIR_SEPARATOR_S ".gnucash", gnc_userdata_dir());
if (userdata_migrated)
userdata_migration_msg = gnc_filepath_init();
if (userdata_migration_msg)
g_print("\n\n%s\n", userdata_migration_msg);
gnc_log_init();

View File

@ -65,6 +65,10 @@ extern "C" {
}
#include <boost/filesystem.hpp>
#include <boost/locale.hpp>
#include <iostream>
#if PLATFORM(WINDOWS)
#include <codecvt>
@ -73,6 +77,8 @@ extern "C" {
namespace bfs = boost::filesystem;
namespace bst = boost::system;
namespace bl = boost::locale;
using namespace boost::locale;
/**
* Scrubs a filename by changing "strange" chars (e.g. those that are not
@ -319,6 +325,7 @@ gnc_path_find_localized_html_file (const gchar *file_name)
/* ====================================================================== */
static auto gnc_userdata_home = bfs::path();
static auto gnc_userconfig_home = bfs::path();
static auto build_dir = bfs::path();
static bool dir_is_descendant (const bfs::path& path, const bfs::path& base)
@ -580,6 +587,141 @@ get_userconfig_home(void)
return userconfig_home;
}
static std::string migrate_gnc_datahome()
{
auto success = false;
// Specify location of dictionaries
auto old_dir = bfs::path(g_get_home_dir()) / ".gnucash";
bl::generator gen;
gen.add_messages_path(gnc_path_get_datadir());
gen.add_messages_domain(PACKAGE);
// std::locale::global(gen(""));
auto migration_msg = std::stringstream ();
migration_msg.imbue(gen(""));
if (copy_recursive (old_dir,
gnc_userdata_home))
{
/* Step 1: copy directory $HOME/.gnucash to $GNC_DATA_HOME */
/* Translators: the message below will be completed with two directory names. */
migration_msg
<< translate ("Notice") << std::endl << std::endl
<< translate ("Your gnucash metadata has been migrated.") << std::endl << std::endl
<< translate ("Old location:") << " " << old_dir.string() << std::endl
<< translate ("New location:") << " " << gnc_userdata_home.string() << std::endl << std::endl
// Translators {1} will be replaced with the package name (typically Gnucash) at runtime
<< bl::format (translate ("If you no longer intend to run {1} 2.6.x or older on this system you can safely remove the old directory."))
% PACKAGE_NAME;
/* Step 2: move user editable config files from $GNC_DATA_HOME to GNC_CONFIG_HOME
These files are:
- log.conf
- the most recent of "config-2.0.user", "config-1.8.user", "config-1.6.user",
"config.user"
Note: we'll also rename config.user to config-user.scm to make it more clear what
this file is expecting custom scm code to load at run time
This is only done if not Windows or OS X, because on those platforms
gnc_userconfig_home and gnc_userdata_home are the same.*/
#if !defined G_OS_WIN32 && !defined MAC_INTEGRATION
auto failed = std::vector<std::string>{};
auto succeeded = std::vector<std::string>{};
auto oldlogpath = gnc_userdata_home / "log.conf";
auto newlogpath = gnc_userconfig_home / "log.conf";
try
{
if (bfs::exists (oldlogpath) && gnc_validate_directory (gnc_userconfig_home))
{
bfs::rename (oldlogpath, newlogpath);
succeeded.emplace_back ("log.conf");
}
}
catch (const bfs::filesystem_error& ex)
{
failed.emplace_back ("log.conf");
}
auto user_config_files = std::vector<std::string>
{
"config.user", "config-1.6.user",
"config-1.8.user", "config-2.0.user"
};
auto newconfpath = gnc_userconfig_home / "config-user.scm";
auto conf_exist_vec = std::vector<std::string> {};
auto final_rename = std::string();
for (auto conf_file : user_config_files)
{
auto oldconfpath = gnc_userdata_home / conf_file;
try
{
if (bfs::exists (oldconfpath) && gnc_validate_directory (gnc_userconfig_home))
{
bfs::rename (oldconfpath, newconfpath);
/* Translators: this string refers to a file name that gets renamed */
final_rename = conf_file + " (" + _("Renamed to:") + " config-user.scm)";
conf_exist_vec.emplace_back (conf_file);
}
}
catch (const bfs::filesystem_error& ex)
{
failed.emplace_back (conf_file);
}
}
if (!final_rename.empty())
succeeded.emplace_back (final_rename);
/* The last element in conf_exist_vec would be the same as final_rename.
* This will be reported in the succeeded vector, so don't
* report it again as removed */
if (!conf_exist_vec.empty())
conf_exist_vec.pop_back();
/* Step 3: inform the user of additional changes */
if (!succeeded.empty() || !conf_exist_vec.empty() || !failed.empty())
migration_msg << std::endl << std::endl
<< translate ("In addition:");
if (!succeeded.empty())
{
migration_msg << std::endl << std::endl
<< bl::format (translate ("The following file has been moved to {1} instead:",
"The following files have been moved to {1} instead:",
succeeded.size())) % gnc_userconfig_home.string().c_str()
<< std::endl;
for (auto success_file : succeeded)
migration_msg << "- " << success_file << std::endl;
}
if (!conf_exist_vec.empty())
{
migration_msg << std::endl << std::endl
<< translate ("The following file has been removed instead:",
"The following files have been removed instead:",
conf_exist_vec.size())
<< std::endl;
for (auto rem_file : conf_exist_vec)
migration_msg << "- " << rem_file << std::endl;
}
if (!failed.empty())
{
migration_msg << std::endl << std::endl
<< bl::format (translate ("The following file could not be moved to {1}:",
"The following files could not be moved to {1}:",
failed.size())) % gnc_userconfig_home.string().c_str()
<< std::endl;
for (auto failed_file : failed)
migration_msg << "- " << failed_file << std::endl;
}
#endif
}
return migration_msg.str ();
}
#if defined G_OS_WIN32 ||defined MAC_INTEGRATION
constexpr auto path_package = PACKAGE_NAME;
#else
@ -587,9 +729,14 @@ constexpr auto path_package = PACKAGE;
#endif
gboolean
char *
gnc_filepath_init (void)
{
// Initialize the user's config directory for gnucash
gnc_userconfig_home = get_userconfig_home() / path_package;
// Initialize the user's data directory for gnucash
auto gnc_userdata_home_exists = false;
auto have_valid_userdata_home = false;
@ -660,10 +807,11 @@ gnc_filepath_init (void)
}
}
auto migrated = FALSE;
/* Run migration code before creating the default directories
If migrating, these default directories are copied instead of created. */
auto migration_notice = std::string ();
if (!gnc_userdata_home_exists)
migrated = copy_recursive (bfs::path (g_get_home_dir()) / ".gnucash",
gnc_userdata_home);
migration_notice = migrate_gnc_datahome();
/* Try to create the standard subdirectories for gnucash' user data */
try
@ -678,7 +826,7 @@ gnc_filepath_init (void)
"(Error: %s)", ex.what());
}
return migrated;
return migration_notice.empty() ? NULL : g_strdup (migration_notice.c_str());
}
/** @fn const gchar * gnc_userdata_dir ()
@ -744,8 +892,10 @@ gnc_userdata_dir (void)
const gchar *
gnc_userconfig_dir (void)
{
auto config_path = get_userconfig_home() / path_package;
return g_strdup(config_path.string().c_str());
if (gnc_userdata_home.empty())
gnc_filepath_init();
return gnc_userconfig_home.string().c_str();
}
static const bfs::path&

View File

@ -91,9 +91,9 @@ gchar *gnc_path_find_localized_html_file (const gchar *file_name);
* function will also try to copy files from $HOME/.gnucash
* to there if that old location exists.
*
* @return whether files got copied from the old location.
* @return a migration message when files got copied from the old location, NULL otherwise
*/
gboolean gnc_filepath_init (void);
char * gnc_filepath_init (void);
const gchar *gnc_userdata_dir (void);
gchar *gnc_build_userdata_path (const gchar *filename);

View File

@ -155,6 +155,8 @@ IF(BUILDING_FROM_VCS)
find_program(INTLTOOL_EXTRACT NAMES intltool-extract)
find_program(XGETTEXT xgettext)
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/Makevars
${CMAKE_CURRENT_BINARY_DIR}/Makevars COPYONLY)
IF (${INTLTOOL_EXTRACT} STREQUAL "INTLTOOL_EXTRACT-NOTFOUND")
MESSAGE(FATAL_ERROR "Can't find the 'intltool-extract' program.")

View File

@ -8,7 +8,13 @@ subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=Q_
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=Q_ \
--keyword=translate:1,1t --keyword=translate:1c,2,2t \
--keyword=translate:1,2,3t --keyword=translate:1c,2,3,4t
# The two lines below are also for boost::locale. I haven't added them (yet) as
# we should first investigate whether they interfere with plain C gettext keywords
# --keyword=gettext:1 --keyword=pgettext:1c,2 \
# --keyword=ngettext:1,2 --keyword=npgettext:1c,2,3 \
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding

View File

@ -7,7 +7,7 @@ set(ENV{INTLTOOL_EXTRACT} ${INTLTOOL_EXTRACT})
set(ENV{XGETTEXT} ${XGETTEXT})
set(ENV{srcdir} ${PO_SRC_DIR})
execute_process(
COMMAND ${PERL} ${INTLTOOL_UPDATE} --gettext-package ${PACKAGE} --pot
COMMAND ${PERL} ${INTLTOOL_UPDATE} -x --gettext-package ${PACKAGE} --pot
WORKING_DIRECTORY ${PO_BIN_DIR}
RESULT_VARIABLE GNUCASH_POT_RESULT
)