diff --git a/gnucash/CMakeLists.txt b/gnucash/CMakeLists.txt index 8e6e339d14..0646128572 100644 --- a/gnucash/CMakeLists.txt +++ b/gnucash/CMakeLists.txt @@ -63,7 +63,7 @@ target_compile_definitions(gnucash PRIVATE -DG_LOG_DOMAIN=\"gnc.bin\") target_link_libraries (gnucash gnc-ledger-core gnc-gnome gnc-gnome-utils gnc-app-utils - gnc-engine gnc-module gnc-core-utils gnucash-guile + gnc-engine gnc-module gnc-core-utils gnc-quotes gnucash-guile gnc-qif-import gnc-csv-import gnc-csv-export gnc-log-replay gnc-bi-import gnc-customer-import gnc-report PkgConfig::GTK3 ${GUILE_LDFLAGS} ${GLIB2_LDFLAGS} @@ -98,7 +98,7 @@ target_compile_definitions(gnucash-cli PRIVATE -DG_LOG_DOMAIN=\"gnc.bin\") target_link_libraries (gnucash-cli gnc-gnome-utils gnc-app-utils - gnc-engine gnc-core-utils gnucash-guile gnc-report + gnc-engine gnc-core-utils gnc-quotes gnucash-guile gnc-report ${GUILE_LDFLAGS} ${GLIB2_LDFLAGS} ${Boost_LIBRARIES} ) diff --git a/gnucash/gnucash-cli.cpp b/gnucash/gnucash-cli.cpp index a679b5af64..c161e78c17 100644 --- a/gnucash/gnucash-cli.cpp +++ b/gnucash/gnucash-cli.cpp @@ -42,6 +42,7 @@ extern "C" { #include #endif #include +#include namespace bl = boost::locale; @@ -94,7 +95,8 @@ Gnucash::GnucashCli::configure_program_options (void) bpo::options_description quotes_options(_("Price Quotes Retrieval Options")); quotes_options.add_options() ("quotes,Q", bpo::value (&m_quotes_cmd), - _("Execute price quote related commands. Currently only one command is supported.\n\n" + _("Execute price quote related commands. The following commands are supported.\n\n" + " info: \tShow Finance::Quote version and exposed quote sources.\n" " get: \tFetch current quotes for all foreign currencies and stocks in the given GnuCash datafile.\n")) ("namespace", bpo::value (&m_namespace), _("Regular expression determining which namespace commodities will be retrieved for")); @@ -127,21 +129,45 @@ Gnucash::GnucashCli::start ([[maybe_unused]] int argc, [[maybe_unused]] char **a if (m_quotes_cmd) { - if (*m_quotes_cmd != "get") + if (*m_quotes_cmd == "info") { - std::cerr << bl::format (bl::translate("Unknown quotes command '{1}'")) % *m_quotes_cmd << "\n\n" - << *m_opt_desc_display.get(); - return 1; + auto quotes = gnc_get_quotes_instance(); + if (quotes.check()) + { + std::cout << bl::format (bl::translate ("Found Finance::Quote version {1}.")) % quotes.version() << std::endl; + std::cout << bl::translate ("Finance::Quote sources: "); + for (auto source : quotes.sources()) + std::cout << source << " "; + std::cout << std::endl; + return 0; + } + else + { + std::cerr << bl::translate ("Finance::Quote isn't " + "installed properly.") << "\n"; + std::cerr << bl::translate ("Error message:") << std::endl; + std::cerr << quotes.error_msg() << std::endl; + return 1; + } } + else if (*m_quotes_cmd == "get") + { - if (!m_file_to_load || m_file_to_load->empty()) + if (!m_file_to_load || m_file_to_load->empty()) + { + std::cerr << bl::translate("Missing data file parameter") << "\n\n" + << *m_opt_desc_display.get(); + return 1; + } + else + return Gnucash::add_quotes (m_file_to_load); + } + else { - std::cerr << bl::translate("Missing data file parameter") << "\n\n" + std::cerr << bl::format (bl::translate("Unknown quotes command '{1}'")) % *m_quotes_cmd << "\n\n" << *m_opt_desc_display.get(); return 1; } - else - return Gnucash::add_quotes (m_file_to_load); } if (m_report_cmd) diff --git a/gnucash/gnucash-commands.cpp b/gnucash/gnucash-commands.cpp index 6460987847..2edf8e6ca8 100644 --- a/gnucash/gnucash-commands.cpp +++ b/gnucash/gnucash-commands.cpp @@ -45,6 +45,7 @@ extern "C" { #include #include #include +#include namespace bl = boost::locale; @@ -78,22 +79,30 @@ scm_add_quotes(void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **ar { auto add_quotes_file = static_cast(data); - scm_c_eval_string("(debug-set! stack 200000)"); - - auto mod = scm_c_resolve_module("gnucash price-quotes"); - scm_set_current_module(mod); - gnc_prefs_init (); qof_event_suspend(); - scm_c_eval_string("(gnc:price-quotes-install-sources)"); - if (!gnc_quote_source_fq_installed()) + auto quotes = gnc_get_quotes_instance(); + if (quotes.check()) + { + std::cout << bl::format (bl::translate ("Found Finance::Quote version {1}.")) % quotes.version() << std::endl; + auto quote_sources = quotes.sources_as_glist(); + gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources); + g_list_free (quote_sources); + } + else { std::cerr << bl::translate ("No quotes retrieved. Finance::Quote isn't " "installed properly.") << "\n"; - scm_cleanup_and_exit_with_failure (nullptr); + std::cerr << bl::translate ("Error message:") << std::endl; + std::cerr << quotes.error_msg() << std::endl; } + scm_c_eval_string("(debug-set! stack 200000)"); + + auto mod = scm_c_resolve_module("gnucash price-quotes"); + scm_set_current_module(mod); + auto add_quotes = scm_c_eval_string("gnc:book-add-quotes"); auto session = gnc_get_current_session(); if (!session) diff --git a/gnucash/gnucash.cpp b/gnucash/gnucash.cpp index abd4ac160b..bcf3feb7a7 100644 --- a/gnucash/gnucash.cpp +++ b/gnucash/gnucash.cpp @@ -69,6 +69,7 @@ extern "C" { #include #include #include +#include namespace bl = boost::locale; @@ -174,9 +175,24 @@ scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char ** /* Install Price Quote Sources */ auto msg = bl::translate ("Checking Finance::Quote...").str(gnc_get_boost_locale()); + + auto quotes = gnc_get_quotes_instance(); + if (quotes.check()) + { + msg = (bl::format (bl::translate("Found Finance::Quote version {1}.")) % quotes.version()).str(gnc_get_boost_locale()); + auto quote_sources = quotes.sources_as_glist(); + gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources); + g_list_free (quote_sources); + scm_c_use_module("gnucash price-quotes"); + } + else + { + msg = bl::translate("Unable to load Finance::Quote.").str(gnc_get_boost_locale()); + PINFO ("Attempt to load Finance::Quote returned this error message:\n"); + PINFO ("%s", quotes.error_msg().c_str()); + } + gnc_update_splash_screen (msg.c_str(), GNC_SPLASH_PERCENTAGE_UNKNOWN); - scm_c_use_module("gnucash price-quotes"); - scm_c_eval_string("(gnc:price-quotes-install-sources)"); gnc_hook_run(HOOK_STARTUP, NULL); diff --git a/gnucash/price-quotes.scm b/gnucash/price-quotes.scm index 8e3ff255fb..511c629812 100644 --- a/gnucash/price-quotes.scm +++ b/gnucash/price-quotes.scm @@ -23,7 +23,6 @@ (define-module (gnucash price-quotes)) (export gnc:book-add-quotes) ;; called from gnome/dialog-price-edit-db.c -(export gnc:price-quotes-install-sources) (use-modules (gnucash engine)) (use-modules (gnucash utilities)) @@ -33,35 +32,6 @@ (use-modules (srfi srfi-11) (srfi srfi-1)) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define gnc:*finance-quote-check* - (string-append (gnc-path-get-bindir) "/gnc-fq-check")) - -(define (gnc:fq-check-sources) - (let ((program #f)) - - (define (start-program) - (set! program - (gnc-spawn-process-async - (list "perl" "-w" gnc:*finance-quote-check*) #t))) - - (define (get-sources) - (when program - (catch #t - (lambda () - (let ((results (read (fdes->inport (gnc-process-get-fd program 1))))) - (gnc:debug "gnc:fq-check-sources results: " results) - results)) - (lambda (key . args) key)))) - - (define (kill-program) - (when program - (gnc-detach-process program #t) - (set! program #f))) - - (dynamic-wind start-program get-sources kill-program))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Finance::Quote based instantaneous quotes -- used by the @@ -532,13 +502,3 @@ Run 'gnc-fq-update' as root to install them."))) (when keep-going? (book-add-prices! book (filter (negate string?) prices))))))) - -(define (gnc:price-quotes-install-sources) - (let ((sources (gnc:fq-check-sources))) - (cond - ((list? sources) - ;; Translators: ~A is the version string - (format #t (G_ "Found Finance::Quote version ~A.") (car sources)) - (newline) - (gnc:msg "Found Finance::Quote version " (car sources)) - (gnc-quote-source-set-fq-installed (car sources) (cdr sources)))))) diff --git a/libgnucash/quotes/CMakeLists.txt b/libgnucash/quotes/CMakeLists.txt index b33569d396..d855246c6b 100644 --- a/libgnucash/quotes/CMakeLists.txt +++ b/libgnucash/quotes/CMakeLists.txt @@ -1,3 +1,54 @@ +### libgnc-quotes +set (quotes_SOURCES + gnc-quotes.cpp +) + +# Add dependency on config.h +set_source_files_properties (${quotes_SOURCES} PROPERTIES OBJECT_DEPENDS ${CONFIG_H}) + +set(quotes_noinst_HEADERS + gnc-quotes.hpp +) + +add_library(gnc-quotes ${quotes_SOURCES} ${quotes_noinst_HEADERS}) + +add_dependencies(gnc-quotes gnc-vcs-info) + +target_include_directories(gnc-quotes + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${GLIB2_INCLUDE_DIRS} + PRIVATE + ${GTK_MAC_INCLUDE_DIRS} +) + +target_link_libraries(gnc-quotes + PRIVATE + gnc-core-utils + ${Boost_LIBRARIES} + ${GLIB2_LDFLAGS} + ${GOBJECT_LDFLAGS} + ${GTK_MAC_LDFLAGS} + "$<$:${OSX_EXTRA_LIBRARIES}>" +) + +target_compile_definitions(gnc-quotes + PRIVATE + G_LOG_DOMAIN=\"gnc.quotes\" + ${GTK_MAC_CFLAGS_OTHER} +) + +target_compile_options(gnc-quotes + PRIVATE + $<$:${OSX_EXTRA_COMPILE_FLAGS}> +) + +install(TARGETS gnc-quotes + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) set(_BIN_FILES "") foreach(file gnc-fq-check.in gnc-fq-helper.in gnc-fq-update.in gnc-fq-dump.in) diff --git a/libgnucash/quotes/gnc-fq-check.in b/libgnucash/quotes/gnc-fq-check.in index 6b76829dfd..8eb768458a 100755 --- a/libgnucash/quotes/gnc-fq-check.in +++ b/libgnucash/quotes/gnc-fq-check.in @@ -91,12 +91,12 @@ check_modules (); my $quoter = Finance::Quote->new(); my $prgnam = "gnc-fq-check"; +print "$Finance::Quote::VERSION\n"; my @qsources; my @sources = $quoter->sources(); foreach my $source (@sources) { - push(@qsources, "\"$source\""); + print "$source\n"; } -printf "(\"%s\" %s)\n", $Finance::Quote::VERSION, join(" ", sort(@qsources)); ## Local Variables: ## mode: perl diff --git a/libgnucash/quotes/gnc-quotes.cpp b/libgnucash/quotes/gnc-quotes.cpp new file mode 100644 index 0000000000..20abcc3629 --- /dev/null +++ b/libgnucash/quotes/gnc-quotes.cpp @@ -0,0 +1,90 @@ +/********************************************************************\ + * gnc-quotes.hpp -- proxy for Finance::Quote * + * Copyright (C) 2021 Geert Janssens * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\ *******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "gnc-quotes.hpp" + +extern "C" { + #include "gnc-path.h" +} + +namespace bp = boost::process; + +static GncQuotes quotes_cached; + +bool +GncQuotes::check (void) +{ + m_version.clear(); + m_sources.clear(); + m_error_msg.clear(); + m_cmd_result = 0; + + auto perl_executable = bp::search_path("perl"); //or get it from somewhere else. + auto fq_check = std::string(gnc_path_get_bindir()) + "/gnc-fq-check"; + + bp::ipstream out_stream; + bp::ipstream err_stream; + bp::child process (perl_executable, "-w", fq_check, bp::std_out > out_stream, bp::std_err > err_stream); + + std::string stream_line; + while (getline (out_stream, stream_line)) + if (m_version.empty()) + m_version = stream_line; + else + m_sources.push_back (stream_line); + while (getline (err_stream, stream_line)) + m_error_msg.append(stream_line + "\n"); + + process.wait(); + m_cmd_result = process.exit_code(); + + auto success = (m_cmd_result == 0); + + if (success) + std::sort (m_sources.begin(), m_sources.end()); + + return success; +} + +GList* +GncQuotes::sources_as_glist() +{ + GList* slist = nullptr; + for (auto source : m_sources) + slist = g_list_append (slist, g_strdup(source.c_str())); + return slist; +} + + + +GncQuotes& +gnc_get_quotes_instance (void) +{ + return quotes_cached; +} diff --git a/libgnucash/quotes/gnc-quotes.hpp b/libgnucash/quotes/gnc-quotes.hpp new file mode 100644 index 0000000000..86838a3c97 --- /dev/null +++ b/libgnucash/quotes/gnc-quotes.hpp @@ -0,0 +1,55 @@ +/********************************************************************\ + * gnc-quotes.hpp -- proxy for Finance::Quote * + * Copyright (C) 2021 Geert Janssens * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ +#ifndef GNC_QUOTES_HPP +#define GNC_QUOTES_HPP + +#include +#include + +extern "C" { +#include +} + +class GncQuotes +{ +public: + bool check (void); + + // Constructor - check for presence of Finance::Quote and import version and quote sources + GncQuotes() { check(); } + + // Function to check if Finance::Quote is properly installed + int cmd_result() { return m_cmd_result; } + std::string error_msg() { return m_error_msg; } + std::string version() { return m_version.empty() ? "Not Found" : m_version; } + std::vector sources() { return m_sources; } + GList* sources_as_glist (); +private: + std::string m_version; + std::vector m_sources; + int m_cmd_result; + std::string m_error_msg; +}; + +GncQuotes& gnc_get_quotes_instance (void); + +#endif /* GNC_QUOTES_HPP */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 04fcede2e8..af1caca03f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -672,6 +672,7 @@ libgnucash/engine/Transaction.c libgnucash/engine/TransLog.c libgnucash/gnc-module/example/gncmod-example.c libgnucash/gnc-module/gnc-module.c +libgnucash/quotes/gnc-quotes.cpp libgnucash/tax/de_DE/tax.scm libgnucash/tax/de_DE/txf-help.scm libgnucash/tax/de_DE/txf.scm