Init: Basic project structure and functionality.
This commit is contained in:
commit
8715c69e89
13 changed files with 503 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
*.pyc
|
||||||
|
.mypy_cache
|
||||||
|
__pycache__
|
||||||
|
result
|
20
LICENSE
Normal file
20
LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (c) 2019-2020 Kevin Baensch
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
47
README.md
Normal file
47
README.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# fck - A simple checksum utility that just works
|
||||||
|
File checker (fck) is a python wrapper for various checksum functions (though right now it only supports CRC32).
|
||||||
|
It's goal is to make verifying large amounts of files both easier and faster.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Process/check multiple files at once.
|
||||||
|
- Automatically find expected checksums
|
||||||
|
- Quickly find faulty files.
|
||||||
|
- (Not yet) easily extendable
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
```
|
||||||
|
fck --help
|
||||||
|
usage: fck [-h] [-b] [-p PROCESSES] [-c CHECKSFV] [files [files ...]]
|
||||||
|
|
||||||
|
Calculate CRC32 of files
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
files files and folders to process
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-b, --bigfiles parse files that exceed your memory limit
|
||||||
|
-p PROCESSES, --processes PROCESSES
|
||||||
|
-c CHECKSFV, --checksfv CHECKSFV
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- >= Python3.8
|
||||||
|
- zlib // used to calculate CRC32 sums
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
### 0.1
|
||||||
|
- [ ] Context based selection of apropriate checksum type.
|
||||||
|
- [ ] Define and document project/class structure.
|
||||||
|
- [ ] Support reading/writing '.sfv' files.
|
||||||
|
- [ ] Add Tests.
|
||||||
|
### 0.2
|
||||||
|
- [ ] Dehardcode various CRC32 specific functionalities.
|
||||||
|
- [ ] Implement propper logging.
|
||||||
|
- [ ] Implement other common checksum types.
|
||||||
|
- [ ] Write a comprehensive documentation.
|
||||||
|
### Future
|
||||||
|
- [ ] More and better error (and memory) handling.
|
||||||
|
- [ ] Better logging/output control.
|
||||||
|
- [ ] Add an optional GUI.
|
||||||
|
- [ ] Package application for Windows/Mac/Linux (maybe)
|
19
default.nix
Normal file
19
default.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{ buildPythonApplication, zlib, lib }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
buildPythonApplication {
|
||||||
|
name = "fck";
|
||||||
|
version = "0.1";
|
||||||
|
|
||||||
|
src = cleanSource ./.;
|
||||||
|
|
||||||
|
buildInputs = [ zlib ];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
homepage = "https://git.ophanim.de/derped/fck";
|
||||||
|
description = "A small checksum utility that just works.";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
192
deprecated/crc32sum_threaded.py
Executable file
192
deprecated/crc32sum_threaded.py
Executable file
|
@ -0,0 +1,192 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# This software is licensed under the MIT License:
|
||||||
|
# Copyright (c) 2019-2020 Kevin Baensch
|
||||||
|
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
# DISCLAIMER
|
||||||
|
# This file will not receive any updates.
|
||||||
|
# This is my initial implementation of a crc32 checker.
|
||||||
|
# The code quality is kind of mediocre (as it was only intended for personal use)
|
||||||
|
# Still works perfectly fine and has the advantage of being compact (and not as bloated as the OO implementation)
|
||||||
|
|
||||||
|
|
||||||
|
# Cool things to come... eventually... maybe (when I'm motivated):
|
||||||
|
# - add support for sfv files
|
||||||
|
# - write checksums to files
|
||||||
|
# - better error handling (symlinks etc)
|
||||||
|
# - should under no circumstances crash (check for available memory)
|
||||||
|
# - lots and lots of cleanup
|
||||||
|
# - documentation
|
||||||
|
# - verify sfv files: re.fullmatch(r"^[0-9a-fA-F]$", s or "") is not None
|
||||||
|
# - contextmanagers are a cool way to handle exceptions https://www.python.org/dev/peps/pep-0343/
|
||||||
|
# - if possible move file handling into separate function (or if really necessary a class)
|
||||||
|
# - unit tests
|
||||||
|
# - maybe use a logging library
|
||||||
|
# - turn this into a proper library -> move stuff into separate files
|
||||||
|
|
||||||
|
"""
|
||||||
|
+---------------------+
|
||||||
|
| CRC32 sum generator |
|
||||||
|
+---------------------+
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from multiprocessing import Pool
|
||||||
|
from os import listdir, path
|
||||||
|
from typing import Generator, List, Tuple, Optional
|
||||||
|
from zlib import crc32
|
||||||
|
|
||||||
|
|
||||||
|
def file_search(pathlist: List[str]) -> Generator[Tuple[(Optional[str], str)], 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 crc32 sum (None if unknown)
|
||||||
|
| - a files path string
|
||||||
|
"""
|
||||||
|
for fpath in pathlist:
|
||||||
|
if path.isfile(fpath):
|
||||||
|
if len(fpath) > 4 and fpath[-4:] == ".sfv":
|
||||||
|
yield from sfv_read(fpath)
|
||||||
|
else:
|
||||||
|
yield (None, fpath)
|
||||||
|
continue
|
||||||
|
if path.isdir(fpath):
|
||||||
|
yield from file_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[Tuple[(Optional[str], str)], None, None]:
|
||||||
|
"""
|
||||||
|
Read sfv file.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as file:
|
||||||
|
yield from ((x.split()[-1], ' '.join(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}")
|
||||||
|
|
||||||
|
|
||||||
|
# This was never fully implemented before the OO rewrite - so it won't work.
|
||||||
|
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]
|
||||||
|
# Placeholder
|
||||||
|
file.write('\n'.join([x for x in ["hello" "world"]]))
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def checkmark(check: Optional[bool] = None) -> str:
|
||||||
|
"""
|
||||||
|
Takes optional bool and returns colored string.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
True: '\033[92m✓\033[0m',
|
||||||
|
False: '\033[91m❌\033[0m',
|
||||||
|
None: '\033[90?\033[0m'
|
||||||
|
}[check]
|
||||||
|
|
||||||
|
|
||||||
|
def file_check(filename: Tuple[Optional[str], str],
|
||||||
|
largefile: bool = False) -> Tuple[Tuple[str, str], bool]:
|
||||||
|
"""
|
||||||
|
Check given file and return checked file.
|
||||||
|
"""
|
||||||
|
cksum = ""
|
||||||
|
try:
|
||||||
|
with open(filename[1], 'rb') as file:
|
||||||
|
if not largefile:
|
||||||
|
cksum = str(hex(crc32(file.read())))[2:].upper()
|
||||||
|
else:
|
||||||
|
lastcksum = 0
|
||||||
|
for line in file:
|
||||||
|
lastcksum = crc32(line, lastcksum)
|
||||||
|
cksum = str(hex(lastcksum))[2:].upper()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"[WARN]: No such file or directory: {filename}")
|
||||||
|
if len(cksum) < 8:
|
||||||
|
cksum = ''.join([((8 - len(cksum)) * "0"), cksum])
|
||||||
|
check = ((cksum in filename[1].upper() and filename[0] is None) ^
|
||||||
|
(filename[0] is not None and cksum == filename[0].upper()))
|
||||||
|
print(f"{checkmark(check)} \t {cksum} \t {filename[1]}")
|
||||||
|
return ((cksum, filename[1]), check)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""
|
||||||
|
Main function, should only run when programm gets directly invoked.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(description="Calculate CRC32 of files")
|
||||||
|
parser.add_argument("-b", "--bigfiles",
|
||||||
|
help="parse files that exceed your memory limit",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-p", "--processes",
|
||||||
|
help="",
|
||||||
|
default=2,
|
||||||
|
type=int)
|
||||||
|
parser.add_argument("-c", "--checksfv",
|
||||||
|
help="",
|
||||||
|
default="",
|
||||||
|
type=str)
|
||||||
|
parser.add_argument("files",
|
||||||
|
help="files and folders to process",
|
||||||
|
nargs='*',
|
||||||
|
default=[])
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
file_list = file_search(args.files)
|
||||||
|
ppool = Pool(processes=args.processes)
|
||||||
|
file_list_checked = ppool.starmap(file_check, [(x, args.bigfiles)
|
||||||
|
for x in list(file_list)])
|
||||||
|
ppool.close()
|
||||||
|
print(f"[{len([x for x in file_list_checked if x[1]])}/{len(file_list_checked)}] Files passed")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exception: KeyboardInterrupt")
|
0
fck/__init__.py
Normal file
0
fck/__init__.py
Normal file
32
fck/checker.py
Normal file
32
fck/checker.py
Normal 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
18
fck/cktype/__init__.py
Normal 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
29
fck/cktype/crc32.py
Normal 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
18
fck/file.py
Normal 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
65
fck/fileutils.py
Normal 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
|
47
scripts/fck
Executable file
47
scripts/fck
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
+---------------------------------+
|
||||||
|
| CRC32 sum generator CLI utility |
|
||||||
|
+---------------------------------+
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from multiprocessing import Pool
|
||||||
|
from fck import checker, fileutils
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""
|
||||||
|
Main function, should only run when programm gets directly invoked.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(description="Calculate CRC32 of files")
|
||||||
|
parser.add_argument("-b", "--bigfiles",
|
||||||
|
help="parse files that exceed your memory limit",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-p", "--processes",
|
||||||
|
help="",
|
||||||
|
default=2,
|
||||||
|
type=int)
|
||||||
|
parser.add_argument("-c", "--checksfv",
|
||||||
|
help="",
|
||||||
|
default="",
|
||||||
|
type=str)
|
||||||
|
parser.add_argument("files",
|
||||||
|
help="files and folders to process",
|
||||||
|
nargs='*',
|
||||||
|
default=[])
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
file_list = fileutils.search(args.files)
|
||||||
|
ppool = Pool(processes=args.processes)
|
||||||
|
file_list_checked = ppool.starmap(checker.check, [(x, args.bigfiles)
|
||||||
|
for x in list(file_list)])
|
||||||
|
ppool.close()
|
||||||
|
print(f"[{len([x for x in file_list_checked if x])}/{len(file_list_checked)}] Files passed")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exception: KeyboardInterrupt")
|
12
setup.py
Normal file
12
setup.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='fck',
|
||||||
|
version='0.1',
|
||||||
|
description='A simple checksum utility that just works.',
|
||||||
|
url='https://git.ophanim.de/derped/fck',
|
||||||
|
python_requires='>3.8',
|
||||||
|
packages=['fck', 'fck/cktype'],
|
||||||
|
scripts=['scripts/fck'],
|
||||||
|
)
|
Loading…
Reference in a new issue