Init: Basic project structure and functionality.

This commit is contained in:
Kevin Baensch 2020-03-21 08:20:49 +01:00
commit 8715c69e89
Signed by: derped
GPG key ID: C0F1D326C7626543
13 changed files with 503 additions and 0 deletions

0
fck/__init__.py Normal file
View file

32
fck/checker.py Normal file
View file

@ -0,0 +1,32 @@
from typing import Generator, List, Tuple, Optional
from .file import FILE
import re
def checkmark(value: Optional[bool] = None) -> str:
"""
Takes optional bool and returns colored string.
"""
return {
True: '\033[92m✓\033[0m',
False: '\033[91m❌\033[0m',
None: '\033[33m?\033[0m'
}[value]
def check(f: FILE, largefile: bool = False) -> bool:
"""
Check given file and return checked file.
"""
f.csum.reset()
try:
with open(f.fpath, 'rb') as file:
if not largefile:
f.csum.gensum(file.read())
else:
for line in file:
f.csum.gensum(line)
except FileNotFoundError:
print(f"[WARN]: No such file or directory: {f.fpath}")
print(f"{checkmark(f.verify())} \t {f.csum} \t {f.esum} \t {f.fname}")
return f.verify()

18
fck/cktype/__init__.py Normal file
View file

@ -0,0 +1,18 @@
from re import search
from typing import Optional
from .crc32 import CRC32
CKTYPES = [
(CRC32)
]
def resolve(fname: str, esum: Optional[str] = None, cstype: Optional[str] = None):
"""
Checks fname input for checksum pattern and returns first match.
Can be overridden with cstype.
If neither is applicable the first possible checksum type will be returned.
"""
if esum is None and (match := CKTYPES[0].REGEX.search(fname)):
esum = match.group(0)
return CKTYPES[0](), esum

29
fck/cktype/crc32.py Normal file
View file

@ -0,0 +1,29 @@
from typing import Generator, List, Tuple, Optional
from re import compile, Pattern
from zlib import crc32
class CRC32(object):
NAME: str = "CRC32"
EXT: List[str] = [".sfv"]
SYNTAX: List[Pattern] = [
compile(r'^;*$'),
compile(r'^.* [0-9a-fA-F]{8}$')
]
REGEX: Pattern = compile(r'[0-9a-fA-F]{8}')
def __init__(self):
self.cksum: int = 0
def gensum(self, data: bytes):
self.cksum = crc32(data, self.cksum)
def reset(self):
self.__init__()
def __repr__(self) -> str:
cstring = str(hex(self.cksum))[2:].upper()
return ''.join([((8 - len(cstring)) * "0"), cstring])
def __eq__(self, other) -> bool:
return self.__repr__() == other.upper()

18
fck/file.py Normal file
View file

@ -0,0 +1,18 @@
from typing import Optional
from os import path
from . import cktype
class FILE:
def __init__(self, fpath: str, esum: Optional[str] = None):
self.fpath = fpath
self.fname = path.basename(fpath)
self.csum, self.esum = cktype.resolve(self.fname, esum)
def __repr__(self):
return self.fname
def verify(self) -> Optional[bool]:
if self.esum is None:
return None
return self.csum.__repr__() == self.esum

65
fck/fileutils.py Normal file
View file

@ -0,0 +1,65 @@
from typing import Generator, List, Tuple
from os import listdir, path
from .file import FILE
def search(pathlist: List[str]) -> Generator[FILE, None, None]:
"""
Generate file paths from given list of Paths.
+------------+
| Parameters |
+------------+
| pathlist: List[str]
| List of files and directories.
+--------+
| Yields |
---------+
| file: Tuple[(None, str)]
| file is a Tuple containing:
| - a files path string
| - a crc32 sum (None if unknown)
"""
for fpath in pathlist:
if path.isfile(fpath):
if len(fpath) > 4 and fpath[-4:] == ".sfv":
yield from sfv_read(fpath)
else:
yield FILE(path.realpath(fpath))
continue
if path.isdir(fpath):
yield from search([path.join(fpath, x) for x in listdir(fpath)])
continue
print(f"[WARN]: No such file or directory: {fpath}")
def sfv_read(filename: str) -> Generator[FILE, None, None]:
"""
Read sfv file.
"""
try:
with open(filename, 'r') as file:
yield from (FILE(' '.join(x.split()[:-1]), x.split()[-1])
for x in file.read().split('\n')
if len(x) != 0 and x[0] != ';')
except UnicodeDecodeError:
print(f"[ERR]: {filename} is not a text file.")
except FileNotFoundError:
print(f"[WARN]: No such file or directory: {filename}")
def sfv_write(checked_files: List[Tuple[str, str, bool]], filename: str) -> None:
"""
Write sfv file.
"""
try:
with open(filename, 'w') as file:
checked_files.sort()
if any([not x[2] for x in checked_files]):
print(f"[WARN]: {filename} will contain unverified checksums.")
# [file.write(f"{str(x[0])}\t{str(x[1])}") for x in checked_files]
file.write('\n'.join([x for x in ["hello" "world"]]))
except FileExistsError:
pass