From 5f623bf1106c56b3064b6e87bdb79261f5ba9704 Mon Sep 17 00:00:00 2001 From: Fabian Hamm Date: Mon, 14 Sep 2026 20:49:49 +0200 Subject: [PATCH] fix(zq): stop defaulting the database path into the repo being deleted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `zq.py` hardcoded one absolute path, and it pointed inside `xenia-rs` -- a repository CONSOLIDATION.md archives in Phase 5 and drops in Phase 7. It resolved on exactly one machine, and on that machine it was days from becoming a `duckdb` exception about a missing file, with nothing saying why. Resolution order is now `$SYLPH_XEXDB`, else `/sylpheed.db`, else a refusal that names both. The repo-root path is taken relative to this script, not the caller's cwd, because zq.py is run from wherever the investigation is. No fallback beyond that, on purpose. The database is a build artefact of a few hundred MB and is not tracked, so there is nothing to fall back *to*; a default that silently resolves to the wrong database is worse than no default. That is issue #16's lesson, which was about exactly this shape in the test suite. Both failure paths say what to do and exit 1: $ zq.py fn 82000000 # nothing set, nothing at the repo root no database found. looked for: /…/Sylpheed/sylpheed.db set $SYLPH_XEXDB to an existing one, or build it with: sylph-xexdb dis --db sylpheed.db --analyze sql $ SYLPH_XEXDB=/nope/missing.db zq.py fn 82000000 $SYLPH_XEXDB is set but is not a file: /nope/missing.db Also fixes the regeneration hint, which still named `xenia-rs dis` -- the retired binary. It is `sylph-xexdb dis`. Connecting is skipped when there is no subcommand, so `zq.py` still prints its usage on a machine that has no database yet. Verified: usage with no db (rc 0); missing db (rc 1); `$SYLPH_XEXDB` set to a non-file (rc 1); and `$SYLPH_XEXDB` pointed at a real 336 MB database, where `imp Rtl` returns its 1,280 `RtlLeaveCriticalSection` call sites. That database turns out to have been generated from the uncommitted tree this branch ports: it carries `import_address`, `import_role` and all 16 foreign keys -- an independent confirmation of the schema the golden test now locks. Co-Authored-By: Claude Opus 5 --- tools/zq.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/tools/zq.py b/tools/zq.py index 0dc6dbc2..81757f24 100755 --- a/tools/zq.py +++ b/tools/zq.py @@ -38,18 +38,59 @@ Usage: A command that needs a table the current DB predates prints what to regenerate rather than a SQL error. + +The database is found via `$SYLPH_XEXDB`, else `/sylpheed.db`. It is a +build artefact, not a tracked file; if neither exists, zq.py says so and prints +the command that builds one. """ -import duckdb, sys, signal +import duckdb, sys, os, pathlib, signal # Output is routinely piped into `head`; without this Python prints a # BrokenPipeError traceback when the reader closes early. signal.signal(signal.SIGPIPE, signal.SIG_DFL) -DB = '/home/fabi/RE - Project Sylpheed/xenia-rs/sylpheed.db' -c = duckdb.connect(DB, read_only=True) -H = lambda x: '0x%08x' % x +REGEN = "sylph-xexdb dis --db sylpheed.db --analyze sql" -REGEN = ("xenia-rs dis --db sylpheed.db --analyze sql") + +def _resolve_db(): + """Locate the database: `$SYLPH_XEXDB`, else `/sylpheed.db`. + + 🔴 This used to be one hardcoded absolute path, and it pointed *inside* + `xenia-rs` -- a repository `docs/agents/CONSOLIDATION.md` archives in Phase 5 + and drops in Phase 7. It resolved on exactly one machine and would have + started failing there too, with `duckdb` raising about a missing file rather + than anything saying why. + + The database is a build artefact of several hundred MB and is not in the + repository, so there is nothing to fall back *to*: if neither location has + one, say so and print how to build it. A default that silently resolves to + the wrong database is worse than no default -- see issue #16. + """ + env = os.environ.get('SYLPH_XEXDB') + if env: + p = pathlib.Path(env).expanduser() + if not p.is_file(): + sys.exit(f'$SYLPH_XEXDB is set but is not a file:\n {p}') + return p + # Relative to this script, not to the caller's cwd: `zq.py` is run from + # wherever the investigation happens to be. + p = pathlib.Path(__file__).resolve().parent.parent / 'sylpheed.db' + if p.is_file(): + return p + sys.exit( + f'no database found.\n' + f' looked for: {p}\n' + f' set $SYLPH_XEXDB to an existing one, or build it with:\n' + f' {REGEN}' + ) + + +# Resolved lazily enough that `zq.py` with no command still prints its usage on +# a machine that has no database yet. +_WANTS_DB = len(sys.argv) > 1 and sys.argv[1] not in ('-h', '--help', 'help') +DB = _resolve_db() if _WANTS_DB else None +c = duckdb.connect(str(DB), read_only=True) if DB is not None else None +H = lambda x: '0x%08x' % x def _need(*tables):