exlab_wizard.sync.transports.rclone#

rclone transport driver. Backend Spec §7.1.3.

Single transport binary for the NAS sync subsystem. Push uses rclone copy --checksum --files-from; verify uses rclone check --download --combined which streams remote bytes back and computes SHA-256 locally (the only way to integrity-check SFTP and SMB backends, which expose no server-side hashing).

The driver is intentionally thin: it builds an argv, hands it to exlab_wizard.sync.transports._run.run_subprocess(), and translates the exit-code + stderr-substring into one of the TransportErrorKind retry classes.

rclone.conf NAS-sync migration: the connection (host, credentials, backend type) is defined entirely by a named remote in the operator’s rclone.conf. The driver injects no credentials and never sees a password – it only passes --config <path> when the nas: block pins one.

Classes

AboutResult(ok[, reason, info])

Outcome of rclone about <remote> --json.

CheckResult([equal, differ, extra_on_dst, ...])

Parsed result of a rclone check --combined run.

RcloneDriver(*[, binary, config_path, ...])

rclone transport driver.

class exlab_wizard.sync.transports.rclone.AboutResult(ok, reason=None, info=<factory>)[source]#

Bases: object

Outcome of rclone about <remote> --json.

Surfaces as the equipment-probe response. ok flips true when rclone returned 0; reason carries the classified failure mode otherwise. info holds the parsed JSON payload on success (free-space, used, etc.) so the Settings panel can render it.

Parameters:
info: dict[str, int]#
ok: bool#
reason: str | None#
class exlab_wizard.sync.transports.rclone.CheckResult(equal=(), differ=(), extra_on_dst=(), missing_on_dst=(), errors=())[source]#

Bases: object

Parsed result of a rclone check --combined run.

The combined-output format emits one prefixed line per file:

  • = path – present and identical on both sides

  • * path – present on both sides but differs

  • + path – present on the destination only

  • - path – missing on the destination

  • ! path – error encountered checking this path

Each field below carries the run-relative POSIX paths corresponding to its prefix.

Parameters:
differ: tuple[str, ...]#
equal: tuple[str, ...]#
errors: tuple[str, ...]#
extra_on_dst: tuple[str, ...]#
missing_on_dst: tuple[str, ...]#
class exlab_wizard.sync.transports.rclone.RcloneDriver(*, binary='rclone', config_path=None, transfers=None, checkers=None)[source]#

Bases: object

rclone transport driver. Backend Spec §7.1.3.

Parameters:
async about(remote)[source]#

Run rclone about <remote> --json – the equipment probe.

Used by the Settings “Test connection” affordance. Confirms authentication and reachability; surfaces parsed free-space info on success. Failure paths are translated into AboutResult rather than raised, so the UI panel can render the reason inline.

Parameters:

remote (str)

Return type:

AboutResult

async check(local, remote, *, files_from)[source]#

Run rclone check --download --files-from --combined over files_from.

Streams the remote files back to compute their SHA-256 locally (the only way to integrity-check SFTP and SMB backends, which expose no server-side hashing). --combined writes one = / * / + / - / ! line per file to a tempfile that this method parses and returns as a CheckResult.

Raises TransportError with a classified error_kind when rclone itself failed (auth / network / unknown) – a clean run with files in the differ or missing_on_dst columns returns ok=True so the caller can route partial-failure reconciliation correctly.

Parameters:
Return type:

CheckResult

async listremotes()[source]#

Return the remote names defined in rclone.conf (each incl. trailing :)

Offline and cheap — no network. Used by the setup-availability gate and the Settings remote badge. A missing/unreadable config yields () so callers treat “no remotes” the same as “remote not found”.

Return type:

tuple[str, ...]

async lsjson(remote, *, recursive=True)[source]#

Run rclone lsjson (read-only) and return the raw JSON array text.

Listing only — no transfer, no remote mutation. recursive adds -R so a whole run subtree returns in one call. Raises TransportError with a classified error_kind on a non-zero exit so callers route auth/network failures the same way as push/check.

Parameters:
Return type:

str

async push(local, remote, *, bwlimit_kibps=None, files_from=None)[source]#

Run rclone copy --checksum from local to remote.

remote is the full <remote_name>:<path> string; the named remote (and its credentials) lives in the operator’s rclone.conf. bwlimit_kibps is forwarded as --bwlimit <K>K when set; files_from is forwarded as --files-from <path> so only a subset of the local tree transfers.

Returns a TransportResult. A spawn failure raises TransportError so the queue terminates rather than looping on a missing binary.

Parameters:
Return type:

TransportResult