sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit faeb889812e7a92ac50db695dd2a18aaa71e13cb
parent e6b00b95b91ff20f13eff9e0442c2ff3281a42c2
Author: Iván Ávalos <avalos@disroot.org>
Date:   Fri,  2 Oct 2026 12:05:12 +0200

CI: build libmicrohttpd2 from source and extend the jobs

Diffstat:
Acontrib/check-db-naming.py | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcontrib/ci/Containerfile | 19+++++++++++++++++--
Acontrib/ci/debian-package-job.sh | 28++++++++++++++++++++++++++++
Acontrib/ci/jobs/0-db-naming/config.ini | 6++++++
Acontrib/ci/jobs/0-db-naming/job.sh | 4++++
Mcontrib/ci/jobs/1-build/build.sh | 5++++-
Mcontrib/ci/jobs/2-test/1-build.sh | 5+++++
Mcontrib/ci/jobs/4-deb-package/job.sh | 25+------------------------
Dcontrib/ci/jobs/4-deb-package/version.sh | 6------
9 files changed, 197 insertions(+), 33 deletions(-)

diff --git a/contrib/check-db-naming.py b/contrib/check-db-naming.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +"""Enforce the sync database layer naming conventions. + +Adapted from the equivalent checker in the exchange repository +(contrib/check-db-naming.py) to the conventions used by sync's syncdb: + + 1. every implementation file syncdb_<X>.c defines a function named + SYNCDB_<X>, and a matching header <X>.h exists in the public + include directory declaring exactly that function + 2. the stem <X> starts with one of the approved operation prefixes, + or the file is exempt (internal modules, standalone tools) + 3. a .sql file (if any) belongs to the file it is named after + 4. every prepared statement is unique across all implementation files + 5. no numeric suffixes on stems + 6. no repeated 'syncdb'/'SYNCDB' library prefix anywhere + +Run from the top of the source tree; exits non-zero on any violation. +""" +import re +import sys +import pathlib + +IMPL_DIR = pathlib.Path("src/syncdb") +HDR_DIR = pathlib.Path("src/include/sync/sync-database") + +PREFIX = "SYNCDB_" + +# Approved operation prefixes for the part of the file name after +# 'syncdb_' (e.g. syncdb_lookup_account_TR.c -> 'lookup_account_TR'). +PREFIXES = ( + "append_", "delete_", "update_", "lookup_", "store_", "increment_", + "create_", "drop_", "preflight_", +) + +# Exact stems (without the 'syncdb_' prefix) that are not operations. +EXACT = { + "gc", +} + +# Files that are not part of the API surface at all. +SKIP = {"pg", "sync-dbinit"} + +PREP = re.compile(r'PREPARE\s*\(\s*\w+\s*,\s*"([A-Za-z0-9_]+)"', re.S) +DECL = re.compile(r"^" + re.escape(PREFIX) + r"(\w+)\s*\(", re.M) + +errors = [] + + +def check(): + if not IMPL_DIR.is_dir(): + return + stmt_owner = {} + + for c in sorted(IMPL_DIR.glob("*.c")): + stem = c.stem + if stem in SKIP or stem.startswith("test_"): + continue + if stem.startswith("syncdb_"): + body = stem[len("syncdb_"):] + else: + body = stem + + # 2. approved prefix, or exempt + if (not body.startswith(PREFIXES) + and body not in EXACT): + errors.append(f"{c}: '{body}' uses no approved prefix") + + # 5. numeric suffix + if re.search(r"\d$", body): + errors.append(f"{c}: '{body}' ends in a digit") + + h = HDR_DIR / (body + ".h") + + # 1a. matching header + if not h.exists(): + errors.append(f"{c}: no matching header {h}") + else: + names = DECL.findall(h.read_text(errors="replace")) + # 1b. the header declares exactly the function of this file + if names != [body]: + errors.append( + f"{h}: declares {names}, expected exactly ['{body}']") + + text = c.read_text(errors="replace") + + # 1c. the file defines its function + if not re.search(r"^" + re.escape(PREFIX + body) + r"\s*\(", text, + re.M): + errors.append(f"{c}: does not define {PREFIX}{body}") + + # 3. a .sql file shares the name + sql = c.with_suffix(".sql") + if sql.exists() and sql.stem != stem: + errors.append(f"{c}: .sql file {sql} does not share the name") + + # 4. prepared statement uniqueness + for s in dict.fromkeys(PREP.findall(text)): + if s in stmt_owner and stmt_owner[s] != str(c): + errors.append( + f"{c}: prepared statement '{s}' also prepared in " + f"{stmt_owner[s]}") + stmt_owner[s] = str(c) + + # Also check .sql files that are not covered by a .c file: they must + # either belong to a .c file or be one of the schema/fragment files. + covered = set() + for c in IMPL_DIR.glob("syncdb_*.c"): + covered.add(c.stem) + for s in IMPL_DIR.glob("syncdb_*.sql"): + if s.stem in covered: + continue + if s.stem not in ("procedures",): + errors.append( + f"{s}: .sql file without a matching .c and not 'procedures'") + + # 6. repeated library prefix anywhere in the tree + for f in list(IMPL_DIR.glob("*.[ch]")) + list(HDR_DIR.glob("*.h")): + if "unc-backup" in f.name: + continue + if re.search(r"\bSYNCDB_syncdb\b|\bsyncdb_syncdb\b", f.read_text( + errors="replace")): + errors.append(f"{f}: repeated 'sync[d]b' prefix") + + +for e in errors: + print("ERROR:", e) +print(f"\ndb-naming: {len(errors)} violation(s)") +sys.exit(1 if errors else 0) + + +if __name__ == "__main__": + check() diff --git a/contrib/ci/Containerfile b/contrib/ci/Containerfile @@ -9,6 +9,7 @@ RUN apt-get update -yqq && \ meson \ libjansson-dev \ libgcrypt-dev \ + libgnutls28-dev \ libqrencode-dev \ libpq-dev \ pkg-config \ @@ -32,7 +33,22 @@ RUN apt-get install -yqq \ build-essential \ debhelper-compat \ devscripts \ - git-buildpackage + git-buildpackage \ + autoconf \ + automake + +# Debian does not (yet) package libmicrohttpd2, so build it from source. +# Pinned to a specific revision of git.gnunet.org/libmicrohttpd2. +RUN git clone https://git.gnunet.org/libmicrohttpd2.git /tmp/libmicrohttpd2 \ + && cd /tmp/libmicrohttpd2 \ + && git checkout 24a2913c4e1cb31a5cff52047beae146959d50b0 \ + && ./bootstrap \ + && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu \ + --disable-doc --disable-examples \ + && make -j"$(nproc)" \ + && make install \ + && ldconfig \ + && rm -rf /tmp/libmicrohttpd2 # Install docs generation utils RUN apt-get update -yqq && \ @@ -51,7 +67,6 @@ Package: * \n\ Pin: origin "deb.taler.net" \n\ Pin-Priority: 999' > /etc/apt/preferences.d/taler -# FIXME: we need libeufin-bank here for the CI to work! RUN cat /etc/apt/preferences.d/taler && \ apt-get update -y && \ apt-get install -y \ diff --git a/contrib/ci/debian-package-job.sh b/contrib/ci/debian-package-job.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -exuo pipefail +# This file is in the public domain. +# Helper script to build the latest DEB packages in the container. +# Shared between various jobs. + +unset LD_LIBRARY_PATH + +# Install build-time dependencies. +# Update apt cache first +apt-get update +apt-get upgrade -y +mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control + +# Sanity-check the version generation logic before deriving the package version. +python3 contrib/ci/test_version.py + +VERSION="$(./contrib/ci/version.sh)" +export VERSION +: "${VERSION:?version generation returned an empty version}" +echo "Building package version ${VERSION}" +EMAIL=none gbp dch --dch-opt=-b --ignore-branch --debian-tag="%(version)s" --git-author --new-version="${VERSION}" +./bootstrap +dpkg-buildpackage -rfakeroot -b -uc -us + +ls -alh ../*.deb +mkdir -p /artifacts/sync/${CI_COMMIT_REF} # Variable comes from CI environment +mv ../*.deb /artifacts/sync/${CI_COMMIT_REF}/ diff --git a/contrib/ci/jobs/0-db-naming/config.ini b/contrib/ci/jobs/0-db-naming/config.ini @@ -0,0 +1,6 @@ +[build] +HALT_ON_FAILURE = True +WARN_ON_FAILURE = True +CONTAINER_BUILD = False +CONTAINER_NAME = localhost/sync +CONTAINER_ARCH = amd64 diff --git a/contrib/ci/jobs/0-db-naming/job.sh b/contrib/ci/jobs/0-db-naming/job.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -exuo pipefail + +exec ./contrib/check-db-naming.py diff --git a/contrib/ci/jobs/1-build/build.sh b/contrib/ci/jobs/1-build/build.sh @@ -7,4 +7,7 @@ set -exuo pipefail --enable-logging=verbose \ --disable-doc -make +# New container, may contain old build artifacts +make clean +nump=$(grep processor /proc/cpuinfo | wc -l) +make -j$(( $nump / 2 )) diff --git a/contrib/ci/jobs/2-test/1-build.sh b/contrib/ci/jobs/2-test/1-build.sh @@ -10,3 +10,8 @@ apt-get upgrade -yqq --enable-coverage \ --enable-logging=verbose \ --disable-doc + +# New container, may contain old build artifacts +make clean +nump=$(grep processor /proc/cpuinfo | wc -l) +make -j$(( $nump / 2 )) diff --git a/contrib/ci/jobs/4-deb-package/job.sh b/contrib/ci/jobs/4-deb-package/job.sh @@ -1,25 +1,2 @@ #!/bin/bash -set -exuo pipefail -# This file is in the public domain. -# Helper script to build the latest DEB packages in the container. - - -unset LD_LIBRARY_PATH - -# Install build-time dependencies. -# Update apt cache first -apt-get update -apt-get upgrade -y -mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control - -VERSION="$(./contrib/ci/jobs/4-deb-package/version.sh)" -export VERSION -: "${VERSION:?version generation returned an empty version}" -echo "Building package version ${VERSION}" -EMAIL=none gbp dch --dch-opt=-b --ignore-branch --debian-tag="%(version)s" --git-author --new-version="${VERSION}" -./bootstrap -dpkg-buildpackage -rfakeroot -b -uc -us - -ls -alh ../*.deb -mkdir -p /artifacts/sync/${CI_COMMIT_REF} # Variable comes from CI environment -mv ../*.deb /artifacts/sync/${CI_COMMIT_REF}/ +exec ./contrib/ci/debian-package-job.sh diff --git a/contrib/ci/jobs/4-deb-package/version.sh b/contrib/ci/jobs/4-deb-package/version.sh @@ -1,6 +0,0 @@ -#!/bin/sh -# This file is in the public domain. -# Compatibility entry point, also usable in generated job directories. -set -eu -repo_dir=$(git rev-parse --show-toplevel) -exec "$repo_dir/contrib/ci/version.sh" "$@"