commit 1f15734ef02be33e4a4d8634ea6245c686b98781
parent ab409323e606702ecd4b23a3e3db0d679c9b90e8
Author: Florian Dold <dold@taler.net>
Date: Sun, 9 Aug 2026 21:47:53 +0200
inline and simplify build system
Diffstat:
9 files changed, 230 insertions(+), 70 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -18,9 +18,6 @@ configure
*.swp
.idea/
-# old folder
-build-scripts/
-
# Git worktree of pre-built wallet files
prebuilt/
diff --git a/.gitmodules b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "build-scripts"]
- path = build-system/taler-build-scripts
- url = ../build-common
[submodule "contrib/wallet-testdata"]
path = contrib/wallet-testdata
url = ../wallet-testdata.git
diff --git a/Makefile b/Makefile
@@ -1,10 +1,9 @@
# This Makefile has been placed in the public domain.
-tsc = node_modules/typescript/bin/tsc
-pogen = node_modules/@gnu-taler/pogen/bin/pogen.js
-ava = node_modules/.bin/ava
-c8 = pnpm --filter @gnu-taler/qa-tooling exec c8
-git-archive-all = ./build-system/taler-build-scripts/archive-with-submodules/git_archive_all.py
+archive = ./build-system/archive.py
+configurable-packages = $(patsubst %/,%,$(dir $(wildcard packages/*/Makefile)))
+configure-files = configure $(addsuffix /configure,$(configurable-packages))
+archive-includes = $(addprefix --include ,$(configure-files))
include .config.mk
@@ -21,19 +20,14 @@ build:
.PHONY: dist
dist:
- $(git-archive-all) \
- --include ./configure \
- --include ./packages/taler-wallet-cli/configure \
- --include ./packages/anastasis-cli/configure \
- --include ./packages/libeufin-bank-webui/configure \
- --include ./packages/taler-harness/configure \
- --include ./packages/taler-merchant-webui/configure \
- taler-typescript-core-$(shell git describe --tags --abbrev=0 | sed -e 's/^v//').tar.gz
+ $(archive) $(archive-includes) \
+ taler-typescript-core-$(shell git describe --tags --abbrev=0 | sed -e 's/^v//').tar.gz
# Create tarball with git hash prefix in name
.PHONY: dist-git
dist-git:
- $(git-archive-all) --include ./configure taler-wallet-$(shell git describe --tags).tar.gz
+ $(archive) $(archive-includes) \
+ taler-typescript-core-$(shell git describe --tags).tar.gz
.PHONY: publish
publish:
diff --git a/bootstrap b/bootstrap
@@ -14,29 +14,18 @@ fi
# submodules to avoid accidental rollbacks.
git config --local submodule.recurse true
-git submodule update --init
-
-copy_configure() {
- src=$1
- dst=$2
- rm -f $dst
- cp $src $dst
- # Try making the configure script read-only to prevent
- # accidental changes in the wrong place.
- chmod ogu-w $dst || true
-}
+git submodule update --init --recursive
# To enable a GNU-style build system, we copy a configure
# script to each package that can be installed
-our_configure=build-system/taler-build-scripts/configure
-copy_configure "$our_configure" ./configure
-copy_configure "$our_configure" ./packages/taler-wallet-cli/configure
-copy_configure "$our_configure" ./packages/anastasis-cli/configure
-copy_configure "$our_configure" ./packages/libeufin-bank-webui/configure
-copy_configure "$our_configure" ./packages/taler-harness/configure
-copy_configure "$our_configure" ./packages/taler-util/configure
-copy_configure "$our_configure" ./packages/taler-merchant-webui/configure
-copy_configure "$our_configure" ./packages/taler-exchange-aml-webui/configure
-copy_configure "$our_configure" ./packages/taler-exchange-kyc-webui/configure
-copy_configure "$our_configure" ./packages/taler-auditor-webui/configure
-copy_configure "$our_configure" ./packages/challenger-webui/configure
+configure_targets=./configure
+for makefile in ./packages/*/Makefile; do
+ configure_targets="$configure_targets ${makefile%/Makefile}/configure"
+done
+
+for dst in $configure_targets; do
+ rm -f "$dst"
+ cp build-system/configure.sh "$dst"
+ # Make generated scripts read-only to discourage editing the copies.
+ chmod a-w "$dst" || true
+done
diff --git a/build-system/archive.py b/build-system/archive.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+
+# This file has been placed in the public domain.
+
+"""Create a source archive containing this repository and its submodules."""
+
+from __future__ import annotations
+
+import argparse
+import os
+from pathlib import Path
+import subprocess
+import sys
+import tarfile
+
+
+def run_git(repo: Path, *args: str, input_data: bytes | None = None) -> bytes:
+ try:
+ return subprocess.run(
+ ["git", *args],
+ cwd=repo,
+ input=input_data,
+ check=True,
+ stdout=subprocess.PIPE,
+ ).stdout
+ except subprocess.CalledProcessError as exc:
+ command = " ".join(("git", *args))
+ raise RuntimeError(f"'{command}' failed in {repo}") from exc
+
+
+def tracked_paths(repo: Path) -> list[Path]:
+ output = run_git(repo, "ls-files", "-z", "--cached")
+ return [
+ Path(os.fsdecode(item)) for item in output.rstrip(b"\0").split(b"\0") if item
+ ]
+
+
+def submodule_paths(repo: Path) -> set[Path]:
+ gitmodules = repo / ".gitmodules"
+ if not gitmodules.exists():
+ return set()
+ result = subprocess.run(
+ [
+ "git",
+ "config",
+ "-f",
+ ".gitmodules",
+ "--get-regexp",
+ r"^submodule\..*\.path$",
+ ],
+ cwd=repo,
+ check=False,
+ stdout=subprocess.PIPE,
+ text=True,
+ )
+ if result.returncode not in (0, 1):
+ raise RuntimeError(f"could not read submodules from {gitmodules}")
+ return {Path(line.split(maxsplit=1)[1]) for line in result.stdout.splitlines()}
+
+
+def export_ignored(repo: Path, paths: list[Path]) -> set[Path]:
+ if not paths:
+ return set()
+ query = b"\0".join(os.fsencode(path) for path in paths) + b"\0"
+ output = run_git(
+ repo, "check-attr", "-z", "--stdin", "export-ignore", input_data=query
+ )
+ fields = output.rstrip(b"\0").split(b"\0")
+ ignored: set[Path] = set()
+ for index in range(0, len(fields), 3):
+ if fields[index + 2] == b"set":
+ ignored.add(Path(os.fsdecode(fields[index])))
+ return ignored
+
+
+def repository_entries(repo: Path) -> list[tuple[Path, Path]]:
+ """Return (filesystem path, archive-relative path) pairs for one repository."""
+ submodules = submodule_paths(repo)
+ candidates: list[tuple[Path, Path]] = []
+
+ for relative in tracked_paths(repo):
+ if relative not in submodules:
+ candidates.append((repo / relative, relative))
+
+ for submodule in sorted(submodules):
+ submodule_dir = repo / submodule
+ if not (submodule_dir / ".git").exists():
+ raise RuntimeError(
+ f"submodule '{submodule}' is not initialized; run './bootstrap' first"
+ )
+ for source, relative in repository_entries(submodule_dir):
+ candidates.append((source, submodule / relative))
+
+ ignored = export_ignored(repo, [relative for _, relative in candidates])
+ return [
+ (source, relative) for source, relative in candidates if relative not in ignored
+ ]
+
+
+def archive_prefix(output: Path) -> Path:
+ name = output.name
+ for suffix in (".tar.gz", ".tgz"):
+ if name.endswith(suffix):
+ prefix = name[: -len(suffix)]
+ if prefix:
+ return Path(prefix)
+ break
+ raise ValueError("output file must end in .tar.gz or .tgz")
+
+
+def parse_args() -> argparse.Namespace:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "--include",
+ action="append",
+ default=[],
+ metavar="FILE",
+ help="include an untracked or export-ignored file (may be repeated)",
+ )
+ parser.add_argument("output", type=Path, help="output .tar.gz file")
+ return parser.parse_args()
+
+
+def main() -> int:
+ args = parse_args()
+ root = Path(run_git(Path.cwd(), "rev-parse", "--show-toplevel").decode().strip())
+ output = args.output.resolve()
+ prefix = archive_prefix(output)
+ entries = repository_entries(root)
+
+ included: list[tuple[Path, Path]] = []
+ for name in args.include:
+ relative = Path(name)
+ if relative.is_absolute() or ".." in relative.parts:
+ raise ValueError(
+ f"included path must be relative to the repository: {name}"
+ )
+ source = (root / relative).absolute()
+ if not source.is_file():
+ raise FileNotFoundError(f"included file does not exist: {name}")
+ included.append((source, relative))
+
+ with tarfile.open(output, "w:gz") as archive:
+ for source, relative in [*included, *entries]:
+ archive.add(source, arcname=prefix / relative, recursive=False)
+
+ print(f"created {output}")
+ return 0
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except (OSError, RuntimeError, ValueError) as exc:
+ print(f"archive: {exc}", file=sys.stderr)
+ sys.exit(1)
diff --git a/build-system/configure.py b/build-system/configure.py
@@ -1,25 +0,0 @@
-# This configure.py file is places in the public domain.
-
-# Configure the build directory.
-# This file is invoked by './configure' and should usually not be invoked
-# manually.
-
-import talerbuildconfig as tbc
-import sys
-import shutil
-
-if getattr(tbc, "serialversion", 0) < 2:
- print("talerbuildconfig outdated, please update the build-common submodule and/or bootstrap")
- sys.exit(1)
-
-b = tbc.BuildConfig()
-b.enable_prefix()
-b.enable_configmk(dotfile=True)
-b.add_tool(tbc.PosixTool("make"))
-b.add_tool(tbc.PosixTool("zip"))
-b.add_tool(tbc.PosixTool("find"))
-b.add_tool(tbc.PosixTool("jq"))
-b.add_tool(tbc.NodeJsTool(version_spec=">=18"))
-b.add_tool(tbc.GenericTool("npm"))
-b.add_tool(tbc.GenericTool("pnpm", hint="Use 'sudo npm install -g pnpm' to install."))
-b.run()
diff --git a/build-system/configure.sh b/build-system/configure.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# This file has been placed in the public domain.
+
+set -eu
+
+prefix=/usr/local
+
+usage() {
+ cat <<EOF
+Usage: ./configure [--prefix=DIR]
+
+Configure the installation prefix (default: /usr/local).
+EOF
+}
+
+while test $# -gt 0; do
+ case $1 in
+ --prefix=*)
+ prefix=${1#*=}
+ ;;
+ --prefix)
+ if test $# -lt 2; then
+ echo "configure: option '--prefix' requires an argument" >&2
+ exit 2
+ fi
+ prefix=$2
+ shift
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ *)
+ echo "configure: unrecognized option '$1'" >&2
+ echo "Try './configure --help' for more information." >&2
+ exit 2
+ ;;
+ esac
+ shift
+done
+
+if test -z "$prefix"; then
+ echo "configure: installation prefix must not be empty" >&2
+ exit 2
+fi
+
+cat >.config.mk <<EOF
+# This makefile fragment is generated by configure.
+prefix = $prefix
+EOF
+
+echo "configured installation prefix: $prefix"
diff --git a/build-system/taler-build-scripts b/build-system/taler-build-scripts
@@ -1 +0,0 @@
-Subproject commit 884e13fe65b584f63d4cf92348fab1136af4bd69
diff --git a/contrib/ci/jobs/0-codespell/job.sh b/contrib/ci/jobs/0-codespell/job.sh
@@ -9,4 +9,4 @@ job_dir=$(dirname "${BASH_SOURCE[0]}")
# ./packages/taler-util/src/iso-639.ts
# contains iso codes
-codespell -q 0 -I "${job_dir}"/dictionary.txt -S "*.pot,*.bib,*.bst,*.cls,*.json,*.png,*.svg,*.wav,*.gz,*/templating/test?/**,**/auditor/*.sql,**/templating/mustach**,*.fees,*key,*.tag,*.info,*.latexmkrc,*.ecc,*.jpg,*.zkey,*.sqlite,*/contrib/hellos/**,*/vpn/tests/**,*.priv,*.file,*.tgz,*.woff,*.gif,*.odt,*.fee,*.deflate,*.dat,*.jpeg,*.eps,*.odg,*/m4/ax_lib_postgresql.m4,*/m4/libgcrypt.m4,*.rpath,config.status,ABOUT-NLS,*/doc/texinfo.tex,*.PNG,*.??.json,*.docx,*.ods,*.doc,*.docx,*.xcf,*.xlsx,*.ecc,*.ttf,*.woff2,*.eot,*.ttf,*.eot,*.mp4,*.pptx,*.epgz,*.min.js,**/*.map,**/fonts/**,*.pack.js,*.po,*.bbl,*/afl-tests/*,*/.git/**,*.pdf,*.epub,**/signing-key.asc,**/pnpm-lock.yaml,**/*.svg,**/*.cls,**/rfc.bib,**/*.bst,*/cbdc-es.tex,*/cbdc-it.tex,**/ExchangeSelection/example.ts,*/testcurl/test_tricky.c,*/i18n/strings.ts,*/src/anastasis-data.ts,**/doc/flows/main.de.tex,*/node_modules/**,*.pnpm-store/**,./prebuilt/**,./packages/*/lib/**,./packages/*/dist/**,./build-system/**,*.ico,*.tff,*.zip,*.sqlite3,./packages/taler-util/src/iso-639.ts,./packages/web-util/src/utils/select-ui-lists.ts,./packages/fix-weblate-format"
+codespell -q 0 -I "${job_dir}"/dictionary.txt -S "*.pot,*.bib,*.bst,*.cls,*.json,*.png,*.svg,*.wav,*.gz,*/templating/test?/**,**/auditor/*.sql,**/templating/mustach**,*.fees,*key,*.tag,*.info,*.latexmkrc,*.ecc,*.jpg,*.zkey,*.sqlite,*/contrib/hellos/**,*/vpn/tests/**,*.priv,*.file,*.tgz,*.woff,*.gif,*.odt,*.fee,*.deflate,*.dat,*.jpeg,*.eps,*.odg,*/m4/ax_lib_postgresql.m4,*/m4/libgcrypt.m4,*.rpath,config.status,ABOUT-NLS,*/doc/texinfo.tex,*.PNG,*.??.json,*.docx,*.ods,*.doc,*.docx,*.xcf,*.xlsx,*.ecc,*.ttf,*.woff2,*.eot,*.ttf,*.eot,*.mp4,*.pptx,*.epgz,*.min.js,**/*.map,**/fonts/**,*.pack.js,*.po,*.bbl,*/afl-tests/*,*/.git/**,*.pdf,*.epub,**/signing-key.asc,**/pnpm-lock.yaml,**/*.svg,**/*.cls,**/rfc.bib,**/*.bst,*/cbdc-es.tex,*/cbdc-it.tex,**/ExchangeSelection/example.ts,*/testcurl/test_tricky.c,*/i18n/strings.ts,*/src/anastasis-data.ts,**/doc/flows/main.de.tex,*/node_modules/**,*.pnpm-store/**,./prebuilt/**,./packages/*/lib/**,./packages/*/dist/**,*.ico,*.tff,*.zip,*.sqlite3,./packages/taler-util/src/iso-639.ts,./packages/web-util/src/utils/select-ui-lists.ts,./packages/fix-weblate-format"