Initial version of libgnc-quotes

This library intends to wrap Finance::Quote the way price-quotes.scm currently does.
In this first commit the library replaces price-quotes.scm's library to install
quote sources. In addition it exposes a new command line parameter  in gnucash-cli
to show which version of Finance::Quote is installed on the system (if any) and
which quotes sources that verions exposes.
This commit is contained in:
Geert Janssens 2021-01-28 17:34:19 +01:00 committed by John Ralls
parent b0ae402c23
commit 2f7ed7f25d
10 changed files with 276 additions and 68 deletions

View File

@ -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}
)

View File

@ -42,6 +42,7 @@ extern "C" {
#include <boost/nowide/args.hpp>
#endif
#include <iostream>
#include <gnc-quotes.hpp>
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")
{
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())
{
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::format (bl::translate("Unknown quotes command '{1}'")) % *m_quotes_cmd << "\n\n"
<< *m_opt_desc_display.get();
return 1;
}
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);
}
if (m_report_cmd)

View File

@ -45,6 +45,7 @@ extern "C" {
#include <fstream>
#include <iostream>
#include <gnc-report.h>
#include <gnc-quotes.hpp>
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<const std::string*>(data);
gnc_prefs_init ();
qof_event_suspend();
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";
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);
gnc_prefs_init ();
qof_event_suspend();
scm_c_eval_string("(gnc:price-quotes-install-sources)");
if (!gnc_quote_source_fq_installed())
{
std::cerr << bl::translate ("No quotes retrieved. Finance::Quote isn't "
"installed properly.") << "\n";
scm_cleanup_and_exit_with_failure (nullptr);
}
auto add_quotes = scm_c_eval_string("gnc:book-add-quotes");
auto session = gnc_get_current_session();
if (!session)

View File

@ -69,6 +69,7 @@ extern "C" {
#include <iostream>
#include <gnc-report.h>
#include <gnc-locale-utils.hpp>
#include <gnc-quotes.hpp>
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);

View File

@ -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))))))

View File

@ -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}
"$<$<BOOL:${MAC_INTEGRATION}>:${OSX_EXTRA_LIBRARIES}>"
)
target_compile_definitions(gnc-quotes
PRIVATE
G_LOG_DOMAIN=\"gnc.quotes\"
${GTK_MAC_CFLAGS_OTHER}
)
target_compile_options(gnc-quotes
PRIVATE
$<$<BOOL:${MAC_INTEGRATION}>:${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)

View File

@ -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

View File

@ -0,0 +1,90 @@
/********************************************************************\
* gnc-quotes.hpp -- proxy for Finance::Quote *
* Copyright (C) 2021 Geert Janssens <geert@kobaltwit.be> *
* *
* 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 <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
#include <glib.h>
#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;
}

View File

@ -0,0 +1,55 @@
/********************************************************************\
* gnc-quotes.hpp -- proxy for Finance::Quote *
* Copyright (C) 2021 Geert Janssens <geert@kobaltwit.be> *
* *
* 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 <string>
#include <vector>
extern "C" {
#include <glib.h>
}
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 <std::string> sources() { return m_sources; }
GList* sources_as_glist ();
private:
std::string m_version;
std::vector <std::string> m_sources;
int m_cmd_result;
std::string m_error_msg;
};
GncQuotes& gnc_get_quotes_instance (void);
#endif /* GNC_QUOTES_HPP */

View File

@ -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