Skip to content

Commit 47eb02c

Browse files
ScottKevillFizzadar
authored andcommitted
Refactor files.HashFile facts
1 parent 3cc596e commit 47eb02c

File tree

11 files changed

+42
-73
lines changed

11 files changed

+42
-73
lines changed

pyinfra/facts/files.py

Lines changed: 31 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
import stat
77
from datetime import datetime
8+
from typing import List, Tuple
89

910
from pyinfra.api.command import QuoteString, make_formatted_string_command
1011
from pyinfra.api.facts import FactBase
@@ -204,91 +205,57 @@ class Socket(File):
204205
type = "socket"
205206

206207

207-
class Sha1File(FactBase):
208-
"""
209-
Returns a SHA1 hash of a file. Works with both sha1sum and sha1. Returns
210-
``None`` if the file doest not exist.
211-
"""
208+
class HashFileFactBase(FactBase):
209+
_raw_cmd: str
210+
_regexes: Tuple[str, str]
211+
212+
def __init_subclass__(cls, digits: int, cmds: List[str], **kwargs) -> None:
213+
super().__init_subclass__(**kwargs)
212214

213-
_regexes = [
214-
r"^([a-zA-Z0-9]{40})\s+%s$",
215-
r"^SHA1\s+\(%s\)\s+=\s+([a-zA-Z0-9]{40})$",
216-
]
215+
raw_hash_cmds = ["%s {0} 2> /dev/null" % cmd for cmd in cmds]
216+
raw_hash_cmd = " || ".join(raw_hash_cmds)
217+
cls._raw_cmd = "test -e {0} && ( %s ) || true" % raw_hash_cmd
218+
219+
assert cls.__name__.endswith("File")
220+
hash_name = cls.__name__[:-4].upper()
221+
cls._regexes = (
222+
# GNU coreutils style:
223+
r"^([a-fA-F0-9]{%d})\s+%%s$" % digits,
224+
# BSD style:
225+
r"^%s\s+\(%%s\)\s+=\s+([a-fA-F0-9]{%d})$" % (hash_name, digits),
226+
)
217227

218228
def command(self, path):
219229
self.path = path
220-
return make_formatted_string_command(
221-
(
222-
"test -e {0} && ( "
223-
"sha1sum {0} 2> /dev/null || shasum {0} 2> /dev/null || sha1 {0} "
224-
") || true"
225-
),
226-
QuoteString(path),
227-
)
230+
return make_formatted_string_command(self._raw_cmd, QuoteString(path))
228231

229232
def process(self, output):
233+
output = output[0]
234+
escaped_path = re.escape(self.path)
230235
for regex in self._regexes:
231-
regex = regex % re.escape(self.path)
232-
matches = re.match(regex, output[0])
236+
matches = re.match(regex % escaped_path, output)
233237
if matches:
234238
return matches.group(1)
235239

236240

237-
class Sha256File(FactBase):
241+
class Sha1File(HashFileFactBase, digits=40, cmds=["sha1sum", "shasum", "sha1"]):
238242
"""
239-
Returns a SHA256 hash of a file, or ``None`` if the file does not exist.
243+
Returns a SHA1 hash of a file. Works with both sha1sum and sha1. Returns
244+
``None`` if the file doest not exist.
240245
"""
241246

242-
_regexes = [
243-
r"^([a-zA-Z0-9]{64})\s+%s$",
244-
r"^SHA256\s+\(%s\)\s+=\s+([a-zA-Z0-9]{64})$",
245-
]
246-
247-
def command(self, path):
248-
self.path = path
249-
return make_formatted_string_command(
250-
(
251-
"test -e {0} && ( "
252-
"sha256sum {0} 2> /dev/null "
253-
"|| shasum -a 256 {0} 2> /dev/null "
254-
"|| sha256 {0} "
255-
") || true"
256-
),
257-
QuoteString(path),
258-
)
259247

260-
def process(self, output):
261-
for regex in self._regexes:
262-
regex = regex % re.escape(self.path)
263-
matches = re.match(regex, output[0])
264-
if matches:
265-
return matches.group(1)
248+
class Sha256File(HashFileFactBase, digits=64, cmds=["sha256sum", "shasum -a 256", "sha256"]):
249+
"""
250+
Returns a SHA256 hash of a file, or ``None`` if the file does not exist.
251+
"""
266252

267253

268-
class Md5File(FactBase):
254+
class Md5File(HashFileFactBase, digits=32, cmds=["md5sum", "md5"]):
269255
"""
270256
Returns an MD5 hash of a file, or ``None`` if the file does not exist.
271257
"""
272258

273-
_regexes = [
274-
r"^([a-zA-Z0-9]{32})\s+%s$",
275-
r"^MD5\s+\(%s\)\s+=\s+([a-zA-Z0-9]{32})$",
276-
]
277-
278-
def command(self, path):
279-
self.path = path
280-
return make_formatted_string_command(
281-
"test -e {0} && ( md5sum {0} 2> /dev/null || md5 {0} ) || true",
282-
QuoteString(path),
283-
)
284-
285-
def process(self, output):
286-
for regex in self._regexes:
287-
regex = regex % re.escape(self.path)
288-
matches = re.match(regex, output[0])
289-
if matches:
290-
return matches.group(1)
291-
292259

293260
class FindInFile(FactBase):
294261
"""

tests/facts/files.Md5File/file.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( md5sum myfile 2> /dev/null || md5 myfile ) || true",
3+
"command": "test -e myfile && ( md5sum myfile 2> /dev/null || md5 myfile 2> /dev/null ) || true",
44
"output": [
55
"c10ba97d7c9078a006d26b5db01d8ee7 myfile"
66
],

tests/facts/files.Md5File/file_bsd_style.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( md5sum myfile 2> /dev/null || md5 myfile ) || true",
3+
"command": "test -e myfile && ( md5sum myfile 2> /dev/null || md5 myfile 2> /dev/null ) || true",
44
"output": [
55
"MD5 (myfile) = c10ba97d7c9078a006d26b5db01d8ee7"
66
],

tests/facts/files.Md5File/file_needs_quotes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "my () file && special_chars.txt",
3-
"command": "test -e 'my () file && special_chars.txt' && ( md5sum 'my () file && special_chars.txt' 2> /dev/null || md5 'my () file && special_chars.txt' ) || true",
3+
"command": "test -e 'my () file && special_chars.txt' && ( md5sum 'my () file && special_chars.txt' 2> /dev/null || md5 'my () file && special_chars.txt' 2> /dev/null ) || true",
44
"output": [
55
"c10ba97d7c9078a006d26b5db01d8ee7 my () file && special_chars.txt"
66
],

tests/facts/files.Sha1File/file.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( sha1sum myfile 2> /dev/null || shasum myfile 2> /dev/null || sha1 myfile ) || true",
3+
"command": "test -e myfile && ( sha1sum myfile 2> /dev/null || shasum myfile 2> /dev/null || sha1 myfile 2> /dev/null ) || true",
44
"output": [
55
"85746ef87ddabd9fdf4836c5835e34a030d2a141 myfile"
66
],

tests/facts/files.Sha1File/file_bsd_style.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( sha1sum myfile 2> /dev/null || shasum myfile 2> /dev/null || sha1 myfile ) || true",
3+
"command": "test -e myfile && ( sha1sum myfile 2> /dev/null || shasum myfile 2> /dev/null || sha1 myfile 2> /dev/null ) || true",
44
"output": [
55
"SHA1 (myfile) = 85746ef87ddabd9fdf4836c5835e34a030d2a141"
66
],

tests/facts/files.Sha1File/file_needs_quotes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "my () file && special_chars.txt",
3-
"command": "test -e 'my () file && special_chars.txt' && ( sha1sum 'my () file && special_chars.txt' 2> /dev/null || shasum 'my () file && special_chars.txt' 2> /dev/null || sha1 'my () file && special_chars.txt' ) || true",
3+
"command": "test -e 'my () file && special_chars.txt' && ( sha1sum 'my () file && special_chars.txt' 2> /dev/null || shasum 'my () file && special_chars.txt' 2> /dev/null || sha1 'my () file && special_chars.txt' 2> /dev/null ) || true",
44
"output": [
55
"85746ef87ddabd9fdf4836c5835e34a030d2a141 my () file && special_chars.txt"
66
],

tests/facts/files.Sha256File/file.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( sha256sum myfile 2> /dev/null || shasum -a 256 myfile 2> /dev/null || sha256 myfile ) || true",
3+
"command": "test -e myfile && ( sha256sum myfile 2> /dev/null || shasum -a 256 myfile 2> /dev/null || sha256 myfile 2> /dev/null ) || true",
44
"output": [
55
"3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033 myfile"
66
],

tests/facts/files.Sha256File/file_bsd_style.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "myfile",
3-
"command": "test -e myfile && ( sha256sum myfile 2> /dev/null || shasum -a 256 myfile 2> /dev/null || sha256 myfile ) || true",
3+
"command": "test -e myfile && ( sha256sum myfile 2> /dev/null || shasum -a 256 myfile 2> /dev/null || sha256 myfile 2> /dev/null ) || true",
44
"output": [
55
"SHA256 (myfile) = 3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033"
66
],

tests/facts/files.Sha256File/file_needs_quotes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"arg": "my () file && special_chars.txt",
3-
"command": "test -e 'my () file && special_chars.txt' && ( sha256sum 'my () file && special_chars.txt' 2> /dev/null || shasum -a 256 'my () file && special_chars.txt' 2> /dev/null || sha256 'my () file && special_chars.txt' ) || true",
3+
"command": "test -e 'my () file && special_chars.txt' && ( sha256sum 'my () file && special_chars.txt' 2> /dev/null || shasum -a 256 'my () file && special_chars.txt' 2> /dev/null || sha256 'my () file && special_chars.txt' 2> /dev/null ) || true",
44
"output": [
55
"3867882e8ccc16bd6a1e3e214a46608f9cf5d21687bbb8c25751da3c47b48033 my () file && special_chars.txt"
66
],

0 commit comments

Comments
 (0)