module

Krikri::PluginHelpers::AclCommand

Command construction + output parsing for the acl plugin (POSIX ACL management via getfacl(1)/setfacl(1)) - split out from plugins/acl.cr so it can be unit-tested without a real ACL-capable filesystem or superuser (mirrors the ufw/iptables split). Every shape here is ported field-for-field from real ansible.posix's own acl.py (build_command/split_entry/build_entry/acl_changed/run_acl) and cross-checked against the actual setfacl 2.3.2 --test output (see spec/unit/acl_command_spec.cr's notes).

Class methods

build_command(mode : String, path : String, follow : Bool, default : Bool, recursive : Bool, recalculate_mask : String, use_nfsv4_acls : Bool = false, entry : String = "") : Array(String)

Builds the argv for one getfacl/setfacl invocation - mirrors real acl.py's build_command, including the exact flag ordering real Ansible produces (which matters: -d is inserted right after the binary name, and everything else appends). Linux only, matching this engine's Linux-target binaries - the real module's FreeBSD -h branch (and its non-Linux fail) is not represented. mode is "set" | "rm" | "get".

Source
build_entry(etype : String | Nil, entity : String | Nil, permissions : String | Nil, use_nfsv4_acls : Bool = false) : String

Builds the -m/-x entry argument - mirrors real acl.py's build_entry. For POSIX ACLs the permissions section is omitted entirely when nil (the state: absent form - -x user:joe), for NFSv4 ACLs the 'A' ACE form with the 'tcy' type suffix is built instead, and the group etype gets the 'g' flag in that form.

Source
changed?(lines : Array(String), entry : String, use_nfsv4_acls : Bool = false) : Bool

The idempotency check, ported from real acl.py's acl_changed: setfacl --test prints the would-be result of the operation, ending the line with *,* when nothing would change and with a full entry list (ending ,*) when it would. So for POSIX ACLs ANY line that does not end with *,* means changed. (FreeBSD's always-true branch is omitted - Linux only, see build_command.) For NFSv4 ACLs the heuristic is different: the tested-new entry is listed twice when it already exists and once when it would genuinely be added.

Source
filter_lines(raw : String) : Array(String)

run_acl's line filtering, in a pure form (real acl.py drops any line starting with '#', strips each remaining line, then trims a single trailing empty line - blank separator lines BETWEEN entries survive, which is what real Ansible's recursive acl return value looks like).

Source
split_entry(entry : String) : Tuple(Bool | Nil, String | Nil, String | Nil, String | Nil)

Splits an entry: shorthand string into its parts - mirrors real acl.py's split_entry: an optional leading d/default section (when the entry starts with a 'd') marks a default ACL entry, and an entry with only two ':'-separated sections (the state: absent form, e.g. user:joe) gets a nil permissions slot. The etype is normalized by its first letter, exactly like the real module - anything else becomes nil (which then flows through to setfacl as-is and fails there, matching real Ansible's behavior for a garbage entry string).

Source