taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

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:
M.gitignore | 3---
M.gitmodules | 3---
MMakefile | 22++++++++--------------
Mbootstrap | 35++++++++++++-----------------------
Abuild-system/archive.py | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dbuild-system/configure.py | 25-------------------------
Abuild-system/configure.sh | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Dbuild-system/taler-build-scripts | 1-
Mcontrib/ci/jobs/0-codespell/job.sh | 2+-
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"