wrolpi/alembic
lrnselfreliance 0e4d701cd4
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Controller Tests / controller-tests (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run
files: unique (directory, stem) after collapsing duplicate FileGroups (#715)
* files: pass find -printf \0 as an escape, not a Python NUL (#716)

* files: pass find -printf \\0 as an escape, not a Python NUL

'%h\\0%f\\0%T@\\0' in a Python string is an embedded null byte.  subprocess
cannot pass that as an argument, so every GNU-find refresh on Linux CI
raised ValueError.  find wants the two-character escape \\0 in the format
string and emits NULs itself.

* files: serialize stem backfill so a cancelled compare cannot lock SQLite

compare_file_groups runs ensure_file_group_stems in a thread.  Cancelling
the task does not stop that thread, and a second compare then writes
wrolpi_kv on the same connection (tests share one session).  A lock
plus a version re-check makes the second call a no-op.

* files: unique (directory, stem) after collapsing duplicate FileGroups

713 added stem and a non-unique index.  This release backfills any NULL
stems, merges leftover duplicates (tags and collection membership move
onto the winner), and creates a UNIQUE index.

Upsert deletes sidecar FileGroups before INSERT so a new primary cannot
collide.  Refresh deletes before upsert for the same reason.
from_paths looks up by stem so adding a sidecar does not insert a second
row.  Same-stem files without a modeled primary stay one FileGroup.

* files: do not use the test SQLite connection from a worker thread

get_db_curs in pytest shares the test session connection.  Running
ensure_file_group_stems and _upsert_files via asyncio.to_thread then
segfaults when the event loop commits that same connection (CI xdist).
Keep to_thread in production, where get_db_curs opens a dedicated
raw connection.

* files: keep tags when a sidecar joins an unmodeled group

choose_primary_file is the single fallback for unmodeled stem groups so
_upsert_files and _upsert_file_groups cannot pick different primaries
and DELETE the tagged row.  FileGroup.move merges an existing
(directory, stem) group and flushes the delete before taking that stem.
refresh_files_directly deletes before upsert, matching the other two
callers.

* files: group by (directory, stem), not stem alone

group_files_by_stem mixed marauder/s3.bin and other/s3.bin into one
FileGroup because it ignored directory.  Unique (directory, stem) then
kept only one of them, so flasher search missed a firmware file.

run_command_streaming awaits the stdout reader instead of cancelling it
when the process exits, so the last lines are not lost on a fast CI run.

* jobs: write the exception into the Job log on failure

test_jobs_failure only saw 'boom' in the log when JobLogHandler captured
logger.error(..., exc_info=e).  Sanic/pytest dictConfig replaces root
handlers (especially under xdist on CI), so that path is empty even
though status and error are set.  Log the exception on the Job itself
and store it in the same _update_job as FAILED.
2026-09-19 21:03:49 -06:00
..
versions files: unique (directory, stem) after collapsing duplicate FileGroups (#715) 2026-09-19 21:03:49 -06:00
env.py Postgres -> SQLite hard cutover: the database moves into the media directory. 2026-07-12 14:09:37 -06:00
README A new start 2021-11-01 16:43:09 -06:00
script.py.mako Postgres -> SQLite hard cutover: the database moves into the media directory. 2026-07-12 14:09:37 -06:00

Generic single-database configuration.