sitecustomize.py:
- Replace _PATCHES dispatch dict with if/elif in exec_module; removes
coupling between dispatch and _record_status's count barrier
- Drop _record_status count barrier entirely; both patches fire within
milliseconds during the same import sequence, write-on-every-call is safe
- Replace _broken_url regex with str.partition + startswith checks; same
semantics, no regex knowledge required to read
- Replace @staticmethod decorator inside plain function with explicit
staticmethod() assignment; decorator form creates a descriptor object,
not a callable, which confuses readers expecting class-body usage
apply.sh:
- Inline warn/ok helpers; each was one echo with a prefix, the indirection
cost more than the abstraction saved
- Collapse patch_ui.py if/else (whose if branch was a no-op comment) to
a single || fallback line
create_task.py:
- Remove vestigial (_client, _args) params from cmd_verify; it was pulled
out of dispatch, the params were never used
- Replace 3-entry dispatch dict with if/elif; dict implied a uniform calling
convention that verify already broke
If the patch ever prevents middlewared from starting, users now have a
clear escape hatch that requires no knowledge of Python internals:
bash /data/truecloud-patch/recover.sh
Or at a bare shell prompt:
touch /data/truecloud-patch/disabled
systemctl restart middlewared
sitecustomize.py checks for /data/truecloud-patch/disabled at Python
startup and skips the import hook entirely when the file exists.
apply.sh does the same so the PREINIT script also does nothing on reboot.
recover.sh is copied to /data/truecloud-patch/ by install.sh so it is
available even without the original repo directory.
README gains an "Emergency recovery" section above Troubleshooting.
sitecustomize.py: exec_module was calling importlib.util.find_spec(fullname)
after Python had already added the module to sys.modules. find_spec
short-circuits to sys.modules[name].__spec__, which is our own wrapper spec,
so real_spec.loader.exec_module(module) immediately called exec_module again
— infinite recursion. Fix: resolve the real file spec in find_spec (before
sys.modules is populated) and store it on the Loader. exec_module now uses
the stored spec directly with no find_spec call.
Also move _mark_done into the finally block so a module that fails to load
doesn't trigger infinite retry loops on subsequent import attempts.
apply.sh: warn() writes to stdout. Inside $(find_mw_python), stdout is
captured by the command substitution, so any warn() call folded its text
into $PYTHON — causing every subsequent "$PYTHON" invocation to fail. Fix:
emit the fallback warning to stderr (>&2) so it goes to the log without
being captured.
Patches middlewared at runtime via sitecustomize.py (no file edits to /usr/)
and widens the UI credential dropdown from Storj-only to S3+B2+Storj.
Persists across TrueNAS updates via PREINIT initshutdownscript stored in DB.