diff --git a/.gitignore b/.gitignore
index ba96765..7a5a921 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,7 @@ pom.xml.next
pom.xml.releaseBackup
pom.xml.tag
release.properties
+
+# Python-based code generator
+venv/
+.python-version
diff --git a/codegen.py b/codegen.py
new file mode 100644
index 0000000..9f1008e
--- /dev/null
+++ b/codegen.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python3
+# Copyright 2021 Barend Garvelink
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Code generator for the country codes file.
+"""
+import os
+import json
+from pathlib import Path
+
+from jinja2 import FileSystemLoader, Environment
+from yaml import safe_load as yaml_load
+
+
+def expand_templates(basedir: Path, context: dict):
+ template_dir = basedir.joinpath("src/main/jinja2")
+ target_dir = basedir.joinpath("target/generated-sources/jinja2")
+
+ def flat_get(obj, path: str, def_val=None):
+ for elem in path.split("."):
+ if elem not in obj:
+ return def_val if def_val is not None else environment.undefined(name=f"'{path}' (at '{elem}')")
+ obj = obj[elem]
+ return obj
+
+ environment = Environment(loader=FileSystemLoader(template_dir), autoescape=False)
+ environment.filters["date_time_format"] = lambda dt, pat: dt.strftime(pat)
+ environment.filters["escape_java_string"] = lambda s: json.dumps(s).strip("\"")
+ environment.filters["flat_get"] = flat_get
+
+ for template in environment.list_templates():
+ template_path = Path(template)
+ output_path = Path(target_dir).joinpath(template_path.parent)
+ output_path.mkdir(parents=True, exist_ok=True)
+ output_fqfn = output_path.joinpath(template_path.with_suffix("").name)
+ with open(output_fqfn, "w") as outfile:
+ print(f"Render {template} to {output_fqfn}")
+ print(environment.get_template(template).render(context), file=outfile)
+
+
+def load_context(basedir: Path) -> dict:
+ data_file = basedir.joinpath("src/main/resources/nl/garvelink/iban/IBAN.yml")
+ with open(data_file, "r") as df:
+ return yaml_load(df)
+
+
+if __name__ == "__main__":
+ basedir = Path(os.getcwd())
+ context = load_context(basedir)
+ expand_templates(basedir, context)
diff --git a/codegen.sh b/codegen.sh
new file mode 100755
index 0000000..2060f0f
--- /dev/null
+++ b/codegen.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -eu
+
+if [ ! -d "venv" ]; then
+ /usr/bin/env python3 -m venv venv
+fi
+venv/bin/pip3 install --progress-bar off --require-hashes -r requirements.txt
+venv/bin/python codegen.py
diff --git a/docs/index.md b/docs/index.md
index 69eb09e..f870719 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -107,6 +107,11 @@ Obtain an `IBAN` instance using one of the static factory methods: `valueOf( )`
### Version History
+#### 1.9.1: Unreleased
+* Drop `template-maven-plugin`. It has proven to make the CI build very flaky. This also removes the build-time
+ dependency on a third-party artifact repository. The downside is that the build now requires Python 3 and a bourne
+ shell. It builds on WSL2 just fine, but I have no idea how to build this natively on Windows.
+
#### 1.9.0: 3 April 2021
* Compatible change: utility functions in `CountryCodes` now accept `java.lang.CharSequence` (was String).
* New API method: `IBAN.compose(CharSequence, CharSequence)`.
diff --git a/pom.xml b/pom.xml
index 6c6301c..15734b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,56 +83,23 @@
1.8
-
-
-
- central
- Central Repository
- https://repo.maven.apache.org/maven2
-
-
-
- jitpack.io
- https://jitpack.io
-
-
-
-
- template-maven-plugin
- com.github.terefang.template
- 2021.4.28
-
-
- generate-code
- generate-sources
-
- jinjava-standard
-
-
- src/main/resources/nl/garvelink/iban/IBAN.yml
- src/main/jinjava/
- ${project.build.directory}/generated-sources/jinjava
-
-
-
-
org.codehaus.mojo
- build-helper-maven-plugin
- 3.2.0
+ exec-maven-plugin
+ 3.0.0
- include-extra-sources-dir
+ generate-code
generate-sources
- add-source
+ exec
-
- ${project.build.directory}/generated-sources/jinjava
-
+ codegen.sh
+ ${project.build.directory}/generated-sources/jinja2
+ true
@@ -236,7 +203,7 @@
${project.basedir}/src/main/java11
- ${project.build.directory}/generated-sources/jinjava
+ ${project.build.directory}/generated-sources/jinja2
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..d6f8740
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,6 @@
+Jinja2==3.0.1 \
+ --hash=sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4
+MarkupSafe==2.0.1 \
+ --hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a
+PyYAML==5.4.1 \
+ --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e
diff --git a/src/main/jinjava/nl/garvelink/iban/CountryCodesData.java.j2 b/src/main/jinja2/nl/garvelink/iban/CountryCodesData.java.j2
similarity index 77%
rename from src/main/jinjava/nl/garvelink/iban/CountryCodesData.java.j2
rename to src/main/jinja2/nl/garvelink/iban/CountryCodesData.java.j2
index c95e35a..bd25b24 100755
--- a/src/main/jinjava/nl/garvelink/iban/CountryCodesData.java.j2
+++ b/src/main/jinja2/nl/garvelink/iban/CountryCodesData.java.j2
@@ -21,17 +21,17 @@ import java.util.Collections;
/**
* Contains information about IBAN country codes. This is a generated file.
- * Updated to SWIFT IBAN Registry version {{ context.meta.iban_registry_version | escape }} on {{ context.meta.last_update | datetimeformat("%Y-%m-%d") | escape }}.
+ * Updated to SWIFT IBAN Registry version {{ meta.iban_registry_version | escape }} on {{ meta.last_update | date_time_format("%Y-%m-%d") | escape }}.
*/
abstract class CountryCodesData {
/**
* The "yyyy-MM-dd" datestamp that the embedded IBAN data was updated.
*/
- static final String LAST_UPDATE_DATE = "{{ context.meta.last_update | datetimeformat("%Y-%m-%d") | escapejson }}";
+ static final String LAST_UPDATE_DATE = "{{ meta.last_update | date_time_format("%Y-%m-%d") | escape_java_string }}";
/**
* The revision of the SWIFT IBAN Registry to which the embedded IBAN data was updated.
*/
- static final String LAST_UPDATE_REV = "{{ context.meta.iban_registry_version | escapejson }}";
+ static final String LAST_UPDATE_REV = "{{ meta.iban_registry_version | escape_java_string }}";
static final int SEPA = 1 << 8;
static final int SWIFT = 1 << 9;
@@ -44,12 +44,12 @@ abstract class CountryCodesData {
static final int BRANCH_IDENTIFIER_END_SHIFT = 24;
static final int BRANCH_IDENTIFIER_END_MASK = 0xFF << BRANCH_IDENTIFIER_END_SHIFT;
-/**
+ /**
* Known country codes, this list must be sorted to allow binary search. All other lists in this file must use the
* same indices for the same countries.
*/
static final String[] COUNTRY_CODES = {
-{%- for iban in context.ibans %}
+{%- for iban in ibans %}
"{{ iban.country_code }}"{% if not loop.last %},{% endif %}{#
#}{% endfor %}
};
@@ -60,7 +60,7 @@ abstract class CountryCodesData {
* whether the record is listed in the SWIFT IBAN Registry.
*/
static final int[] COUNTRY_IBAN_LENGTHS = {
-{%- for iban in context.ibans %}
+{%- for iban in ibans %}
/* {{ iban.country_code }} */ {{ iban.length }}{% if iban.flags.in_swift_registry %} | SWIFT{% endif %}{% if iban.flags.sepa_country %} | SEPA{% endif %}{#
#}{% if not loop.last %},{% endif %}{#
#}{% endfor %}
@@ -78,12 +78,12 @@ abstract class CountryCodesData {
*
*/
static final int[] BANK_CODE_BRANCH_CODE = {
-{%- for iban in context.ibans %}
+{%- for iban in ibans %}
/* {{ iban.country_code }} */
- {{ iban.embeds.bank_code.position | default(0) }}
- | ({{ iban.embeds.bank_code.position | default(0) }} + {{ iban.embeds.bank_code.length | default(0) }}) << BANK_IDENTIFIER_END_SHIFT
- | {{ iban.embeds.branch_code.position | default(0) }} << BRANCH_IDENTIFIER_BEGIN_SHIFT
- | ({{ iban.embeds.branch_code.position | default(0) }} + {{ iban.embeds.branch_code.length | default(0) }}) << BRANCH_IDENTIFIER_END_SHIFT{#
+ {{ iban | flat_get("embeds.bank_code.position", 0) }}
+ | ({{ iban | flat_get("embeds.bank_code.position", 0) }} + {{ iban | flat_get("embeds.bank_code.length", 0) }}) << BANK_IDENTIFIER_END_SHIFT
+ | {{ iban | flat_get("embeds.branch_code.position", 0) }} << BRANCH_IDENTIFIER_BEGIN_SHIFT
+ | ({{ iban | flat_get("embeds.branch_code.position", 0) }} + {{ iban | flat_get("embeds.branch_code.length", 0) }}) << BRANCH_IDENTIFIER_END_SHIFT{#
#}{% if not loop.last %},{% endif %}
{% endfor %}
};