From 004e7f089e83d6a78a394862a27a9203f0cfcde6 Mon Sep 17 00:00:00 2001 From: Jordan ERNST Date: Tue, 25 Aug 2026 00:46:21 +0200 Subject: [PATCH] fix(facts.files): fix tilde expansion for HashFiles (#1235) --- src/pyinfra/facts/files.py | 14 ++++++++++---- tests/facts/files.Md5File/tilde.yaml | 5 +++++ tests/facts/files.Md5File/tilde_bsd_style.yaml | 5 +++++ tests/facts/files.Sha1File/tilde.yaml | 5 +++++ tests/facts/files.Sha1File/tilde_bsd_style.yaml | 5 +++++ tests/facts/files.Sha256File/tilde.yaml | 5 +++++ tests/facts/files.Sha256File/tilde_bsd_style.yaml | 5 +++++ tests/facts/files.Sha384File/tilde.yaml | 5 +++++ tests/facts/files.Sha384File/tilde_bsd_style.yaml | 5 +++++ 9 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/facts/files.Md5File/tilde.yaml create mode 100644 tests/facts/files.Md5File/tilde_bsd_style.yaml create mode 100644 tests/facts/files.Sha1File/tilde.yaml create mode 100644 tests/facts/files.Sha1File/tilde_bsd_style.yaml create mode 100644 tests/facts/files.Sha256File/tilde.yaml create mode 100644 tests/facts/files.Sha256File/tilde_bsd_style.yaml create mode 100644 tests/facts/files.Sha384File/tilde.yaml create mode 100644 tests/facts/files.Sha384File/tilde_bsd_style.yaml diff --git a/src/pyinfra/facts/files.py b/src/pyinfra/facts/files.py index d16ec48fd..75d972068 100644 --- a/src/pyinfra/facts/files.py +++ b/src/pyinfra/facts/files.py @@ -398,15 +398,21 @@ def __init_subclass__(cls, digits: int, cmds: list[str], **kwargs) -> None: @override def command(self, path): - self.path = path - return make_formatted_string_command(self._raw_cmd, QuoteString(path)) + if path.startswith("~/"): + # Insert .* to take into account string expansion + self.escaped_path = ".*" + re.escape(path.removeprefix("~")) + # Do not quote leading tilde to ensure that it gets properly expanded by the shell + path = StringCommand("~/", QuoteString(path.removeprefix("~/")), _separator="") + else: + self.escaped_path = re.escape(path) + path = QuoteString(path) + return make_formatted_string_command(self._raw_cmd, path) @override def process(self, output) -> str | None: output = output[0] - escaped_path = re.escape(self.path) for regex in self._regexes: - matches = re.match(regex % escaped_path, output) + matches = re.match(regex % self.escaped_path, output) if matches: return matches.group(1) return None diff --git a/tests/facts/files.Md5File/tilde.yaml b/tests/facts/files.Md5File/tilde.yaml new file mode 100644 index 000000000..df51a4d3c --- /dev/null +++ b/tests/facts/files.Md5File/tilde.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( md5sum ~/myfile 2> /dev/null || md5 ~/myfile 2> /dev/null ) || true" +"output": + - "c10ba97d7c9078a006d26b5db01d8ee7 /home/pyinfra/myfile" +"fact": "c10ba97d7c9078a006d26b5db01d8ee7" diff --git a/tests/facts/files.Md5File/tilde_bsd_style.yaml b/tests/facts/files.Md5File/tilde_bsd_style.yaml new file mode 100644 index 000000000..f6627b454 --- /dev/null +++ b/tests/facts/files.Md5File/tilde_bsd_style.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( md5sum ~/myfile 2> /dev/null || md5 ~/myfile 2> /dev/null ) || true" +"output": + - "MD5 (/home/pyinfra/myfile) = c10ba97d7c9078a006d26b5db01d8ee7" +"fact": "c10ba97d7c9078a006d26b5db01d8ee7" diff --git a/tests/facts/files.Sha1File/tilde.yaml b/tests/facts/files.Sha1File/tilde.yaml new file mode 100644 index 000000000..03b3dc4de --- /dev/null +++ b/tests/facts/files.Sha1File/tilde.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha1sum ~/myfile 2> /dev/null || shasum ~/myfile 2> /dev/null || sha1 ~/myfile 2> /dev/null ) || true" +"output": + - "85746ef87ddabd9fdf4836c5835e34a030d2a141 /home/pyinfra/myfile" +"fact": "85746ef87ddabd9fdf4836c5835e34a030d2a141" diff --git a/tests/facts/files.Sha1File/tilde_bsd_style.yaml b/tests/facts/files.Sha1File/tilde_bsd_style.yaml new file mode 100644 index 000000000..19d2fa1d8 --- /dev/null +++ b/tests/facts/files.Sha1File/tilde_bsd_style.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha1sum ~/myfile 2> /dev/null || shasum ~/myfile 2> /dev/null || sha1 ~/myfile 2> /dev/null ) || true" +"output": + - "SHA1 (/home/pyinfra/myfile) = 85746ef87ddabd9fdf4836c5835e34a030d2a141" +"fact": "85746ef87ddabd9fdf4836c5835e34a030d2a141" diff --git a/tests/facts/files.Sha256File/tilde.yaml b/tests/facts/files.Sha256File/tilde.yaml new file mode 100644 index 000000000..e71d5f73b --- /dev/null +++ b/tests/facts/files.Sha256File/tilde.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha256sum ~/myfile 2> /dev/null || shasum -a 256 ~/myfile 2> /dev/null || sha256 ~/myfile 2> /dev/null ) || true" +"output": + - "3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033 /home/pyinfra/myfile" +"fact": "3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033" diff --git a/tests/facts/files.Sha256File/tilde_bsd_style.yaml b/tests/facts/files.Sha256File/tilde_bsd_style.yaml new file mode 100644 index 000000000..d93d8303a --- /dev/null +++ b/tests/facts/files.Sha256File/tilde_bsd_style.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha256sum ~/myfile 2> /dev/null || shasum -a 256 ~/myfile 2> /dev/null || sha256 ~/myfile 2> /dev/null ) || true" +"output": + - SHA256 (/home/pyinfra/myfile) = 3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033 +"fact": "3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033" diff --git a/tests/facts/files.Sha384File/tilde.yaml b/tests/facts/files.Sha384File/tilde.yaml new file mode 100644 index 000000000..ebe8efd3a --- /dev/null +++ b/tests/facts/files.Sha384File/tilde.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha384sum ~/myfile 2> /dev/null || shasum -a 384 ~/myfile 2> /dev/null || sha384 ~/myfile 2> /dev/null ) || true" +"output": + - "1dd2e448df7c4dc19848a37fdf25c86660b19d06a4cd6987ca2c4071f80e9dd3061e4b01ddb982dc56ed7a2ed2294699 /home/pyinfra/myfile" +"fact": "1dd2e448df7c4dc19848a37fdf25c86660b19d06a4cd6987ca2c4071f80e9dd3061e4b01ddb982dc56ed7a2ed2294699" diff --git a/tests/facts/files.Sha384File/tilde_bsd_style.yaml b/tests/facts/files.Sha384File/tilde_bsd_style.yaml new file mode 100644 index 000000000..d5fd89aba --- /dev/null +++ b/tests/facts/files.Sha384File/tilde_bsd_style.yaml @@ -0,0 +1,5 @@ +"arg": "~/myfile" +"command": "test -e ~/myfile && ( sha384sum ~/myfile 2> /dev/null || shasum -a 384 ~/myfile 2> /dev/null || sha384 ~/myfile 2> /dev/null ) || true" +"output": + - "SHA384 (/home/pyinfra/myfile) = 1dd2e448df7c4dc19848a37fdf25c86660b19d06a4cd6987ca2c4071f80e9dd3061e4b01ddb982dc56ed7a2ed2294699" +"fact": "1dd2e448df7c4dc19848a37fdf25c86660b19d06a4cd6987ca2c4071f80e9dd3061e4b01ddb982dc56ed7a2ed2294699"