Krikri::SynchronizeRsync
The rsync-invocation core of ansible.posix.synchronize, shared by both entry points that need it:
- SynchronizeActionPlugin (controller-side action plugin - the normal task-execution path; see its own file for why synchronize is controller-side here, same as real Ansible)
- plugins/synchronize.cr (the standalone/fat plugin binary, kept for
--async/manual invocation on whatever host the "local" rsync end is - same split as debug/pause)
Ported from real ansible.posix's plugins/modules/synchronize.py (the
module half; the action-plugin half only munges src/dest into remote
user@host:path form and resolves the private key/port before handing
over). Argument order, flag spelling, and the itemize-changes protocol
all follow that source verbatim:
- every flag rsync gets is the real module's own (including the non-obvious ones: --delete-after for delete:, --delay-updates -F by default, --archive plus explicit --no-X for each toggle that was EXPLICITLY turned off under a default-on archive:)
- changed detection is rsync's own: the command always runs with
--out-format=<<CHANGED>>%i %n%L, so every item rsync actually created/updated/attribute-changed/deleted gets a<<CHANGED>>- prefixed itemize line and an untouched tree prints nothing at all - "any marker line => changed" is exactly real Ansible's ownchanged = changed_marker in outtest (with the documented link_dest exception, where a leading.itemize char means "hard-linked, no change")
Constants
Class methods
Tri-state form: nil when the param is absent (the caller decides what "absent" follows - for the archive toggles that's archive's own value, per the real module's type: bool-without-default spec).
Builds the full rsync argv for one synchronize invocation. src and
dest must already be FINAL (the caller munged remote ends into
user@host:path form first); everything else is read from params
with the real module's own defaults. private_key/dest_port are
the caller-resolved connection values (param override, then
inventory vars) that feed the --rsh= ssh command when either path
is remote (contains ':').
The real module's changed test: any itemize line at all - except the
link_dest case, where rsync prints a leading-. itemize char for
each file it hard-linked WITHOUT changing, and the real module's own
test is literally (changed_marker + '.') not in out.
Strips the markers back off, keeping one itemize line (marker removed) per real change - the real module's msg/stdout_lines/diff payload.
_format_rsync_rsh_target - builds user@host:path for the remote
end, preserving an already-qualified path (user@host:path as written
in the task, or an rsync:// URL) untouched. IPv6 hosts get the
[user@addr]:path bracket form rsync's ssh transport requires.
True when either final path is an rsync remote spec (host:path,
user@host:path, or rsync:// URL) - the real module's
is_rsh_needed. Two plain local paths (the delegate_to: localhost
idiom) need no remote shell.
List-shaped params arrive as strings (the wire format every plugin gets) - either a JSON array or comma-separated. Same defensive re-parse find.cr/apt.cr document (a YAML one-element list otherwise becomes ONE string containing literal brackets/quotes).