From 0d9da52dc5c05524be8c5adf84dd0c3f76a9a2d3 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 20 May 2019 22:57:09 +0200 Subject: readme --- README | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..9bdc8fa --- /dev/null +++ b/README @@ -0,0 +1,63 @@ +Installation instructions +------------------------- + +First, initialize the configure script. + +$ ./bootstrap + +Then, choose the installation prefix + +$ ./configure --prefix= + +Last, install + +$ make install + +Optionally, to run tests: + +$ make check + +Configuration options. +---------------------- + +The following configuration excerpt shows all the options +accepted by the donations shop. + +$ cat ~/.config/taler.conf + +[frontends] + +# Merchant backend to use. +backend = http://backend.test.taler.net/ + +# This value will fill: "Authorization: ApiKey " +backend_apikey = sandbox + +[donations] + +# The following three options configure the way the blog +# will serve UWSGI requests via unix domain sockets. +uwsgi_serve = unix +uwsgi_unixpath = /path/to/blog.uwsgi +uwsgi_unixpath_mode = 660 + +# The following option picks the merchant instance that +# will be represented by the running blog. +instance = default + +Running instructions +-------------------- + +The following command launches the blog to serve HTTP requests +on the port . + +$ taler-merchant-donations serve-http -p + +The following command launches the blog to serve UWSGI requests +via a unix domain socket. + +$ taler-merchant-donations serve-uwsgi + +Finally, get a help message with the following command + +$ taler-merchant-donations --help -- cgit v1.2.3 From 27e5a47358437bc6e1894be0ddc9689761a39bcd Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Tue, 21 May 2019 00:19:23 +0200 Subject: readme --- README | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README b/README index 9bdc8fa..586a9e7 100644 --- a/README +++ b/README @@ -35,26 +35,26 @@ backend_apikey = sandbox [donations] -# The following three options configure the way the blog -# will serve UWSGI requests via unix domain sockets. +# The following three options configure the way the donations +# shop will serve UWSGI requests via unix domain sockets. uwsgi_serve = unix -uwsgi_unixpath = /path/to/blog.uwsgi +uwsgi_unixpath = /path/to/donations.uwsgi uwsgi_unixpath_mode = 660 # The following option picks the merchant instance that -# will be represented by the running blog. +# will be represented by the running donations shop. instance = default Running instructions -------------------- -The following command launches the blog to serve HTTP requests -on the port . +The following command launches the donations shop +to serve HTTP requests on the port . $ taler-merchant-donations serve-http -p -The following command launches the blog to serve UWSGI requests -via a unix domain socket. +The following command launches the donations shop +to serve UWSGI requests via a unix domain socket. $ taler-merchant-donations serve-uwsgi -- cgit v1.2.3 From 62b549f47e86634b8ee822268770ee553e8455a3 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Fri, 24 May 2019 17:23:58 +0200 Subject: provide default config --- Makefile.in | 1 + donations.conf | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index 5cb170b..c19386a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,6 +25,7 @@ $(script_templates): %: Makefile %.in .PHONY: install-data install-data: $(templates) @$(INSTALL_DATA) -Dt $(prefix)/share/taler/ frontend-donations.wsgi + @$(INSTALL_DATA) -Dt $(prefix)/share/taler/config.d/ donations.conf # @test -n "$$(ls -A talerbank/app/static/web-common/)" || \ # (echo "please check out git submodules"; exit 1) diff --git a/donations.conf b/donations.conf index e0492dc..7404b3c 100644 --- a/donations.conf +++ b/donations.conf @@ -2,11 +2,21 @@ currency = TESTKUDOS [frontends] -BACKEND = http://backend.test.taler.net/ + +# Merchant backend to use. +backend = http://backend.test.taler.net/ + +# This value will fill: "Authorization: ApiKey " +backend_apikey = sandbox [donations] -UWSGI_UNIXPATH_MODE = 660 + +# The following three options configure the way the donations +# shop will serve UWSGI requests via unix domain sockets. +uwsgi_serve = unix +uwsgi_unixpath = /path/to/donations.uwsgi +uwsgi_unixpath_mode = 660 + +# The following option picks the merchant instance that +# will be represented by the running donations shop. instance = default -UWSGI_SERVE = unix -UWSGI_UNIXPATH = $HOME/sockets/donations.uwsgi -UWSGI_UNIXMODE = 666 -- cgit v1.2.3 From f7829956ff2ee4b517f010a3f23bc62012e881e7 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 27 May 2019 18:03:08 +0200 Subject: use latest config logic --- talerdonations/talerconfig.py | 392 ++++++++++++++++++++++++++++++++---------- 1 file changed, 304 insertions(+), 88 deletions(-) diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py index a7ca065..2d2c78e 100644 --- a/talerdonations/talerconfig.py +++ b/talerdonations/talerconfig.py @@ -1,22 +1,21 @@ -# This file is part of TALER -# (C) 2016 INRIA +## +# This file is part of TALER +# (C) 2016 INRIA # -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free Software -# Foundation; either version 3, or (at your option) any later version. +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. # -# TALER 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. +# TALER 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 -# TALER; see the file COPYING. If not, see +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see # -# @author Florian Dold - -""" -Parse GNUnet-style configurations in pure Python -""" +# @author Florian Dold +# @author Marcello Stanisci +# @brief Parse GNUnet-style configurations in pure Python import logging import collections @@ -24,34 +23,48 @@ import os import weakref import sys import re +from typing import Callable, Any LOGGER = logging.getLogger(__name__) __all__ = ["TalerConfig"] TALER_DATADIR = None + try: - # not clear if this is a good idea ... from talerpaths import TALER_DATADIR as t TALER_DATADIR = t except ImportError: pass +## +# Exception class for a any configuration error. class ConfigurationError(Exception): pass +## +# Exception class for malformed strings having with parameter +# expansion. class ExpansionSyntaxError(Exception): pass - -def expand(var, getter): - """ - Do shell-style parameter expansion. - Supported syntax: - - ${X} - - ${X:-Y} - - $X - """ +## +# Do shell-style parameter expansion. +# Supported syntax: +# - ${X} +# - ${X:-Y} +# - $X +# +# @param var entire config value that might contain a parameter +# to expand. +# @param getter function that is in charge of returning _some_ +# value to be used in place of the parameter to expand. +# Typically, the replacement is searched first under the +# PATHS section of the current configuration, or (if not +# found) in the environment. +# +# @return the expanded config value. +def expand(var: str, getter: Callable[[str], str]) -> str: pos = 0 result = "" while pos != -1: @@ -88,38 +101,25 @@ def expand(var, getter): result = result + replace pos = end - return result + var[pos:] - -class OptionDict(collections.defaultdict): - def __init__(self, config, section_name): - self.config = weakref.ref(config) - self.section_name = section_name - super().__init__() - def __missing__(self, key): - entry = Entry(self.config(), self.section_name, key) - self[key] = entry - return entry - def __getitem__(self, chunk): - return super().__getitem__(chunk.lower()) - def __setitem__(self, chunk, value): - super().__setitem__(chunk.lower(), value) - - -class SectionDict(collections.defaultdict): - def __missing__(self, key): - value = OptionDict(self, key) - self[key] = value - return value - def __getitem__(self, chunk): - return super().__getitem__(chunk.lower()) - def __setitem__(self, chunk, value): - super().__setitem__(chunk.lower(), value) - - +## +# A configuration entry. class Entry: - def __init__(self, config, section, option, **kwargs): + + ## + # Init constructor. + # + # @param self the object itself. + # @param config reference to a configuration object - FIXME + # define "configuration object". + # @param section name of the config section where this entry + # got defined. + # @param option name of the config option associated with this + # entry. + # @param kwargs keyword arguments that hold the value / filename + # / line number of this current option. + def __init__(self, config, section: str, option: str, **kwargs) -> None: self.value = kwargs.get("value") self.filename = kwargs.get("filename") self.lineno = kwargs.get("lineno") @@ -127,14 +127,36 @@ class Entry: self.option = option self.config = weakref.ref(config) - def __repr__(self): + ## + # XML representation of this entry. + # + # @param self the object itself. + # @return XML string holding all the relevant information + # for this entry. + def __repr__(self) -> str: return "" \ % (self.section, self.option, repr(self.value),) - def __str__(self): + ## + # Return the value for this entry, as is. + # + # @param self the object itself. + # @return the config value. + def __str__(self) -> Any: return self.value - def value_string(self, default=None, required=False, warn=False): + ## + # Return entry value, accepting defaults. + # + # @param self the object itself + # @param default default value to return if none was found. + # @param required indicate whether the value was required or not. + # If the value was required, but was not found, an exception + # is found. + # @param warn if True, outputs a warning message if the value was + # not found -- regardless of it being required or not. + # @return the value, or the given @a default, if not found. + def value_string(self, default=None, required=False, warn=False) -> str: if required and self.value is None: raise ConfigurationError("Missing required option '%s' in section '%s'" \ % (self.option.upper(), self.section.upper())) @@ -149,7 +171,16 @@ class Entry: return default return self.value - def value_int(self, default=None, required=False, warn=False): + ## + # Return entry value as a _int_. Raise exception if the + # value is not convertible to a integer. + # + # @param self the object itself + # @param default currently ignored. + # @param required currently ignored. + # @param warn currently ignored. + # @return the value, or the given @a default, if not found. + def value_int(self, default=None, required=False, warn=False) -> int: value = self.value_string(default, warn, required) if value is None: return None @@ -158,8 +189,13 @@ class Entry: except ValueError: raise ConfigurationError("Expected number for option '%s' in section '%s'" \ % (self.option.upper(), self.section.upper())) - - def _getsubst(self, key): + ## + # Fetch value to substitute to expansion variables. + # + # @param self the object itself. + # @param key the value's name to lookup. + # @return the value, if found, None otherwise. + def _getsubst(self, key: str) -> Any: value = self.config()["paths"][key].value if value is not None: return value @@ -168,31 +204,136 @@ class Entry: return value return None - def value_filename(self, default=None, required=False, warn=False): + ## + # Fetch the config value that should be a filename, + # taking care of invoking the variable-expansion logic first. + # + # @param self the object itself. + # @param default currently ignored. + # @param required currently ignored. + # @param warn currently ignored. + # @return the (expanded) filename. + def value_filename(self, default=None, required=False, warn=False) -> str: value = self.value_string(default, required, warn) if value is None: return None return expand(value, self._getsubst) - def location(self): + ## + # Give the filename and line number of this config entry. + # + # @param self this object. + # @return :, or "" if one + # is not known. + def location(self) -> str: if self.filename is None or self.lineno is None: return "" return "%s:%s" % (self.filename, self.lineno) +## +# Represent a section by inheriting from 'defaultdict'. +class OptionDict(collections.defaultdict): + + ## + # Init constructor. + # + # @param self the object itself + # @param config the "config" object -- typically a @a TalerConfig instance. + # @param section_name the section name to assign to this object. + def __init__(self, config, section_name: str) -> None: + self.config = weakref.ref(config) + self.section_name = section_name + super().__init__() + + ## + # Logic to run when a non-existent key is dereferenced. + # Just create and return a empty config @a Entry. Note + # that the freshly created entry will nonetheless put + # under the accessed key (that *does* become existent + # afterwards). + # + # @param self the object itself. + # @param key the key attempted to be accessed. + # @return the no-value entry. + def __missing__(self, key: str) -> Entry: + entry = Entry(self.config(), self.section_name, key) + self[key] = entry + return entry + + ## + # Attempt to fetch one value from the object. + # + # @param self the object itself. + # @param chunk the key (?) that is tried to access. + # @return the object, if it exists, or a freshly created + # (empty) one, if it doesn't exist. + def __getitem__(self, chunk: str) -> Entry: + return super().__getitem__(chunk.lower()) + + ## + # Set one value into the object. + # + # @param self the object itself. + # @param chunk key under which the value is going to be set. + # @param value value to set the @a chunk to. + def __setitem__(self, chunk: str, value: Entry) -> None: + super().__setitem__(chunk.lower(), value) + +## +# Collection of all the (@a OptionDict) sections. +class SectionDict(collections.defaultdict): + ## + # Automatically invoked when a missing section is + # dereferenced. It creates the missing - empty - section. + # + # @param self the object itself. + # @param key the dereferenced section name. + # @return the freshly created section. + def __missing__(self, key): + value = OptionDict(self, key) + self[key] = value + return value + + ## + # Attempt to retrieve a section. + # + # @param self the object itself. + # @param chunk the section name. + def __getitem__(self, chunk: str) -> OptionDict: + return super().__getitem__(chunk.lower()) + + ## + # Set a section. + # + # @param self the object itself. + # @param chunk the section name to set. + # @param value the value to set under that @a chunk. + def __setitem__(self, chunk: str, value: OptionDict) -> None: + super().__setitem__(chunk.lower(), value) + +## +# One loaded taler configuration, including base configuration +# files and included files. class TalerConfig: - """ - One loaded taler configuration, including base configuration - files and included files. - """ - def __init__(self): - """ - Initialize an empty configuration - """ - self.sections = SectionDict() - - # defaults != config file: the first is the 'base' - # whereas the second overrides things from the first. + + ## + # Init constructor.. + # + # @param self the object itself. + def __init__(self) -> None: + self.sections = SectionDict() # just plain dict + + ## + # Load a configuration file, instantiating a config object. + # + # @param filename the filename where to load the configuration + # from. If None, it defaults "taler.conf". + # @param load_defaults if True, then defaults values are loaded + # (from canonical directories like "/share/config.d/taler/") + # before the actual configuration file. This latter then + # can override some/all the defaults. + # @return the config object. @staticmethod def from_file(filename=None, load_defaults=True): cfg = TalerConfig() @@ -204,22 +345,57 @@ class TalerConfig: filename = os.path.expanduser("~/.config/taler.conf") if load_defaults: cfg.load_defaults() - cfg.load_file(filename) + cfg.load_file(os.path.expanduser(filename)) return cfg - def value_string(self, section, option, **kwargs): + ## + # Get a string value from the config. + # + # @param self the config object itself. + # @param section the section to fetch the value from. + # @param option the value's option name. + # @param kwargs dict argument with instructions about + # the value retrieval logic. + # @return the wanted string (or a default / exception if + # a error occurs). + def value_string(self, section, option, **kwargs) -> str: return self.sections[section][option].value_string( kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) - def value_filename(self, section, option, **kwargs): + ## + # Get a value from the config that should be a filename. + # The variable expansion for the path's components is internally managed. + # + # @param self the config object itself. + # @param section the section to fetch the value from. + # @param option the value's option name. + # @param kwargs dict argument with instructions about + # the value retrieval logic. + # @return the wanted filename (or a default / exception if + # a error occurs). + def value_filename(self, section, option, **kwargs) -> str: return self.sections[section][option].value_filename( kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) - def value_int(self, section, option, **kwargs): + ## + # Get a integer value from the config. + # + # @param self the config object itself. + # @param section the section to fetch the value from. + # @param option the value's option name. + # @param kwargs dict argument with instructions about + # the value retrieval logic. + # @return the wanted integer (or a default / exception if + # a error occurs). + def value_int(self, section, option, **kwargs) -> int: return self.sections[section][option].value_int( kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) - def load_defaults(self): + ## + # Load default values from canonical locations. + # + # @param self the object itself. + def load_defaults(self) -> None: base_dir = os.environ.get("TALER_BASE_CONFIG") if base_dir: self.load_dir(base_dir) @@ -236,16 +412,25 @@ class TalerConfig: return LOGGER.warning("no base directory found") + ## + # Load configuration from environment variable + # TALER_CONFIG_FILE or from default location if the + # variable is not set. + # + # @param args currently unused. + # @param kwargs kwargs for subroutine @a from_file. + # @return freshly instantiated config object. @staticmethod def from_env(*args, **kwargs): - """ - Load configuration from environment variable TALER_CONFIG_FILE - or from default location if the variable is not set. - """ filename = os.environ.get("TALER_CONFIG_FILE") return TalerConfig.from_file(filename, *args, **kwargs) - def load_dir(self, dirname): + ## + # Load config values from _each_ file found in a directory. + # + # @param self the object itself. + # @param dirname the directory to crawl in the look for config files. + def load_dir(self, dirname) -> None: try: files = os.listdir(dirname) except FileNotFoundError: @@ -256,7 +441,11 @@ class TalerConfig: continue self.load_file(os.path.join(dirname, file)) - def load_file(self, filename): + ## + # Load config values from a file. + # + # @param filename config file to take the values from. + def load_file(self, filename) -> None: sections = self.sections try: with open(filename, "r") as file: @@ -271,6 +460,16 @@ class TalerConfig: if line.startswith("#"): # comment continue + if line.startswith("@INLINE@"): + pair = line.split() + if 2 != len(pair): + LOGGER.error("invalid inlined config filename given ('%s')" % line) + continue + if pair[1].startswith("/"): + self.load_file(pair[1]) + else: + self.load_file(os.path.join(os.path.dirname(filename), pair[1])) + continue if line.startswith("["): if not line.endswith("]"): LOGGER.error("invalid section header in line %s: %s", @@ -299,8 +498,16 @@ class TalerConfig: LOGGER.error("Configuration file (%s) not found", filename) sys.exit(3) - - def dump(self): + ## + # Dump the textual representation of a config object. + # + # Format: + # + # [section] + # option = value # FIXME (what is location?) + # + # @param self the object itself, that will be dumped. + def dump(self) -> None: for kv_section in self.sections.items(): print("[%s]" % (kv_section[1].section_name,)) for kv_option in kv_section[1].items(): @@ -309,7 +516,16 @@ class TalerConfig: kv_option[1].value, kv_option[1].location())) - def __getitem__(self, chunk): + + ## + # Return a whole section from this object. + # + # @param self the object itself. + # @param chunk name of the section to return. + # @return the section - note that if the section is + # not found, a empty one will created on the fly, + # then set under 'chunk', and returned. + def __getitem__(self, chunk: str) -> OptionDict: if isinstance(chunk, str): return self.sections[chunk] raise TypeError("index must be string") -- cgit v1.2.3 From 7becf0b04e22fcfd4457203fd5d3fbda1ddf10f3 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 27 May 2019 18:04:03 +0200 Subject: fix order --- taler-merchant-donations.in | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/taler-merchant-donations.in b/taler-merchant-donations.in index 5e3243d..691f7d4 100644 --- a/taler-merchant-donations.in +++ b/taler-merchant-donations.in @@ -35,12 +35,8 @@ site.addsitedir("%s/lib/python%d.%d/site-packages" % ( sys.version_info.major, sys.version_info.minor)) -## @cond -TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE")) - # No perfect match to our logging format, but good enough ... UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)" -## @endcond ## @@ -118,4 +114,5 @@ if getattr(ARGS, 'func', None) is None: if ARGS.config is not None: os.environ["TALER_CONFIG_FILE"] = ARGS.config +TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE")) ARGS.func(ARGS) -- cgit v1.2.3 From 5cdf3b0799b848b0b9f547b49b7b57f6c27df372 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 27 May 2019 18:08:22 +0200 Subject: ux --- talerdonations/talerconfig.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py index 2d2c78e..9598be5 100644 --- a/talerdonations/talerconfig.py +++ b/talerdonations/talerconfig.py @@ -32,6 +32,7 @@ __all__ = ["TalerConfig"] TALER_DATADIR = None try: + # not clear if this is a good idea ... from talerpaths import TALER_DATADIR as t TALER_DATADIR = t except ImportError: @@ -343,6 +344,7 @@ class TalerConfig: filename = os.path.join(xdg, "taler.conf") else: filename = os.path.expanduser("~/.config/taler.conf") + logging.info("Loading default config: (%s)" % filename) if load_defaults: cfg.load_defaults() cfg.load_file(os.path.expanduser(filename)) -- cgit v1.2.3 From dd835689654c18353b02f9f5809c7746de222ab9 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 27 May 2019 18:17:12 +0200 Subject: talerconfig --- talerdonations/talerconfig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py index 9598be5..4a44c97 100644 --- a/talerdonations/talerconfig.py +++ b/talerdonations/talerconfig.py @@ -344,7 +344,7 @@ class TalerConfig: filename = os.path.join(xdg, "taler.conf") else: filename = os.path.expanduser("~/.config/taler.conf") - logging.info("Loading default config: (%s)" % filename) + print("Loading default config: (%s)" % filename) if load_defaults: cfg.load_defaults() cfg.load_file(os.path.expanduser(filename)) @@ -497,7 +497,8 @@ class TalerConfig: value=value, filename=filename, lineno=lineno) sections[current_section][key] = entry except FileNotFoundError: - LOGGER.error("Configuration file (%s) not found", filename) + # not logging here, as this interests the final user mostly. + print("Configuration file (%s) not found" % filename) sys.exit(3) ## -- cgit v1.2.3 From f09cb421c2eeec58b2f768e09b97b39b8616ec02 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 10 Jun 2019 20:23:56 +0200 Subject: dependencies --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5cddc40..3e89959 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup(name='talerdonations', author_email='stanisci.m@gmail.com', license='GPL', packages=find_packages(), - install_requires=["Flask>=0.10"], + install_requires=["Flask>=0.10", "requests", "uwsgi"], tests_require=["mock", "nose"], test_suite="nose.collector", package_data={ -- cgit v1.2.3 From f80d6a250c99210c366410bb313a6c11f6fc58b1 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Tue, 25 Jun 2019 10:47:21 +0200 Subject: 5667: move jsmin dep to setup.py. --- configure.ac | 10 ---------- setup.py | 5 ++++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index c7440be..e2ecfbe 100644 --- a/configure.ac +++ b/configure.ac @@ -48,16 +48,6 @@ AC_SUBST(DEBIAN_PIP3_SYSTEM) AC_CHECK_PROG([tsc],[tsc],[yes],[no]) AM_CONDITIONAL([HAVE_TSC], [test "x$tsc" = xyes]) -# -# Check for minifier -# -AC_MSG_CHECKING([Checking for jsmin]) -python3 -m jsmin &> /dev/null -if test $? -ne 0; - then - AC_MSG_ERROR([Please install Python3 module 'jsmin']) -fi - # # Report # diff --git a/setup.py b/setup.py index 3e89959..a917c11 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,10 @@ setup(name='talerdonations', author_email='stanisci.m@gmail.com', license='GPL', packages=find_packages(), - install_requires=["Flask>=0.10", "requests", "uwsgi"], + install_requires=["Flask>=0.10", + "requests", + "uwsgi", + "jsmin"], tests_require=["mock", "nose"], test_suite="nose.collector", package_data={ -- cgit v1.2.3 From ea2a0c9dbe52c4a4922ee1e9a22b97b9024822a8 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:01:01 +0200 Subject: simplify build system --- Doxyfile | 331 ----------------------- Makefile.in | 56 ---- bootstrap | 12 - configure.ac | 66 ----- contrib/Doxyfile | 331 +++++++++++++++++++++++ frontend-donations.wsgi.in | 21 -- m4/ax_compare_version.m4 | 177 ------------ m4/python.m4 | 646 -------------------------------------------- setup.py | 8 +- taler-merchant-donations.in | 118 -------- 10 files changed, 335 insertions(+), 1431 deletions(-) delete mode 100644 Doxyfile delete mode 100644 Makefile.in delete mode 100755 bootstrap delete mode 100644 configure.ac create mode 100644 contrib/Doxyfile delete mode 100644 frontend-donations.wsgi.in delete mode 100644 m4/ax_compare_version.m4 delete mode 100644 m4/python.m4 delete mode 100644 taler-merchant-donations.in diff --git a/Doxyfile b/Doxyfile deleted file mode 100644 index 530157e..0000000 --- a/Doxyfile +++ /dev/null @@ -1,331 +0,0 @@ -# Doxyfile 1.8.13 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "taler-donations" -PROJECT_NUMBER = -PROJECT_BRIEF = -PROJECT_LOGO = -OUTPUT_DIRECTORY = doxygen-doc/ -CREATE_SUBDIRS = NO -ALLOW_UNICODE_NAMES = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = YES -STRIP_FROM_PATH = -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 4 -ALIASES = -TCL_SUBST = -OPTIMIZE_OUTPUT_FOR_C = NO -OPTIMIZE_OUTPUT_JAVA = NO -OPTIMIZE_FOR_FORTRAN = NO -OPTIMIZE_OUTPUT_VHDL = NO -EXTENSION_MAPPING = in=Python -MARKDOWN_SUPPORT = YES -TOC_INCLUDE_HEADINGS = 0 -AUTOLINK_SUPPORT = YES -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -SIP_SUPPORT = NO -IDL_PROPERTY_SUPPORT = YES -DISTRIBUTE_GROUP_DOC = NO -GROUP_NESTED_COMPOUNDS = NO -SUBGROUPING = YES -INLINE_GROUPED_CLASSES = NO -INLINE_SIMPLE_STRUCTS = NO -TYPEDEF_HIDES_STRUCT = NO -LOOKUP_CACHE_SIZE = 0 -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = YES -EXTRACT_PRIVATE = NO -EXTRACT_PACKAGE = NO -EXTRACT_STATIC = NO -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -HIDE_COMPOUND_REFERENCE= NO -SHOW_INCLUDE_FILES = YES -SHOW_GROUPED_MEMB_INC = NO -FORCE_LOCAL_INCLUDES = NO -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = NO -SORT_MEMBERS_CTORS_1ST = NO -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -STRICT_PROTO_MATCHING = NO -GENERATE_TODOLIST = YES -GENERATE_TESTLIST = YES -GENERATE_BUGLIST = YES -GENERATE_DEPRECATEDLIST= YES -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_FILES = YES -SHOW_NAMESPACES = NO -FILE_VERSION_FILTER = -LAYOUT_FILE = -CITE_BIB_FILES = -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_AS_ERROR = NO -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.py *.in -RECURSIVE = YES -EXCLUDE = Makefile.in -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = * -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -FILTER_SOURCE_PATTERNS = -USE_MDFILE_AS_MAINPAGE = -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -SOURCE_TOOLTIPS = YES -USE_HTAGS = NO -VERBATIM_HEADERS = YES -CLANG_ASSISTED_PARSING = NO -CLANG_OPTIONS = -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_EXTRA_STYLESHEET = -HTML_EXTRA_FILES = -HTML_COLORSTYLE_HUE = 220 -HTML_COLORSTYLE_SAT = 100 -HTML_COLORSTYLE_GAMMA = 80 -HTML_TIMESTAMP = NO -HTML_DYNAMIC_SECTIONS = NO -HTML_INDEX_NUM_ENTRIES = 100 -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" -DOCSET_BUNDLE_ID = org.doxygen.Project -DOCSET_PUBLISHER_ID = org.doxygen.Publisher -DOCSET_PUBLISHER_NAME = Publisher -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -CHM_INDEX_ENCODING = -BINARY_TOC = NO -TOC_EXPAND = NO -GENERATE_QHP = NO -QCH_FILE = -QHP_NAMESPACE = org.doxygen.Project -QHP_VIRTUAL_FOLDER = doc -QHP_CUST_FILTER_NAME = -QHP_CUST_FILTER_ATTRS = -QHP_SECT_FILTER_ATTRS = -QHG_LOCATION = -GENERATE_ECLIPSEHELP = NO -ECLIPSE_DOC_ID = org.doxygen.Project -DISABLE_INDEX = NO -GENERATE_TREEVIEW = NO -ENUM_VALUES_PER_LINE = 4 -TREEVIEW_WIDTH = 250 -EXT_LINKS_IN_WINDOW = NO -FORMULA_FONTSIZE = 10 -FORMULA_TRANSPARENT = YES -USE_MATHJAX = NO -MATHJAX_FORMAT = HTML-CSS -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest -MATHJAX_EXTENSIONS = -MATHJAX_CODEFILE = -SEARCHENGINE = YES -SERVER_BASED_SEARCH = NO -EXTERNAL_SEARCH = NO -SEARCHENGINE_URL = -SEARCHDATA_FILE = searchdata.xml -EXTERNAL_SEARCH_ID = -EXTRA_SEARCH_MAPPINGS = -#--------------------------------------------------------------------------- -# Configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4 -EXTRA_PACKAGES = -LATEX_HEADER = -LATEX_FOOTER = -LATEX_EXTRA_STYLESHEET = -LATEX_EXTRA_FILES = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -LATEX_SOURCE_CODE = NO -LATEX_BIB_STYLE = plain -LATEX_TIMESTAMP = NO -#--------------------------------------------------------------------------- -# Configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -RTF_SOURCE_CODE = NO -#--------------------------------------------------------------------------- -# Configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_SUBDIR = -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# Configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# Configuration options related to the DOCBOOK output -#--------------------------------------------------------------------------- -GENERATE_DOCBOOK = NO -DOCBOOK_OUTPUT = docbook -DOCBOOK_PROGRAMLISTING = NO -#--------------------------------------------------------------------------- -# Configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# Configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration options related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -EXTERNAL_PAGES = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = NO -MSCGEN_PATH = -DIA_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -DOT_NUM_THREADS = 0 -DOT_FONTNAME = Helvetica -DOT_FONTSIZE = 10 -DOT_FONTPATH = -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -UML_LIMIT_NUM_FIELDS = 10 -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = NO -CALLER_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -INTERACTIVE_SVG = NO -DOT_PATH = -DOTFILE_DIRS = -MSCFILE_DIRS = -DIAFILE_DIRS = -PLANTUML_JAR_PATH = -PLANTUML_CFG_FILE = -PLANTUML_INCLUDE_PATH = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 0 -DOT_TRANSPARENT = NO -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index c19386a..0000000 --- a/Makefile.in +++ /dev/null @@ -1,56 +0,0 @@ -INSTALL = install -INSTALL_PROGRAM = $(INSTALL) -INSTALL_DATA = $(INSTALL) -m 644 -prefix = @prefix@ -srcdir = @srcdir@ - -script_templates = taler-merchant-donations frontend-donations.wsgi -templates = Makefile $(script_templates) - -edit = sed -e 's|@prefix[@]|$(prefix)|g' - -.PHONY: all -all: $(templates) - cd talerdonations/donations/static/web-common && make && cd - - -Makefile: Makefile.in - ./config.status $@ - -$(script_templates): %: Makefile %.in - rm -f $@ $@.tmp - $(edit) '$(srcdir)/$@.in' >$@.tmp - mv $@.tmp $@ - - -.PHONY: install-data -install-data: $(templates) - @$(INSTALL_DATA) -Dt $(prefix)/share/taler/ frontend-donations.wsgi - @$(INSTALL_DATA) -Dt $(prefix)/share/taler/config.d/ donations.conf - -# @test -n "$$(ls -A talerbank/app/static/web-common/)" || \ -# (echo "please check out git submodules"; exit 1) - - - -# link package under prefix to source tree -.PHONY: devinstall -devinstall: $(templates) install-data - @pip3 install -e . --install-option="--prefix=@prefix@" - - -# install into prefix -.PHONY: install -install: $(templates) install-data - @pip3 install . @DEBIAN_PIP3_SYSTEM@ --install-option="--prefix=@prefix@" - @# force update when sources changed - @pip3 install . @DEBIAN_PIP3_SYSTEM@ --install-option="--prefix=@prefix@" --upgrade --no-deps - cd talerdonations/donations/static/web-common && make install && cd - - -# run testcases -.PHONY: check -check: - @export TALER_CONFIG_FILE=@abs_srcdir@/talerdonations/tests.conf; \ - python3 setup.py test - -pylint: - @pylint talerdonations/ diff --git a/bootstrap b/bootstrap deleted file mode 100755 index 373e5f5..0000000 --- a/bootstrap +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if ! git --version >/dev/null; then - echo "git not installed" - exit 1 -fi - -echo "$0: Updating submodules" -echo | git submodule update --init - -echo "$0: Running autoreconf" -autoreconf -if diff --git a/configure.ac b/configure.ac deleted file mode 100644 index e2ecfbe..0000000 --- a/configure.ac +++ /dev/null @@ -1,66 +0,0 @@ -AC_INIT([talerdonations], [0.1.0], [taler-bug@gnunet.org]) - -AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE -AC_PROG_AWK -AC_PROG_SED - -# -# Check for Python -# - -PC_INIT([3.4]) -pyheaders=0 -PC_PYTHON_CHECK_HEADERS([pyheaders=1]) -PC_PYTHON_CHECK_VERSION() - -# -# Check for pip3 -# - -AC_MSG_CHECKING([pip3]) -pip3 --version >/dev/null -if test $? -ne 0; - then - AC_MSG_ERROR([Please install pip3>=6.0]) -fi - -VERSION=$(pip3 --version | $AWK '{ print $2 }') - -AC_MSG_RESULT([$VERSION]) - -AX_COMPARE_VERSION([$VERSION],[lt],[6.0], [AC_MSG_ERROR([Please install pip3>=6.0])]) - -# On Debian systems, we may need to pass "--system" to pip3 to get -# to the desired installation target directory -pip3 install --help | grep '\-\-system' >> /dev/null -if test $? -ne 0; -then - DEBIAN_PIP3_SYSTEM="" -else - DEBIAN_PIP3_SYSTEM="--system" -fi -AC_SUBST(DEBIAN_PIP3_SYSTEM) - -# -# Check for tsc -# -AC_CHECK_PROG([tsc],[tsc],[yes],[no]) -AM_CONDITIONAL([HAVE_TSC], [test "x$tsc" = xyes]) - -# -# Report -# -if test x$pyheaders != x1; then - AC_MSG_WARN([Python headers not installed, might be required to build uwsgi]) -fi - - -# -# Finish -# - -AC_CONFIG_FILES([Makefile - talerdonations/donations/static/web-common/Makefile]) - -AC_OUTPUT diff --git a/contrib/Doxyfile b/contrib/Doxyfile new file mode 100644 index 0000000..530157e --- /dev/null +++ b/contrib/Doxyfile @@ -0,0 +1,331 @@ +# Doxyfile 1.8.13 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "taler-donations" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = doxygen-doc/ +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = in=Python +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = NO +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.py *.in +RECURSIVE = YES +EXCLUDE = Makefile.in +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_OPTIONS = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/frontend-donations.wsgi.in b/frontend-donations.wsgi.in deleted file mode 100644 index 8007866..0000000 --- a/frontend-donations.wsgi.in +++ /dev/null @@ -1,21 +0,0 @@ -import sys - -if sys.version_info.major < 3: - print("The taler bank needs to run with Python>=3.4") - sys.exit(1) - -import site -import os -import logging - -logging.basicConfig(level=logging.INFO) - -os.environ.setdefault("TALER_PREFIX", "@prefix@") -site.addsitedir("%s/lib/python%d.%d/site-packages" % ( - "@prefix@", - sys.version_info.major, - sys.version_info.minor)) - -import talerdonations.donations - -application = talerdonations.donations.app diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4 deleted file mode 100644 index 74dc0fd..0000000 --- a/m4/ax_compare_version.m4 +++ /dev/null @@ -1,177 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -# -# DESCRIPTION -# -# This macro compares two version strings. Due to the various number of -# minor-version numbers that can exist, and the fact that string -# comparisons are not compatible with numeric comparisons, this is not -# necessarily trivial to do in a autoconf script. This macro makes doing -# these comparisons easy. -# -# The six basic comparisons are available, as well as checking equality -# limited to a certain number of minor-version levels. -# -# The operator OP determines what type of comparison to do, and can be one -# of: -# -# eq - equal (test A == B) -# ne - not equal (test A != B) -# le - less than or equal (test A <= B) -# ge - greater than or equal (test A >= B) -# lt - less than (test A < B) -# gt - greater than (test A > B) -# -# Additionally, the eq and ne operator can have a number after it to limit -# the test to that number of minor versions. -# -# eq0 - equal up to the length of the shorter version -# ne0 - not equal up to the length of the shorter version -# eqN - equal up to N sub-version levels -# neN - not equal up to N sub-version levels -# -# When the condition is true, shell commands ACTION-IF-TRUE are run, -# otherwise shell commands ACTION-IF-FALSE are run. The environment -# variable 'ax_compare_version' is always set to either 'true' or 'false' -# as well. -# -# Examples: -# -# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) -# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) -# -# would both be true. -# -# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) -# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) -# -# would both be false. -# -# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) -# -# would be true because it is only comparing two minor versions. -# -# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) -# -# would be true because it is only comparing the lesser number of minor -# versions of the two values. -# -# Note: The characters that separate the version numbers do not matter. An -# empty string is the same as version 0. OP is evaluated by autoconf, not -# configure, so must be a string, not a variable. -# -# The author would like to acknowledge Guido Draheim whose advice about -# the m4_case and m4_ifvaln functions make this macro only include the -# portions necessary to perform the specific comparison specified by the -# OP argument in the final configure script. -# -# LICENSE -# -# Copyright (c) 2008 Tim Toolan -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 11 - -dnl ######################################################################### -AC_DEFUN([AX_COMPARE_VERSION], [ - AC_REQUIRE([AC_PROG_AWK]) - - # Used to indicate true or false condition - ax_compare_version=false - - # Convert the two version strings to be compared into a format that - # allows a simple string comparison. The end result is that a version - # string of the form 1.12.5-r617 will be converted to the form - # 0001001200050617. In other words, each number is zero padded to four - # digits, and non digits are removed. - AS_VAR_PUSHDEF([A],[ax_compare_version_A]) - A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ - -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ - -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ - -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ - -e 's/[[^0-9]]//g'` - - AS_VAR_PUSHDEF([B],[ax_compare_version_B]) - B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ - -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ - -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ - -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ - -e 's/[[^0-9]]//g'` - - dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary - dnl # then the first line is used to determine if the condition is true. - dnl # The sed right after the echo is to remove any indented white space. - m4_case(m4_tolower($2), - [lt],[ - ax_compare_version=`echo "x$A -x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` - ], - [gt],[ - ax_compare_version=`echo "x$A -x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` - ], - [le],[ - ax_compare_version=`echo "x$A -x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` - ], - [ge],[ - ax_compare_version=`echo "x$A -x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` - ],[ - dnl Split the operator from the subversion count if present. - m4_bmatch(m4_substr($2,2), - [0],[ - # A count of zero means use the length of the shorter version. - # Determine the number of characters in A and B. - ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` - ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` - - # Set A to no more than B's length and B to no more than A's length. - A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` - B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` - ], - [[0-9]+],[ - # A count greater than zero means use only that many subversions - A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` - B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` - ], - [.+],[ - AC_WARNING( - [illegal OP numeric parameter: $2]) - ],[]) - - # Pad zeros at end of numbers to make same length. - ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" - B="$B`echo $A | sed 's/./0/g'`" - A="$ax_compare_version_tmp_A" - - # Check for equality or inequality as necessary. - m4_case(m4_tolower(m4_substr($2,0,2)), - [eq],[ - test "x$A" = "x$B" && ax_compare_version=true - ], - [ne],[ - test "x$A" != "x$B" && ax_compare_version=true - ],[ - AC_WARNING([illegal OP parameter: $2]) - ]) - ]) - - AS_VAR_POPDEF([A])dnl - AS_VAR_POPDEF([B])dnl - - dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. - if test "$ax_compare_version" = "true" ; then - m4_ifvaln([$4],[$4],[:])dnl - m4_ifvaln([$5],[else $5])dnl - fi -]) dnl AX_COMPARE_VERSION diff --git a/m4/python.m4 b/m4/python.m4 deleted file mode 100644 index 98a68b8..0000000 --- a/m4/python.m4 +++ /dev/null @@ -1,646 +0,0 @@ -# Copyright 2012, 2013, 2014 Brandon Invergo -# -# This file is part of pyconfigure. 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 3 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. -# -# Under Section 7 of GPL version 3, you are granted additional -# permissions described in the Autoconf Configure Script Exception, -# version 3.0, as published by the Free Software Foundation. -# -# You should have received a copy of the GNU General Public License -# and a copy of the Autoconf Configure Script Exception along with -# this program; see the files COPYINGv3 and COPYING.EXCEPTION -# respectively. If not, see . - - -# Many of these macros were adapted from ones written by Andrew Dalke -# and James Henstridge and are included with the Automake utility -# under the following copyright terms: -# -# Copyright (C) 1999-2012 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# Table of Contents: -# -# 1. Language selection -# and routines to produce programs in a given language. -# -# 2. Producing programs in a given language. -# -# 3. Looking for a compiler -# And possibly the associated preprocessor. -# -# 4. Looking for specific libs & functionality - - -## ----------------------- ## -## 1. Language selection. ## -## ----------------------- ## - - -# AC_LANG(Python) -# --------------- -AC_LANG_DEFINE([Python], [py], [PY], [PYTHON], [], -[ac_ext=py -ac_compile='chmod +x conftest.$ac_ext >&AS_MESSAGE_LOG_FD' -ac_link='chmod +x conftest.$ac_ext && cp conftest.$ac_ext conftest >&AS_MESSAGE_LOG_FD' -]) - - -# AC_LANG_PYTHON -# -------------- -AU_DEFUN([AC_LANG_PYTHON], [AC_LANG(Python)]) - - -## ----------------------- ## -## 2. Producing programs. ## -## ----------------------- ## - - -# AC_LANG_PROGRAM(Python)([PROLOGUE], [BODY]) -# ------------------------------------------- -m4_define([AC_LANG_PROGRAM(Python)], [dnl -@%:@!$PYTHON -$1 -m4_if([$2], [], [], [dnl -if __name__ == '__main__': -$2])]) - - -# _AC_LANG_IO_PROGRAM(Python) -# --------------------------- -# Produce source that performs I/O. -m4_define([_AC_LANG_IO_PROGRAM(Python)], -[AC_LANG_PROGRAM([dnl -import sys -try: - h = open('conftest.out') -except: - sys.exit(1) -else: - close(h) - sys.exit(0) -], [])]) - - -# _AC_LANG_CALL(Python)([PROLOGUE], [FUNCTION]) -# --------------------- -# Produce source that calls FUNCTION -m4_define([_AC_LANG_CALL(Python)], -[AC_LANG_PROGRAM([$1], [$2])]) - - -## -------------------------------------------- ## -## 3. Looking for Compilers and Interpreters. ## -## -------------------------------------------- ## - - -AC_DEFUN([AC_LANG_COMPILER(Python)], -[AC_REQUIRE([PC_PROG_PYTHON])]) - - -# PC_INIT([MIN-VERSION], [MAX-VERSION]) -# ----------------------------- -# Initialize pyconfigure, finding a Python interpreter with a given -# minimum and/or maximum version. -AC_DEFUN([PC_INIT], -[PC_PROG_PYTHON([], [$1], [$2]) -dnl If we found something, do a sanity check that the interpreter really -dnl has the version its name would suggest. -m4_ifval([PYTHON], - [PC_PYTHON_VERIFY_VERSION([>=], [pc_min_ver], [], - [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])]) -m4_ifval([PYTHON], - [PC_PYTHON_VERIFY_VERSION([<=], [pc_max_ver], [], - [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])]) -])# PC_INIT - -# PC_PROG_PYTHON([PROG-TO-CHECK-FOR], [MIN-VERSION], [MAX-VERSION]) -# --------------------------------- -# Find a Python interpreter. Python versions prior to 2.0 are not -# supported. (2.0 was released on October 16, 2000). -AC_DEFUN_ONCE([PC_PROG_PYTHON], -[AC_ARG_VAR([PYTHON], [the Python interpreter]) -dnl The default minimum version is 2.0 -m4_define_default([pc_min_ver], m4_ifval([$2], [$2], [2.0])) -dnl The default maximum version is 3.3 -m4_define_default([pc_max_ver], m4_ifval([$3], [$3], [4.0])) -dnl Build up a list of possible interpreter names. -m4_define_default([_PC_PYTHON_INTERPRETER_LIST], - [dnl If we want some Python 3 versions (max version >= 3.0), -dnl also search for "python3" - m4_if(m4_version_compare(pc_max_ver, [2.9]), [1], [python3], []) \ -dnl If we want some Python 2 versions (min version <= 2.7), -dnl also search for "python2". - m4_if(m4_version_compare(pc_min_ver, [2.8]), [-1], [python2], []) \ -dnl Construct a comma-separated list of interpreter names (python2.6, -dnl python2.7, etc). We only care about the first 3 characters of the -dnl version strings (major-dot-minor; not -dnl major-dot-minor-dot-bugfix[-dot-whatever]) - m4_foreach([pc_ver], - m4_esyscmd_s(seq -s[[", "]] -f["[[%.1f]]"] m4_substr(pc_max_ver, [0], [3]) -0.1 m4_substr(pc_min_ver, [0], [3])), -dnl Remove python2.8 and python2.9 since they will never exist - [m4_bmatch(pc_ver, [2.[89]], [], [python]pc_ver)]) \ - [python]]) -dnl Do the actual search at last. -m4_ifval([$1], - [AC_PATH_PROGS(PYTHON, [$1 _PC_PYTHON_INTERPRETER_LIST])], - [AC_PATH_PROGS(PYTHON, [_PC_PYTHON_INTERPRETER_LIST])]) -])# PC_PROG_PYTHON - - -# PC_PYTHON_PROG_PYTHON_CONFIG(PROG-TO-CHECK-FOR) -# ---------------------------------------------- -# Find the python-config program -AC_DEFUN([PC_PYTHON_PROG_PYTHON_CONFIG], -[AC_REQUIRE([PC_PROG_PYTHON])[]dnl -AC_ARG_VAR([PYTHON_CONFIG], [the Python-config program]) -dnl python-config's binary name is normally based on the Python interpreter's -dnl binary name (i.e. python2.7 -> python2.7-config) -m4_define([_PYTHON_BASENAME], [`basename $PYTHON`]) -m4_ifval([$1], - [AC_PATH_PROGS(PYTHON_CONFIG, [$1 _PYTHON_BASENAME-config])], - [AC_PATH_PROG(PYTHON_CONFIG, _PYTHON_BASENAME-config)]) -]) # PC_PYTHON_PROG_PYTHON_CONFIG - - -# PC_PYTHON_VERIFY_VERSION([RELATION], [VERSION], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -# --------------------------------------------------------------------------- -# Run ACTION-IF-TRUE if the Python interpreter PROG has version [RELATION] VERSION. -# i.e if RELATION is "<", check if PROG has a version number less than VERSION. -# Run ACTION-IF-FALSE otherwise. -# Specify RELATION as any mathematical comparison "<", ">", "<=", ">=", "==" or "!=" -# This test uses sys.hexversion instead of the string equivalent (first -# word of sys.version), in order to cope with versions such as 2.2c1. -# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). -AC_DEFUN([PC_PYTHON_VERIFY_VERSION], -[m4_define([pc_python_safe_ver], m4_bpatsubsts($2, [\.], [_])) -AC_CACHE_CHECK([if Python $1 '$2'], - [[pc_cv_python_req_version_]pc_python_safe_ver], - [AC_LANG_PUSH(Python)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([dnl -import sys -], [dnl - # split strings by '.' and convert to numeric. Append some zeros - # because we need at least 4 digits for the hex conversion. - # map returns an iterator in Python 3.0 and a list in 2.x - reqver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] - reqverhex = 0 - # xrange is not present in Python 3.0 and range returns an iterator - for i in list(range(4)): - reqverhex = (reqverhex << 8) + reqver[[i]] - # the final 8 bits are "0xf0" for final versions, which are all - # we'll test against, since it's doubtful that a released software - # will depend on an alpha- or beta-state Python. - reqverhex += 0xf0 - if sys.hexversion $1 reqverhex: - sys.exit() - else: - sys.exit(1) -])], - [[pc_cv_python_req_version_]pc_python_safe_ver=yes], - [[pc_cv_python_req_version_]pc_python_safe_ver=no]) - AC_LANG_POP(Python)[]dnl - ]) -AS_IF([test "$[pc_cv_python_req_version_]pc_python_safe_ver" = "no"], [$4], [$3]) -])# PC_PYTHON_VERIFY_VERSION - - -# PC_PYTHON_CHECK_VERSION -# ----------------------- -# Query Python for its version number. Getting [:3] seems to be -# the best way to do this; it's what "site.py" does in the standard -# library. -AC_DEFUN([PC_PYTHON_CHECK_VERSION], -[AC_REQUIRE([PC_PROG_PYTHON])[]dnl -AC_CACHE_CHECK([for $1 version], - [pc_cv_python_version], - [AC_LANG_PUSH(Python)[]dnl - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -], [dnl - sys.stdout.write(sys.version[[:3]]) -])], - [pc_cv_python_version=`./conftest`], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl - ]) -AC_SUBST([PYTHON_VERSION], [$pc_cv_python_version]) -])# PC_PYTHON_CHECK_VERSION - - -# PC_PYTHON_CHECK_PREFIX -# ---------------------- -# Use the value of $prefix for the corresponding value of -# PYTHON_PREFIX. This is made a distinct variable so it can be -# overridden if need be. However, general consensus is that you -# shouldn't need this ability. -AC_DEFUN([PC_PYTHON_CHECK_PREFIX], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to get it with python-config otherwise do it from within Python -AC_CACHE_CHECK([for Python prefix], [pc_cv_python_prefix], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_prefix=`$PYTHON_CONFIG --prefix 2>&AS_MESSAGE_LOG_FD` -else - AC_LANG_PUSH(Python)[]dnl - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -], [dnl - sys.stdout.write(sys.prefix) -])], [pc_cv_python_prefix=`./conftest`; - if test $? != 0; then - AC_MSG_FAILURE([could not determine Python prefix]) - fi], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl -fi]) -AC_SUBST([PYTHON_PREFIX], [$pc_cv_python_prefix])]) - - -# PC_PYTHON_CHECK_EXEC_PREFIX -# -------------------------- -# Like above, but for $exec_prefix -AC_DEFUN([PC_PYTHON_CHECK_EXEC_PREFIX], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to get it with python-config otherwise do it from within Python -AC_CACHE_CHECK([for Python exec-prefix], [pc_cv_python_exec_prefix], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_exec_prefix=`$PYTHON_CONFIG --exec-prefix 2>&AS_MESSAGE_LOG_FD` -else - AC_LANG_PUSH(Python)[]dnl - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -], [dnl - sys.stdout.write(sys.exec_prefix) -])], - [pc_cv_python_exec_prefix=`./conftest`; - if test $? != 0; then - AC_MSG_FAILURE([could not determine Python exec_prefix]) - fi], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl -fi -]) -AC_SUBST([PYTHON_EXEC_PREFIX], [$pc_cv_python_exec_prefix])]) - - -# PC_PYTHON_CHECK_INCLUDES -# ------------------------ -# Find the Python header file include flags (ie -# '-I/usr/include/python') -AC_DEFUN([PC_PYTHON_CHECK_INCLUDES], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the headers location with python-config otherwise guess -AC_CACHE_CHECK([for Python includes], [pc_cv_python_includes], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_includes=`$PYTHON_CONFIG --includes 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_includes="[-I$includedir/$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS, - PYTHON_ABI_FLAGS,)" -fi -]) -AC_SUBST([PYTHON_INCLUDES], [$pc_cv_python_includes])]) - - -# PC_PYTHON_CHECK_HEADERS([ACTION-IF-PRESENT], [ACTION-IF-ABSENT]) -# ----------------------- -# Check for the presence and usability of Python.h -AC_DEFUN([PC_PYTHON_CHECK_HEADERS], -[AC_REQUIRE([PC_PYTHON_CHECK_INCLUDES])[]dnl -pc_cflags_store=$CPPFLAGS -CPPFLAGS="$CFLAGS $PYTHON_INCLUDES" -AC_CHECK_HEADER([Python.h], [$1], [$2]) -CPPFLAGS=$pc_cflags_store -]) - - -# PC_PYTHON_CHECK_LIBS -# -------------------- -# Find the Python lib flags (ie '-lpython') -AC_DEFUN([PC_PYTHON_CHECK_LIBS], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the lib flags with python-config otherwise guess -AC_CACHE_CHECK([for Python libs], [pc_cv_python_libs], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_libs=`$PYTHON_CONFIG --libs 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_libs="[-l$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS, PYTHON_ABI_FLAGS,)" -fi -]) -AC_SUBST([PYTHON_LIBS], [$pc_cv_python_libs])]) - - -# PC_PYTHON_TEST_LIBS(LIBRARY-FUNCTION, [ACTION-IF-PRESENT], [ACTION-IF-ABSENT]) -# ------------------- -# Verify that the Python libs can be loaded -AC_DEFUN([PC_PYTHON_TEST_LIBS], -[AC_REQUIRE([PC_PYTHON_CHECK_LIBS])[]dnl -pc_libflags_store=$LIBS -for lflag in $PYTHON_LIBS; do - case $lflag in - -lpython*@:}@ - LIBS="$LIBS $lflag" - pc_libpython=`echo $lflag | sed -e 's/^-l//'` - ;; - *@:}@;; - esac -done -AC_CHECK_LIB([$pc_libpython], [$1], [$2], [$3])]) - - -# PC_PYTHON_CHECK_CFLAGS -# ---------------------- -# Find the Python CFLAGS -AC_DEFUN([PC_PYTHON_CHECK_CFLAGS], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the CFLAGS with python-config otherwise give up -AC_CACHE_CHECK([for Python CFLAGS], [pc_cv_python_cflags], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_cflags=`$PYTHON_CONFIG --cflags 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_cflags= -fi -]) -AC_SUBST([PYTHON_CFLAGS], [$pc_cv_python_cflags])]) - - -# PC_PYTHON_CHECK_LDFLAGS -# ----------------------- -# Find the Python LDFLAGS -AC_DEFUN([PC_PYTHON_CHECK_LDFLAGS], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the LDFLAGS with python-config otherwise give up -AC_CACHE_CHECK([for Python LDFLAGS], [pc_cv_python_ldflags], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_ldflags=`$PYTHON_CONFIG --ldflags 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_ldflags= -fi -]) -AC_SUBST([PYTHON_LDFLAGS], [$pc_cv_python_ldflags])]) - - -# PC_PYTHON_CHECK_EXTENSION_SUFFIX -# -------------------------------- -# Find the Python extension suffix (i.e. '.cpython-32.so') -AC_DEFUN([PC_PYTHON_CHECK_EXTENSION_SUFFIX], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the suffix with python-config otherwise give up -AC_CACHE_CHECK([for Python extension suffix], [pc_cv_python_extension_suffix], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_extension_suffix=`$PYTHON_CONFIG --extension-suffix 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_extension_suffix= -fi -]) -AC_SUBST([PYTHON_EXTENSION_SUFFIX], [$pc_cv_python_extension_suffix])]) - - -# PC_PYTHON_CHECK_ABI_FLAGS -# ------------------------- -# Find the Python ABI flags -AC_DEFUN([PC_PYTHON_CHECK_ABI_FLAGS], -[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl -dnl Try to find the ABI flags with python-config otherwise give up -AC_CACHE_CHECK([for Python ABI flags], [pc_cv_python_abi_flags], -[if test -x "$PYTHON_CONFIG"; then - pc_cv_python_abi_flags=`$PYTHON_CONFIG --abiflags 2>&AS_MESSAGE_LOG_FD` -else - pc_cv_python_abi_flags= -fi -]) -AC_SUBST([PYTHON_ABI_FLAGS], [$pc_cv_python_abi_flags])]) - - -# PC_PYTHON_CHECK_PLATFORM -# ------------------------ -# At times (like when building shared libraries) you may want -# to know which OS platform Python thinks this is. -AC_DEFUN([PC_PYTHON_CHECK_PLATFORM], -[AC_REQUIRE([PC_PROG_PYTHON])[]dnl -dnl Get the platform from within Python (sys.platform) -AC_CACHE_CHECK([for Python platform], [pc_cv_python_platform], - [AC_LANG_PUSH(Python)[]dnl - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -], [dnl - sys.stdout.write(sys.platform) -])], [pc_cv_python_platform=`./conftest`; - if test $? != 0; then - AC_MSG_FAILURE([could not determine Python platform]) - fi], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl - ]) -AC_SUBST([PYTHON_PLATFORM], [$pc_cv_python_platform]) -]) - - -# PC_PYTHON_CHECK_SITE_DIR -# --------------------- -# The directory to which new libraries are installed (i.e. the -# "site-packages" directory. -AC_DEFUN([PC_PYTHON_CHECK_SITE_DIR], -[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_PREFIX])[]dnl -AC_CACHE_CHECK([for Python site-packages directory], - [pc_cv_python_site_dir], - [AC_LANG_PUSH(Python)[]dnl - if test "x$prefix" = xNONE - then - pc_py_prefix=$ac_default_prefix - else - pc_py_prefix=$prefix - fi - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -from platform import python_implementation -# sysconfig in CPython 2.7 doesn't work in virtualenv -# -try: - import sysconfig -except: - can_use_sysconfig = False -else: - can_use_sysconfig = True -if can_use_sysconfig: - if python_implementation() == "CPython" and sys.version[[:3]] == '2.7': - can_use_sysconfig = False -if not can_use_sysconfig: - from distutils import sysconfig - sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py_prefix') -else: - sitedir = sysconfig.get_path('purelib', vars={'base':'$pc_py_prefix'}) -], [dnl - sys.stdout.write(sitedir) -])], [pc_cv_python_site_dir=`./conftest`], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl - case $pc_cv_python_site_dir in - $pc_py_prefix*) - pc__strip_prefix=`echo "$pc_py_prefix" | sed 's|.|.|g'` - pc_cv_python_site_dir=`echo "$pc_cv_python_site_dir" | sed "s,^$pc__strip_prefix/,,"` - ;; - *) - case $pc_py_prefix in - /usr|/System*) ;; - *) - pc_cv_python_site_dir=lib/python$PYTHON_VERSION/site-packages - ;; - esac - ;; - esac - ]) -AC_SUBST([pythondir], [\${prefix}/$pc_cv_python_site_dir])])# PC_PYTHON_CHECK_SITE_DIR - -# PC_PYTHON_SITE_PACKAGE_DIR -# -------------------------- -# $PACKAGE directory under PYTHON_SITE_DIR -AC_DEFUN([PC_PYTHON_SITE_PACKAGE_DIR], -[AC_REQUIRE([PC_PYTHON_CHECK_SITE_DIR])[]dnl -AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE_NAME])]) - - -# PC_PYTHON_CHECK_EXEC_DIR -# ------------------------ -# directory for installing python extension modules (shared libraries) -AC_DEFUN([PC_PYTHON_CHECK_EXEC_DIR], -[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_EXEC_PREFIX])[]dnl - AC_CACHE_CHECK([for Python extension module directory], - [pc_cv_python_exec_dir], - [AC_LANG_PUSH(Python)[]dnl - if test "x$pc_cv_python_exec_prefix" = xNONE - then - pc_py_exec_prefix=$pc_cv_python_prefix - else - pc_py_exec_prefix=$pc_cv_python_exec_prefix - fi - AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl -import sys -from platform import python_implementation -# sysconfig in CPython 2.7 doesn't work in virtualenv -# -try: - import sysconfig -except: - can_use_sysconfig = False -else: - can_use_sysconfig = True -if can_use_sysconfig: - if python_implementation() == "CPython" and sys.version[[:3]] == '2.7': - can_use_sysconfig = False -if not can_use_sysconfig: - from distutils import sysconfig - sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py__exec_prefix') -else: - sitedir = sysconfig.get_path('purelib', vars={'platbase':'$pc_py_exec_prefix'}) -], [dnl - sys.stdout.write(sitedir) -])], [pc_cv_python_exec_dir=`./conftest`], - [AC_MSG_FAILURE([failed to run Python program])]) - AC_LANG_POP(Python)[]dnl - case $pc_cv_python_exec_dir in - $pc_py_exec_prefix*) - pc__strip_prefix=`echo "$pc_py_exec_prefix" | sed 's|.|.|g'` - pc_cv_python_exec_dir=`echo "$pc_cv_python_exec_dir" | sed "s,^$pc__strip_prefix/,,"` - ;; - *) - case $pc_py_exec_prefix in - /usr|/System*) ;; - *) - pc_cv_python_exec_dir=lib/python$PYTHON_VERSION/site-packages - ;; - esac - ;; - esac - ]) -AC_SUBST([pyexecdir], [\${exec_prefix}/$pc_cv_python_pyexecdir])]) #PY_PYTHON_CHECK_EXEC_LIB_DIR - - -# PC_PYTHON_EXEC_PACKAGE_DIR -# -------------------------- -# $PACKAGE directory under PYTHON_SITE_DIR -AC_DEFUN([PC_PYTHON_EXEC_PACKAGE_DIR], -[AC_REQUIRE([PC_PYTHON_CHECK_EXEC_DIR])[]dnl -AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE_NAME])]) - - -## -------------------------------------------- ## -## 4. Looking for specific libs & functionality ## -## -------------------------------------------- ## - - -# PC_PYTHON_CHECK_MODULE(LIBRARY, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# ---------------------------------------------------------------------- -# Macro for checking if a Python library is installed -AC_DEFUN([PC_PYTHON_CHECK_MODULE], -[AC_REQUIRE([PC_PROG_PYTHON])[]dnl -m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_])) -AC_CACHE_CHECK([for Python '$1' library], - [[pc_cv_python_module_]pc_python_safe_mod], - [AC_LANG_PUSH(Python)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([dnl -import sys -try: - import $1 -except: - sys.exit(1) -else: - sys.exit(0) -], [])], - [[pc_cv_python_module_]pc_python_safe_mod="yes"], - [[pc_cv_python_module_]pc_python_safe_mod="no"]) - AC_LANG_POP(Python)[]dnl - ]) -AS_IF([test "$[pc_cv_python_module_]pc_python_safe_mod" = "no"], [$3], [$2]) -])# PC_PYTHON_CHECK_MODULE - - -# PC_PYTHON_CHECK_FUNC([LIBRARY], FUNCTION, ARGS, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# --------------------------------------------------------------------------------------- -# Check to see if a given function call, optionally from a module, can -# be successfully called -AC_DEFUN([PC_PYTHON_CHECK_FUNC], -[AC_REQUIRE([PC_PROG_PYTHON])[]dnl -m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_])) -AC_CACHE_CHECK([for Python m4_ifnblank($1, '$1.$2()', '$2()') function], - [[pc_cv_python_func_]pc_python_safe_mod[_$2]], - [AC_LANG_PUSH(Python)[]dnl - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([dnl -import sys -m4_ifnblank([$1], [dnl -try: - import $1 -except: - sys.exit(1) -], [])], -[ -m4_ifnblank([$1], [ - try: - $1.$2($3)], [ - try: - $2($3)]) - except: - sys.exit(1) - else: - sys.exit(0) -])], - [[pc_cv_python_func_]pc_python_safe_mod[_$2]="yes"], - [[pc_cv_python_func_]pc_python_safe_mod[_$2]="no"]) - AC_LANG_POP(Python)[]dnl - ]) -AS_IF([test "$[pc_cv_python_func_]pc_python_safe_mod[_$2]" = "no"], [$5], [$4]) -])# PC_PYTHON_CHECK_FUNC diff --git a/setup.py b/setup.py index a917c11..71526a9 100755 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ from setuptools import setup, find_packages setup(name='talerdonations', - version='0.0', + version='0.6.0pre1', description='Example donations site for GNU Taler', url='git://taler.net/donations', - author='Marcello Stanisci', - author_email='stanisci.m@gmail.com', + author=['Marcello Stanisci', 'Florian Dold'], + author_email=['stanisci.m@gmail.com', 'dold@taler.net'], license='GPL', packages=find_packages(), install_requires=["Flask>=0.10", @@ -24,5 +24,5 @@ setup(name='talerdonations', "donations/static/web-common/*.html", ] }, - scripts=['taler-merchant-donations'], + scripts=['./bin/taler-merchant-donations'], zip_safe=False) diff --git a/taler-merchant-donations.in b/taler-merchant-donations.in deleted file mode 100644 index 691f7d4..0000000 --- a/taler-merchant-donations.in +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python3 - -## -# This file is part of TALER -# (C) 2017 INRIA -# -# TALER is free software; you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public -# License as published by the Free Software Foundation; either -# version 3, or (at your option) any later version. -# -# TALER 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 TALER; see the file COPYING. If not, -# see -# -# @author Florian Dold -# @file Standalone script to run the donations site. - -import argparse -import sys -import os -import site -import logging -from talerdonations.talerconfig import TalerConfig - - -os.environ.setdefault("TALER_PREFIX", "@prefix@") -site.addsitedir("%s/lib/python%d.%d/site-packages" % ( - "@prefix@", - sys.version_info.major, - sys.version_info.minor)) - -# No perfect match to our logging format, but good enough ... -UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)" - - -## -# This function interprets the 'serve-http' subcommand. -# The effect it to launch the donations HTTP service. -# -# @param args command line options. -def handle_serve_http(args): - port = args.port - if port is None: - port = TC["donations"]["http_port"].value_int(required=True) - spec = ":%d" % (port,) - os.execlp("uwsgi", "uwsgi", - "--master", - "--die-on-term", - "--log-format", UWSGI_LOGFMT, - "--http", spec, - "--wsgi-file", "@prefix@/share/taler/frontend-donations.wsgi") - - -## -# This function interprets the 'serve-uwsgi' subcommand. -# The effect is to launch the donations UWSGI service. This -# type of service is usually used when the HTTP donations interface -# is accessed via a reverse proxy (like Nginx, for example). -# -# @param command line options. -def handle_serve_uwsgi(args): - del args # pacify PEP checkers - serve_uwsgi = TC["donations"]["uwsgi_serve"].value_string(required=True).lower() - params = ["uwsgi", "uwsgi", - "--master", - "--die-on-term", - "--log-format", UWSGI_LOGFMT, - "--wsgi-file", "@prefix@/share/taler/frontend-donations.wsgi"] - if serve_uwsgi == "tcp": - port = TC["donations"]["uwsgi_port"].value_int(required=True) - spec = ":%d" % (port,) - params.extend(["--socket", spec]) - elif serve_uwsgi == "unix": - spec = TC["donations"]["uwsgi_unixpath"].value_filename(required=True) - mode = TC["donations"]["uwsgi_unixpath_mode"].value_filename(required=True) - params.extend(["--socket", spec]) - params.extend(["--chmod-socket="+mode]) - os.makedirs(os.path.dirname(spec), exist_ok=True) - logging.info("launching uwsgi with argv %s", params[1:]) - os.execlp(*params) - - -## @cond -PARSER = argparse.ArgumentParser() -PARSER.set_defaults(func=None) -PARSER.add_argument('--config', '-c', - help="configuration file to use", - metavar="CONFIG", type=str, - dest="config", default=None) -SUB = PARSER.add_subparsers() - -P = SUB.add_parser('serve-http', help="Serve over HTTP") -P.add_argument("--port", "-p", dest="port", - type=int, default=None, metavar="PORT") -P.set_defaults(func=handle_serve_http) - -P = SUB.add_parser('serve-uwsgi', help="Serve over UWSGI") -P.set_defaults(func=handle_serve_uwsgi) - -ARGS = PARSER.parse_args() -## @endcond - - -if getattr(ARGS, 'func', None) is None: - PARSER.print_help() - sys.exit(1) - -if ARGS.config is not None: - os.environ["TALER_CONFIG_FILE"] = ARGS.config - -TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE")) -ARGS.func(ARGS) -- cgit v1.2.3 From 455755737e6dcb7f938f7e6f9672bfc3e38f0a73 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:01:43 +0200 Subject: yapf style file --- .style.yapf | 5 ++ talerdonations/donations/donations.py | 76 ++++++++++++++++------------ talerdonations/talerconfig.py | 95 ++++++++++++++++++++++++----------- talerdonations/tests.py | 1 + 4 files changed, 116 insertions(+), 61 deletions(-) create mode 100644 .style.yapf diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..3b39780 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,5 @@ +[style] +based_on_style = pep8 +coalesce_brackets=True +column_limit=80 +dedent_closing_brackets=True diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index f0f97c5..5655734 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -53,6 +53,7 @@ app.config.from_object(__name__) def utility_processor(): def env(name, default=None): return os.environ.get(name, default) + return dict(env=env) @@ -76,7 +77,9 @@ def err_abort(abort_status_code, **params): def backend_get(endpoint, params): headers = {"Authorization": "ApiKey " + APIKEY} try: - resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params, headers=headers) + resp = requests.get(urljoin(BACKEND_URL, endpoint), + params=params, + headers=headers) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: @@ -84,8 +87,10 @@ def backend_get(endpoint, params): except ValueError: err_abort(500, message="Could not parse response from backend") if resp.status_code != 200: - err_abort(500, message="Backend returned error status", - json=response_json, status_code=resp.status_code) + err_abort(500, + message="Backend returned error status", + json=response_json, + status_code=resp.status_code) return response_json @@ -100,21 +105,25 @@ def backend_get(endpoint, params): def backend_post(endpoint, json): headers = {"Authorization": "ApiKey " + APIKEY} try: - resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json, headers=headers) + resp = requests.post(urljoin(BACKEND_URL, endpoint), + json=json, + headers=headers) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: response_json = resp.json() except ValueError: - err_abort(500, message="Could not parse response from backend", + err_abort(500, + message="Could not parse response from backend", status_code=resp.status_code) if resp.status_code != 200: - err_abort(500, message="Backend returned error status", - json=response_json, status_code=resp.status_code) + err_abort(500, + message="Backend returned error status", + json=response_json, + status_code=resp.status_code) return response_json - ## # Inspect GET arguments in the look for a parameter. # @@ -126,6 +135,7 @@ def expect_parameter(name): return err_abort(400, message="parameter '{}' required".format(name)) return val + ## # "Fallback" exception handler to capture all the unmanaged errors. # @@ -138,13 +148,16 @@ def internal_error(e): message="Internal error", stack=traceback.format_exc()) + ## # Serve the main index page. # # @return response object of the index page. @app.route("/") def index(): - return flask.render_template("templates/index.html", merchant_currency=CURRENCY) + return flask.render_template("templates/index.html", + merchant_currency=CURRENCY) + ## # Serve the "/javascript" page. @@ -155,7 +168,6 @@ def javascript_licensing(): return flask.render_template("templates/javascript.html") - ## # Serve the "/checkout" page. This page lets the # user pick the payment method they want to use, @@ -167,12 +179,11 @@ def checkout(): amount = expect_parameter("donation_amount") donation_receiver = expect_parameter("donation_receiver") donation_donor = expect_parameter("donation_donor") - return flask.render_template( - "templates/checkout.html", - donation_amount=amount, - donation_receiver=donation_receiver, - donation_donor=donation_donor, - merchant_currency=CURRENCY) + return flask.render_template("templates/checkout.html", + donation_amount=amount, + donation_receiver=donation_receiver, + donation_donor=donation_donor, + merchant_currency=CURRENCY) ## @@ -182,8 +193,7 @@ def checkout(): # @return response object about the mentioned impossibility. @app.route("/provider-not-supported") def provider_not_supported(): - return flask.render_template( "templates/provider-not-supported.html") - + return flask.render_template("templates/provider-not-supported.html") ## @@ -201,18 +211,24 @@ def donate(): payment_system = expect_parameter("payment_system") if payment_system != "taler": return flask.redirect(flask.url_for("provider_not_supported")) - fulfillment_url = flask.url_for("fulfillment", receiver=donation_receiver, _external=True) + fulfillment_url = flask.url_for("fulfillment", + receiver=donation_receiver, + _external=True) order = dict( amount=donation_amount, - extra=dict(donor=donation_donor, receiver=donation_receiver, amount=donation_amount), + extra=dict(donor=donation_donor, + receiver=donation_receiver, + amount=donation_amount), fulfillment_url=fulfillment_url, instance=donation_receiver, summary="Donation to {}".format(donation_receiver), ) order_resp = backend_post("order", dict(order=order)) order_id = order_resp["order_id"] - return flask.redirect(flask.url_for("fulfillment", receiver=donation_receiver, order_id=order_id)) - + return flask.redirect( + flask.url_for("fulfillment", + receiver=donation_receiver, + order_id=order_id)) ## @@ -226,8 +242,7 @@ def donate(): @app.route("/donation/") def fulfillment(receiver): order_id = expect_parameter("order_id") - pay_params = dict(instance=receiver, - order_id=order_id) + pay_params = dict(instance=receiver, order_id=order_id) pay_status = backend_get("check-payment", pay_params) if pay_status.get("payment_redirect_url"): @@ -235,13 +250,12 @@ def fulfillment(receiver): if pay_status.get("paid"): extra = pay_status["contract_terms"]["extra"] - return flask.render_template( - "templates/fulfillment.html", - donation_receiver=extra["receiver"], - donation_amount=extra["amount"], - donation_donor=extra["donor"], - order_id=order_id, - currency=CURRENCY) + return flask.render_template("templates/fulfillment.html", + donation_receiver=extra["receiver"], + donation_amount=extra["amount"], + donation_donor=extra["donor"], + order_id=order_id, + currency=CURRENCY) # no pay_redirect but article not paid, this should never happen! err_abort(500, message="Internal error, invariant failed", json=pay_status) diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py index 4a44c97..7959ec2 100644 --- a/talerdonations/talerconfig.py +++ b/talerdonations/talerconfig.py @@ -38,17 +38,20 @@ try: except ImportError: pass + ## # Exception class for a any configuration error. class ConfigurationError(Exception): pass + ## # Exception class for malformed strings having with parameter # expansion. class ExpansionSyntaxError(Exception): pass + ## # Do shell-style parameter expansion. # Supported syntax: @@ -80,7 +83,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str: end += 1 if balance != 0: raise ExpansionSyntaxError("unbalanced parentheses") - piece = var[start+2:end-1] + piece = var[start + 2:end - 1] if piece.find(":-") > 0: varname, alt = piece.split(":-", 1) replace = getter(varname) @@ -93,9 +96,9 @@ def expand(var: str, getter: Callable[[str], str]) -> str: replace = var[start:end] else: end = start + 2 - while end < len(var) and var[start+1:end+1].isalnum(): + while end < len(var) and var[start + 1:end + 1].isalnum(): end += 1 - varname = var[start+1:end] + varname = var[start + 1:end] replace = getter(varname) if replace is None: replace = var[start:end] @@ -104,6 +107,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str: return result + var[pos:] + ## # A configuration entry. class Entry: @@ -164,11 +168,14 @@ class Entry: if self.value is None: if warn: if default is not None: - LOGGER.warning("Configuration is missing option '%s' in section '%s',\ - falling back to '%s'", self.option, self.section, default) + LOGGER.warning( + "Configuration is missing option '%s' in section '%s',\ + falling back to '%s'", self.option, + self.section, default) else: - LOGGER.warning("Configuration ** is missing option '%s' in section '%s'", - self.option.upper(), self.section.upper()) + LOGGER.warning( + "Configuration ** is missing option '%s' in section '%s'", + self.option.upper(), self.section.upper()) return default return self.value @@ -190,6 +197,7 @@ class Entry: except ValueError: raise ConfigurationError("Expected number for option '%s' in section '%s'" \ % (self.option.upper(), self.section.upper())) + ## # Fetch value to substitute to expansion variables. # @@ -231,6 +239,7 @@ class Entry: return "" return "%s:%s" % (self.filename, self.lineno) + ## # Represent a section by inheriting from 'defaultdict'. class OptionDict(collections.defaultdict): @@ -280,6 +289,7 @@ class OptionDict(collections.defaultdict): def __setitem__(self, chunk: str, value: Entry) -> None: super().__setitem__(chunk.lower(), value) + ## # Collection of all the (@a OptionDict) sections. class SectionDict(collections.defaultdict): @@ -313,6 +323,7 @@ class SectionDict(collections.defaultdict): def __setitem__(self, chunk: str, value: OptionDict) -> None: super().__setitem__(chunk.lower(), value) + ## # One loaded taler configuration, including base configuration # files and included files. @@ -323,7 +334,7 @@ class TalerConfig: # # @param self the object itself. def __init__(self) -> None: - self.sections = SectionDict() # just plain dict + self.sections = SectionDict() # just plain dict ## # Load a configuration file, instantiating a config object. @@ -465,36 +476,49 @@ class TalerConfig: if line.startswith("@INLINE@"): pair = line.split() if 2 != len(pair): - LOGGER.error("invalid inlined config filename given ('%s')" % line) - continue + LOGGER.error( + "invalid inlined config filename given ('%s')" + % line) + continue if pair[1].startswith("/"): self.load_file(pair[1]) else: - self.load_file(os.path.join(os.path.dirname(filename), pair[1])) + self.load_file( + os.path.join(os.path.dirname(filename), + pair[1])) continue if line.startswith("["): if not line.endswith("]"): - LOGGER.error("invalid section header in line %s: %s", - lineno, repr(line)) + LOGGER.error( + "invalid section header in line %s: %s", + lineno, repr(line)) section_name = line.strip("[]").strip().strip('"') current_section = section_name continue if current_section is None: - LOGGER.error("option outside of section in line %s: %s", lineno, repr(line)) + LOGGER.error( + "option outside of section in line %s: %s", lineno, + repr(line)) continue pair = line.split("=", 1) if len(pair) != 2: - LOGGER.error("invalid option in line %s: %s", lineno, repr(line)) + LOGGER.error("invalid option in line %s: %s", lineno, + repr(line)) key = pair[0].strip() value = pair[1].strip() if value.startswith('"'): value = value[1:] if not value.endswith('"'): - LOGGER.error("mismatched quotes in line %s: %s", lineno, repr(line)) + LOGGER.error("mismatched quotes in line %s: %s", + lineno, repr(line)) else: value = value[:-1] - entry = Entry(self.sections, current_section, key, - value=value, filename=filename, lineno=lineno) + entry = Entry(self.sections, + current_section, + key, + value=value, + filename=filename, + lineno=lineno) sections[current_section][key] = entry except FileNotFoundError: # not logging here, as this interests the final user mostly. @@ -503,23 +527,22 @@ class TalerConfig: ## # Dump the textual representation of a config object. - # + # # Format: - # + # # [section] # option = value # FIXME (what is location?) # # @param self the object itself, that will be dumped. def dump(self) -> None: for kv_section in self.sections.items(): - print("[%s]" % (kv_section[1].section_name,)) + print("[%s]" % (kv_section[1].section_name, )) for kv_option in kv_section[1].items(): print("%s = %s # %s" % \ (kv_option[1].option, kv_option[1].value, kv_option[1].location())) - ## # Return a whole section from this object. # @@ -538,14 +561,26 @@ if __name__ == "__main__": import argparse PARSER = argparse.ArgumentParser() - PARSER.add_argument("--section", "-s", dest="section", - default=None, metavar="SECTION") - PARSER.add_argument("--option", "-o", dest="option", - default=None, metavar="OPTION") - PARSER.add_argument("--config", "-c", dest="config", - default=None, metavar="FILE") - PARSER.add_argument("--filename", "-f", dest="expand_filename", - default=False, action='store_true') + PARSER.add_argument("--section", + "-s", + dest="section", + default=None, + metavar="SECTION") + PARSER.add_argument("--option", + "-o", + dest="option", + default=None, + metavar="OPTION") + PARSER.add_argument("--config", + "-c", + dest="config", + default=None, + metavar="FILE") + PARSER.add_argument("--filename", + "-f", + dest="expand_filename", + default=False, + action='store_true') ARGS = PARSER.parse_args() TC = TalerConfig.from_file(ARGS.config) diff --git a/talerdonations/tests.py b/talerdonations/tests.py index c9918c2..2e95b60 100644 --- a/talerdonations/tests.py +++ b/talerdonations/tests.py @@ -27,6 +27,7 @@ from talerdonations.talerconfig import TalerConfig TC = TalerConfig.from_env() CURRENCY = TC["taler"]["currency"].value_string(required=True) + ## # Main class that gathers all the tests. class DonationsTestCase(unittest.TestCase): -- cgit v1.2.3 From 9c282aa69a4d25f186e591a075b0f2830b5ec45a Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:02:31 +0200 Subject: make pretty --- setup.py | 51 +++++++++-------- talerdonations/donations/donations.py | 100 ++++++++++++++++++++-------------- talerdonations/talerconfig.py | 95 ++++++++++++++++++-------------- 3 files changed, 136 insertions(+), 110 deletions(-) diff --git a/setup.py b/setup.py index 71526a9..906567c 100755 --- a/setup.py +++ b/setup.py @@ -1,28 +1,27 @@ from setuptools import setup, find_packages -setup(name='talerdonations', - version='0.6.0pre1', - description='Example donations site for GNU Taler', - url='git://taler.net/donations', - author=['Marcello Stanisci', 'Florian Dold'], - author_email=['stanisci.m@gmail.com', 'dold@taler.net'], - license='GPL', - packages=find_packages(), - install_requires=["Flask>=0.10", - "requests", - "uwsgi", - "jsmin"], - tests_require=["mock", "nose"], - test_suite="nose.collector", - package_data={ - '':[ - "donations/templates/*.html", - "donations/static/*.svg", - "donations/static/*.css", - "donations/static/web-common/*.png", - "donations/static/web-common/*.css", - "donations/static/web-common/*.html", - ] - }, - scripts=['./bin/taler-merchant-donations'], - zip_safe=False) +setup( + name='talerdonations', + version='0.6.0pre1', + description='Example donations site for GNU Taler', + url='git://taler.net/donations', + author=['Marcello Stanisci', 'Florian Dold'], + author_email=['stanisci.m@gmail.com', 'dold@taler.net'], + license='GPL', + packages=find_packages(), + install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin"], + tests_require=["mock", "nose"], + test_suite="nose.collector", + package_data={ + '': [ + "donations/templates/*.html", + "donations/static/*.svg", + "donations/static/*.css", + "donations/static/web-common/*.png", + "donations/static/web-common/*.css", + "donations/static/web-common/*.html", + ] + }, + scripts=['./bin/taler-merchant-donations'], + zip_safe=False +) diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index 5655734..220fbb7 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -77,9 +77,9 @@ def err_abort(abort_status_code, **params): def backend_get(endpoint, params): headers = {"Authorization": "ApiKey " + APIKEY} try: - resp = requests.get(urljoin(BACKEND_URL, endpoint), - params=params, - headers=headers) + resp = requests.get( + urljoin(BACKEND_URL, endpoint), params=params, headers=headers + ) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: @@ -87,10 +87,12 @@ def backend_get(endpoint, params): except ValueError: err_abort(500, message="Could not parse response from backend") if resp.status_code != 200: - err_abort(500, - message="Backend returned error status", - json=response_json, - status_code=resp.status_code) + err_abort( + 500, + message="Backend returned error status", + json=response_json, + status_code=resp.status_code + ) return response_json @@ -105,22 +107,26 @@ def backend_get(endpoint, params): def backend_post(endpoint, json): headers = {"Authorization": "ApiKey " + APIKEY} try: - resp = requests.post(urljoin(BACKEND_URL, endpoint), - json=json, - headers=headers) + resp = requests.post( + urljoin(BACKEND_URL, endpoint), json=json, headers=headers + ) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: response_json = resp.json() except ValueError: - err_abort(500, - message="Could not parse response from backend", - status_code=resp.status_code) + err_abort( + 500, + message="Could not parse response from backend", + status_code=resp.status_code + ) if resp.status_code != 200: - err_abort(500, - message="Backend returned error status", - json=response_json, - status_code=resp.status_code) + err_abort( + 500, + message="Backend returned error status", + json=response_json, + status_code=resp.status_code + ) return response_json @@ -144,9 +150,11 @@ def expect_parameter(name): # (and execution stack!). @app.errorhandler(Exception) def internal_error(e): - return flask.render_template("templates/error.html", - message="Internal error", - stack=traceback.format_exc()) + return flask.render_template( + "templates/error.html", + message="Internal error", + stack=traceback.format_exc() + ) ## @@ -155,8 +163,9 @@ def internal_error(e): # @return response object of the index page. @app.route("/") def index(): - return flask.render_template("templates/index.html", - merchant_currency=CURRENCY) + return flask.render_template( + "templates/index.html", merchant_currency=CURRENCY + ) ## @@ -179,11 +188,13 @@ def checkout(): amount = expect_parameter("donation_amount") donation_receiver = expect_parameter("donation_receiver") donation_donor = expect_parameter("donation_donor") - return flask.render_template("templates/checkout.html", - donation_amount=amount, - donation_receiver=donation_receiver, - donation_donor=donation_donor, - merchant_currency=CURRENCY) + return flask.render_template( + "templates/checkout.html", + donation_amount=amount, + donation_receiver=donation_receiver, + donation_donor=donation_donor, + merchant_currency=CURRENCY + ) ## @@ -211,14 +222,16 @@ def donate(): payment_system = expect_parameter("payment_system") if payment_system != "taler": return flask.redirect(flask.url_for("provider_not_supported")) - fulfillment_url = flask.url_for("fulfillment", - receiver=donation_receiver, - _external=True) + fulfillment_url = flask.url_for( + "fulfillment", receiver=donation_receiver, _external=True + ) order = dict( amount=donation_amount, - extra=dict(donor=donation_donor, - receiver=donation_receiver, - amount=donation_amount), + extra=dict( + donor=donation_donor, + receiver=donation_receiver, + amount=donation_amount + ), fulfillment_url=fulfillment_url, instance=donation_receiver, summary="Donation to {}".format(donation_receiver), @@ -226,9 +239,10 @@ def donate(): order_resp = backend_post("order", dict(order=order)) order_id = order_resp["order_id"] return flask.redirect( - flask.url_for("fulfillment", - receiver=donation_receiver, - order_id=order_id)) + flask.url_for( + "fulfillment", receiver=donation_receiver, order_id=order_id + ) + ) ## @@ -250,12 +264,14 @@ def fulfillment(receiver): if pay_status.get("paid"): extra = pay_status["contract_terms"]["extra"] - return flask.render_template("templates/fulfillment.html", - donation_receiver=extra["receiver"], - donation_amount=extra["amount"], - donation_donor=extra["donor"], - order_id=order_id, - currency=CURRENCY) + return flask.render_template( + "templates/fulfillment.html", + donation_receiver=extra["receiver"], + donation_amount=extra["amount"], + donation_donor=extra["donor"], + order_id=order_id, + currency=CURRENCY + ) # no pay_redirect but article not paid, this should never happen! err_abort(500, message="Internal error, invariant failed", json=pay_status) diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py index 7959ec2..1a33294 100644 --- a/talerdonations/talerconfig.py +++ b/talerdonations/talerconfig.py @@ -171,11 +171,13 @@ class Entry: LOGGER.warning( "Configuration is missing option '%s' in section '%s',\ falling back to '%s'", self.option, - self.section, default) + self.section, default + ) else: LOGGER.warning( "Configuration ** is missing option '%s' in section '%s'", - self.option.upper(), self.section.upper()) + self.option.upper(), self.section.upper() + ) return default return self.value @@ -373,7 +375,8 @@ class TalerConfig: # a error occurs). def value_string(self, section, option, **kwargs) -> str: return self.sections[section][option].value_string( - kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) + kwargs.get("default"), kwargs.get("required"), kwargs.get("warn") + ) ## # Get a value from the config that should be a filename. @@ -388,7 +391,8 @@ class TalerConfig: # a error occurs). def value_filename(self, section, option, **kwargs) -> str: return self.sections[section][option].value_filename( - kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) + kwargs.get("default"), kwargs.get("required"), kwargs.get("warn") + ) ## # Get a integer value from the config. @@ -402,7 +406,8 @@ class TalerConfig: # a error occurs). def value_int(self, section, option, **kwargs) -> int: return self.sections[section][option].value_int( - kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")) + kwargs.get("default"), kwargs.get("required"), kwargs.get("warn") + ) ## # Load default values from canonical locations. @@ -477,48 +482,58 @@ class TalerConfig: pair = line.split() if 2 != len(pair): LOGGER.error( - "invalid inlined config filename given ('%s')" - % line) + "invalid inlined config filename given ('%s')" % + line + ) continue if pair[1].startswith("/"): self.load_file(pair[1]) else: self.load_file( - os.path.join(os.path.dirname(filename), - pair[1])) + os.path.join( + os.path.dirname(filename), pair[1] + ) + ) continue if line.startswith("["): if not line.endswith("]"): LOGGER.error( - "invalid section header in line %s: %s", - lineno, repr(line)) + "invalid section header in line %s: %s", lineno, + repr(line) + ) section_name = line.strip("[]").strip().strip('"') current_section = section_name continue if current_section is None: LOGGER.error( "option outside of section in line %s: %s", lineno, - repr(line)) + repr(line) + ) continue pair = line.split("=", 1) if len(pair) != 2: - LOGGER.error("invalid option in line %s: %s", lineno, - repr(line)) + LOGGER.error( + "invalid option in line %s: %s", lineno, repr(line) + ) key = pair[0].strip() value = pair[1].strip() if value.startswith('"'): value = value[1:] if not value.endswith('"'): - LOGGER.error("mismatched quotes in line %s: %s", - lineno, repr(line)) + LOGGER.error( + "mismatched quotes in line %s: %s", lineno, + repr(line) + ) else: value = value[:-1] - entry = Entry(self.sections, - current_section, - key, - value=value, - filename=filename, - lineno=lineno) + entry = Entry( + self.sections, + current_section, + key, + value=value, + filename=filename, + lineno=lineno + ) sections[current_section][key] = entry except FileNotFoundError: # not logging here, as this interests the final user mostly. @@ -561,26 +576,22 @@ if __name__ == "__main__": import argparse PARSER = argparse.ArgumentParser() - PARSER.add_argument("--section", - "-s", - dest="section", - default=None, - metavar="SECTION") - PARSER.add_argument("--option", - "-o", - dest="option", - default=None, - metavar="OPTION") - PARSER.add_argument("--config", - "-c", - dest="config", - default=None, - metavar="FILE") - PARSER.add_argument("--filename", - "-f", - dest="expand_filename", - default=False, - action='store_true') + PARSER.add_argument( + "--section", "-s", dest="section", default=None, metavar="SECTION" + ) + PARSER.add_argument( + "--option", "-o", dest="option", default=None, metavar="OPTION" + ) + PARSER.add_argument( + "--config", "-c", dest="config", default=None, metavar="FILE" + ) + PARSER.add_argument( + "--filename", + "-f", + dest="expand_filename", + default=False, + action='store_true' + ) ARGS = PARSER.parse_args() TC = TalerConfig.from_file(ARGS.config) -- cgit v1.2.3 From e7c20a11fac21ab485b17feec81d0887be4cf5eb Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:09:02 +0200 Subject: url-based payments --- talerdonations/donations/donations.py | 26 +++++++- .../donations/templates/request_payment.html | 69 ++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 talerdonations/donations/templates/request_payment.html diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index 220fbb7..06c6617 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -245,6 +245,16 @@ def donate(): ) +## +# This endpoint is used by the payment request page +# to check if the payment has been completed via the QR code. +@app.route("/check-status/") +def check_status(order_id, session_id): + pay_params = dict( instance=INSTANCE, order_id=order_id) + pay_status = backend_get("check-payment", pay_params) + return flask.jsonify(paid=pay_status["paid"]) + + ## # Serve the fulfillment page. # @@ -260,7 +270,21 @@ def fulfillment(receiver): pay_status = backend_get("check-payment", pay_params) if pay_status.get("payment_redirect_url"): - return flask.redirect(pay_status["payment_redirect_url"]) + taler_pay_uri = pay_status["taler_pay_uri"] + qrcode_svg = get_qrcode_svg(taler_pay_uri) + check_status_url_enc = urllib.parse.quote( + flask.url_for("check_status", order_id=order_id) + ) + content = flask.render_template( + "templates/request_payment.html", + article_name=article_name, + taler_pay_uri=taler_pay_uri, + qrcode_svg=qrcode_svg, + check_status_url_enc=check_status_url_enc + ) + headers = {"Taler": taler_pay_uri} + resp = flask.Response(content, status=402, headers=headers) + return resp if pay_status.get("paid"): extra = pay_status["contract_terms"]["extra"] diff --git a/talerdonations/donations/templates/request_payment.html b/talerdonations/donations/templates/request_payment.html new file mode 100644 index 0000000..6e050d0 --- /dev/null +++ b/talerdonations/donations/templates/request_payment.html @@ -0,0 +1,69 @@ +{% extends "templates/base.html" %} + + +{% block meta %} + +{% endblock meta %} + + +{% block scripts %} + +{% endblock scripts %} + + +{% block main %} + +

Payment Required

+ +
+

+ Looks like your browser doesn't support GNU Taler payments. You can try + installing a wallet browser extension. +

+
+ +
+ +

+ You can use this QR code to pay with your mobile wallet: +

+ + {{ qrcode_svg | safe }} + +

+ Click this link to open your system's Taler wallet if it exists. +

+ +
+ +{% endblock main %} -- cgit v1.2.3 From e50d7d0a57dced455f93b0f462e48065a1f0b764 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:10:24 +0200 Subject: add missing files --- .gitignore | 10 ---- Makefile | 40 +++++++++++++++ bin/taler-merchant-donations | 116 +++++++++++++++++++++++++++++++++++++++++++ configure | 87 ++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 10 deletions(-) create mode 100644 Makefile create mode 100644 bin/taler-merchant-donations create mode 100755 configure diff --git a/.gitignore b/.gitignore index a0630f3..17e4b20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,6 @@ doxygen-doc/ .eggs/ -Makefile -aclocal.m4 -autom4te.cache/ compile -config.log -config.status -configure -frontend-donations.wsgi -install-sh -missing -taler-merchant-donations talerdonations.egg-info/ talerdonations/__pycache__/ talerdonations/donations/__pycache__/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1d98268 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +install_global=false +-include config.mk + +.PHONY: all +all: + @echo "This is a python project, no compilation required" + +.PHONY: install + +ifeq ($(install_global), true) +install: install-global +else +install: install-local +endif + +.PHONY: install-global +install-global: + pip3 install . + +.PHONY: install-local +install-local: + pip3 install . --user + +# run testcases +.PHONY: check +check: + @export TALER_CONFIG_FILE=talerblog/tests.conf; \ + python3 setup.py test + +.PHONY: clean +clean: + @echo nothing to do + +.PHONY: dist +dist: + git archive --format=tar.gz HEAD -o taler-merchant-donations.tar.gz + +.PHONY: pretty +pretty: + yapf -r -i talerdonations/ diff --git a/bin/taler-merchant-donations b/bin/taler-merchant-donations new file mode 100644 index 0000000..0bda611 --- /dev/null +++ b/bin/taler-merchant-donations @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +## +# This file is part of TALER +# (C) 2017 INRIA +# +# TALER is free software; you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public +# License as published by the Free Software Foundation; either +# version 3, or (at your option) any later version. +# +# TALER 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 TALER; see the file COPYING. If not, +# see +# +# @author Florian Dold +# @file Standalone script to run the donations site. + +import argparse +import sys +import os +import site +import logging +from talerdonations.talerconfig import TalerConfig + +# No perfect match to our logging format, but good enough ... +UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)" + + +## +# This function interprets the 'serve-http' subcommand. +# The effect it to launch the donations HTTP service. +# +# @param args command line options. +def handle_serve_http(args): + port = args.port + if port is None: + port = TC["donations"]["http_port"].value_int(required=True) + spec = ":%d" % (port, ) + os.execlp( + "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format", + UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations" + ) + + +## +# This function interprets the 'serve-uwsgi' subcommand. +# The effect is to launch the donations UWSGI service. This +# type of service is usually used when the HTTP donations interface +# is accessed via a reverse proxy (like Nginx, for example). +# +# @param command line options. +def handle_serve_uwsgi(args): + del args # pacify PEP checkers + serve_uwsgi = TC["donations"]["uwsgi_serve"].value_string(required=True + ).lower() + params = [ + "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format", + UWSGI_LOGFMT, "--module", "talerdonations" + ] + if serve_uwsgi == "tcp": + port = TC["donations"]["uwsgi_port"].value_int(required=True) + spec = ":%d" % (port, ) + params.extend(["--socket", spec]) + elif serve_uwsgi == "unix": + spec = TC["donations"]["uwsgi_unixpath"].value_filename(required=True) + mode = TC["donations"]["uwsgi_unixpath_mode"].value_filename( + required=True + ) + params.extend(["--socket", spec]) + params.extend(["--chmod-socket=" + mode]) + os.makedirs(os.path.dirname(spec), exist_ok=True) + logging.info("launching uwsgi with argv %s", params[1:]) + os.execlp(*params) + + +## @cond +PARSER = argparse.ArgumentParser() +PARSER.set_defaults(func=None) +PARSER.add_argument( + '--config', + '-c', + help="configuration file to use", + metavar="CONFIG", + type=str, + dest="config", + default=None +) +SUB = PARSER.add_subparsers() + +P = SUB.add_parser('serve-http', help="Serve over HTTP") +P.add_argument( + "--port", "-p", dest="port", type=int, default=None, metavar="PORT" +) +P.set_defaults(func=handle_serve_http) + +P = SUB.add_parser('serve-uwsgi', help="Serve over UWSGI") +P.set_defaults(func=handle_serve_uwsgi) + +ARGS = PARSER.parse_args() +## @endcond + +if getattr(ARGS, 'func', None) is None: + PARSER.print_help() + sys.exit(1) + +if ARGS.config is not None: + os.environ["TALER_CONFIG_FILE"] = ARGS.config + +TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE")) +ARGS.func(ARGS) diff --git a/configure b/configure new file mode 100755 index 0000000..469bad7 --- /dev/null +++ b/configure @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +set -eu + +usage() { + echo "Usage: ./configure [OPTION]" + echo + echo "Configuration:" + echo " -h, --help display this help and exit" + echo + echo "Installation directories:" + echo " --destination=[local|global] install Python package locally or globally" +} + + +# -allow a command to fail with !’s side effect on errexit +# -use return value from ${PIPESTATUS[0]}, because ! hosed $? +! getopt --test > /dev/null +if [[ ${PIPESTATUS[0]} -ne 4 ]]; then + echo 'getopt not available' + exit 1 +fi + +LONGOPTS=destination:,help +OPTIONS=h + +! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") +if [[ ${PIPESTATUS[0]} -ne 0 ]]; then + # e.g. return value is 1 + # then getopt has complained about wrong arguments to stdout + exit 2 +fi + +# read getopt’s output this way to handle the quoting right: +eval set -- "$PARSED" + +destination="local" + +while true; do + case "$1" in + --destination) + destination="$2" + shift 2 + ;; + -h|--help) + usage + exit 1 + ;; + --) + shift + break + ;; + *) + echo "Programming error" + exit 3 + ;; + esac +done + +case "$destination" in + local) + install_global=false + ;; + global) + install_global=true + ;; + *) + echo "Destination (--destination) must be 'local' or 'global', paths are not allowed." + exit 3 + ;; +esac + +cat << EOF > config.mk +# this file is autogenerated by ./configure +install_global=$install_global +EOF + + +if ! python3 --version &>/dev/null; then + echo 'Error: python3 missing' + exit 1 +fi + +if ! pip3 --version &>/dev/null; then + echo 'Error: pip3 missing' + exit 1 +fi -- cgit v1.2.3 From 31a05eaab426a6121a93945f1f2e08a686987560 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:10:43 +0200 Subject: make pretty --- talerdonations/donations/donations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index 06c6617..886705f 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -250,7 +250,7 @@ def donate(): # to check if the payment has been completed via the QR code. @app.route("/check-status/") def check_status(order_id, session_id): - pay_params = dict( instance=INSTANCE, order_id=order_id) + pay_params = dict(instance=INSTANCE, order_id=order_id) pay_status = backend_get("check-payment", pay_params) return flask.jsonify(paid=pay_status["paid"]) -- cgit v1.2.3 From c75c8b0dc295a7278b5c6ba26cea9bbdb771789c Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:11:55 +0200 Subject: no more wallet detection --- talerdonations/donations/templates/index.html | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/talerdonations/donations/templates/index.html b/talerdonations/donations/templates/index.html index fc956e5..68a0cb2 100644 --- a/talerdonations/donations/templates/index.html +++ b/talerdonations/donations/templates/index.html @@ -7,22 +7,7 @@ You are paying with an imaginary currency ({{ merchant_currency }}).

-
-

Installing the Taler wallet

- First, you need to install the Taler wallet browser extension. - Install the wallet - - - Wallets for other browsers will be provided in the near future. -
- -
+

Please select a project, the amount (*) of {{ merchant_currency }} you wish to donate, and enter the name that will appear on your receipt:

-- cgit v1.2.3 From 06bf80ca7326e9e1c72b27cb4734f9eefc20f68e Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:13:16 +0200 Subject: no more redirect URL --- talerdonations/donations/donations.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index 886705f..d4dd36d 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -269,7 +269,18 @@ def fulfillment(receiver): pay_params = dict(instance=receiver, order_id=order_id) pay_status = backend_get("check-payment", pay_params) - if pay_status.get("payment_redirect_url"): + + if pay_status.get("paid"): + extra = pay_status["contract_terms"]["extra"] + return flask.render_template( + "templates/fulfillment.html", + donation_receiver=extra["receiver"], + donation_amount=extra["amount"], + donation_donor=extra["donor"], + order_id=order_id, + currency=CURRENCY + ) + else: taler_pay_uri = pay_status["taler_pay_uri"] qrcode_svg = get_qrcode_svg(taler_pay_uri) check_status_url_enc = urllib.parse.quote( @@ -286,16 +297,5 @@ def fulfillment(receiver): resp = flask.Response(content, status=402, headers=headers) return resp - if pay_status.get("paid"): - extra = pay_status["contract_terms"]["extra"] - return flask.render_template( - "templates/fulfillment.html", - donation_receiver=extra["receiver"], - donation_amount=extra["amount"], - donation_donor=extra["donor"], - order_id=order_id, - currency=CURRENCY - ) - # no pay_redirect but article not paid, this should never happen! err_abort(500, message="Internal error, invariant failed", json=pay_status) -- cgit v1.2.3 From 8ef2843d05d57c07115dba494cc913efc3f19014 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:15:09 +0200 Subject: qrcode --- setup.py | 2 +- talerdonations/donations/donations.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 906567c..042635f 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( author_email=['stanisci.m@gmail.com', 'dold@taler.net'], license='GPL', packages=find_packages(), - install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin"], + install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin", "qrcode", "lxml"], tests_require=["mock", "nose"], test_suite="nose.collector", package_data={ diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index d4dd36d..c00844b 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -26,6 +26,9 @@ import random import requests import flask import traceback +import qrcode +import qrcode.image.svg +import lxml.etree from ..talerconfig import TalerConfig LOGGER = logging.getLogger(__name__) @@ -255,6 +258,12 @@ def check_status(order_id, session_id): return flask.jsonify(paid=pay_status["paid"]) +def get_qrcode_svg(data): + factory = qrcode.image.svg.SvgImage + img = qrcode.make(data, image_factory=factory) + return lxml.etree.tostring(img.get_image()).decode("utf-8") + + ## # Serve the fulfillment page. # -- cgit v1.2.3 From cdd70817d77265a897e4efb1fed22e66e2c99ce9 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:15:58 +0200 Subject: urllib --- talerdonations/donations/donations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index c00844b..21eb76a 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -26,6 +26,7 @@ import random import requests import flask import traceback +import urllib import qrcode import qrcode.image.svg import lxml.etree -- cgit v1.2.3 From b38365fa582a52592d00f36e8dee2ee9bfca9ee6 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 19:16:45 +0200 Subject: I want static typing --- talerdonations/donations/donations.py | 1 - 1 file changed, 1 deletion(-) diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py index 21eb76a..d85c9a9 100644 --- a/talerdonations/donations/donations.py +++ b/talerdonations/donations/donations.py @@ -298,7 +298,6 @@ def fulfillment(receiver): ) content = flask.render_template( "templates/request_payment.html", - article_name=article_name, taler_pay_uri=taler_pay_uri, qrcode_svg=qrcode_svg, check_status_url_enc=check_status_url_enc -- cgit v1.2.3 From d61ff48aa5d4c0c5642e885eadc8e3fcf1e06366 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sat, 31 Aug 2019 16:19:02 +0200 Subject: fix test case invocation --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1d98268..6622526 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ install-local: # run testcases .PHONY: check check: - @export TALER_CONFIG_FILE=talerblog/tests.conf; \ + @export TALER_CONFIG_FILE=talerdonations/tests.conf; \ python3 setup.py test .PHONY: clean -- cgit v1.2.3 From 38acb9f039fb01a7bc0aef8b93a277e919899ae9 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sat, 31 Aug 2019 16:59:04 +0200 Subject: use correct WSGI module --- bin/taler-merchant-donations | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/taler-merchant-donations b/bin/taler-merchant-donations index 0bda611..ccf6a4e 100644 --- a/bin/taler-merchant-donations +++ b/bin/taler-merchant-donations @@ -44,7 +44,7 @@ def handle_serve_http(args): spec = ":%d" % (port, ) os.execlp( "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format", - UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations" + UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations.donations:app" ) @@ -61,7 +61,7 @@ def handle_serve_uwsgi(args): ).lower() params = [ "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format", - UWSGI_LOGFMT, "--module", "talerdonations" + UWSGI_LOGFMT, "--module", "talerdonations.donations:app" ] if serve_uwsgi == "tcp": port = TC["donations"]["uwsgi_port"].value_int(required=True) -- cgit v1.2.3