diff --git a/catcli/catcli.py b/catcli/catcli.py index 661877d..b3f95d9 100755 --- a/catcli/catcli.py +++ b/catcli/catcli.py @@ -16,6 +16,7 @@ from docopt import docopt # local imports from .version import __version__ as VERSION from .logger import Logger +from .colors import Colors from .catalog import Catalog from .walker import Walker from .noder import Noder @@ -257,8 +258,8 @@ def cmd_edit(args, noder, catalog, top): def banner(): """print banner""" - Logger.out_err(BANNER) - Logger.out_err("") + Logger.stderr_nocolor(BANNER) + Logger.stderr_nocolor("") def print_supported_formats(): @@ -298,7 +299,7 @@ def main(): # set colors if args['--no-color']: - Logger.no_color() + Colors.no_color() # init noder noder = Noder(debug=args['--verbose'], sortsize=args['--sortsize'], @@ -336,7 +337,7 @@ def main(): elif args['edit']: cmd_edit(args, noder, catalog, top) except CatcliException as exc: - Logger.out_err('ERROR ' + str(exc)) + Logger.stderr_nocolor('ERROR ' + str(exc)) return False return True diff --git a/catcli/colors.py b/catcli/colors.py new file mode 100644 index 0000000..e53cd6c --- /dev/null +++ b/catcli/colors.py @@ -0,0 +1,37 @@ +""" +author: deadc0de6 (https://github.com/deadc0de6) +Copyright (c) 2022, deadc0de6 + +shell colors +""" + + +class Colors: + """shell colors""" + + RED = '\033[91m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + PURPLE = '\033[1;35m' + BLUE = '\033[94m' + GRAY = '\033[0;37m' + MAGENTA = '\033[95m' + RESET = '\033[0m' + EMPH = '\033[33m' + BOLD = '\033[1m' + UND = '\033[4m' + + @classmethod + def no_color(cls): + """disable colors""" + Colors.RED = '' + Colors.GREEN = '' + Colors.YELLOW = '' + Colors.PURPLE = '' + Colors.BLUE = '' + Colors.GRAY = '' + Colors.MAGENTA = '' + Colors.RESET = '' + Colors.EMPH = '' + Colors.BOLD = '' + Colors.UND = '' diff --git a/catcli/logger.py b/catcli/logger.py index 59d1ae5..586b033 100644 --- a/catcli/logger.py +++ b/catcli/logger.py @@ -8,99 +8,21 @@ Logging helper import sys # local imports +from catcli.colors import Colors from catcli.utils import fix_badchars class Logger: """log to stdout/stderr""" - RED = '\033[91m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - PURPLE = '\033[1;35m' - BLUE = '\033[94m' - GRAY = '\033[0;37m' - MAGENTA = '\033[95m' - RESET = '\033[0m' - EMPH = '\033[33m' - BOLD = '\033[1m' - UND = '\033[4m' - - STORAGE = 'storage' - ARCHIVE = 'archive' - NBFILES = 'nbfiles' - @classmethod - def no_color(cls): - """disable colors""" - Logger.RED = '' - Logger.GREEN = '' - Logger.YELLOW = '' - Logger.PURPLE = '' - Logger.BLUE = '' - Logger.GRAY = '' - Logger.MAGENTA = '' - Logger.RESET = '' - Logger.EMPH = '' - Logger.BOLD = '' - Logger.UND = '' - - ###################################################################### - # node specific output - ###################################################################### - @classmethod - def storage(cls, pre, name, args, attr): - """print a storage node""" - end = '' - if attr: - end = f' {Logger.GRAY}({attr}){Logger.RESET}' - out = f'{pre}{Logger.UND}{Logger.STORAGE}{Logger.RESET}:' - out += ' ' + Logger.PURPLE + fix_badchars(name) + \ - Logger.RESET + end + '\n' - out += f' {Logger.GRAY}{args}{Logger.RESET}' - sys.stdout.write(f'{out}\n') - - @classmethod - def file(cls, pre, name, attr): - """print a file node""" - nobad = fix_badchars(name) - out = f'{pre}{nobad}' - out += f' {Logger.GRAY}[{attr}]{Logger.RESET}' - sys.stdout.write(f'{out}\n') - - @classmethod - def dir(cls, pre, name, depth='', attr=None): - """print a directory node""" - end = [] - if depth != '': - end.append(f'{Logger.NBFILES}:{depth}') - if attr: - end.append(' '.join([f'{x}:{y}' for x, y in attr])) - if end: - endstring = ', '.join(end) - end = f' [{endstring}]' - out = pre + Logger.BLUE + fix_badchars(name) + Logger.RESET - out += f'{Logger.GRAY}{end}{Logger.RESET}' - sys.stdout.write(f'{out}\n') - - @classmethod - def arc(cls, pre, name, archive): - """archive to stdout""" - out = pre + Logger.YELLOW + fix_badchars(name) + Logger.RESET - out += f' {Logger.GRAY}[{Logger.ARCHIVE}:{archive}]{Logger.RESET}' - sys.stdout.write(f'{out}\n') - - ###################################################################### - # generic output - ###################################################################### - @classmethod - def out(cls, string): + def stdout_nocolor(cls, string): """to stdout no color""" string = fix_badchars(string) sys.stdout.write(f'{string}\n') @classmethod - def out_err(cls, string): + def stderr_nocolor(cls, string): """to stderr no color""" string = fix_badchars(string) sys.stderr.write(f'{string}\n') @@ -108,21 +30,20 @@ class Logger: @classmethod def debug(cls, string): """to stderr no color""" - string = fix_badchars(string) - sys.stderr.write(f'[DBG] {string}\n') + cls.stderr_nocolor(f'[DBG] {string}\n') @classmethod def info(cls, string): """to stdout in color""" string = fix_badchars(string) - out = f'{Logger.MAGENTA}{string}{Logger.RESET}' + out = f'{Colors.MAGENTA}{string}{Colors.RESET}' sys.stdout.write(f'{out}\n') @classmethod def err(cls, string): """to stderr in RED""" string = fix_badchars(string) - out = f'{Logger.RED}{string}{Logger.RESET}' + out = f'{Colors.RED}{string}{Colors.RESET}' sys.stderr.write(f'{out}\n') @classmethod @@ -133,14 +54,14 @@ class Logger: sys.stderr.flush() @classmethod - def bold(cls, string): + def get_bold_text(cls, string): """make it bold""" string = fix_badchars(string) - return f'{Logger.BOLD}{string}{Logger.RESET}' + return f'{Colors.BOLD}{string}{Colors.RESET}' @classmethod - def flog(cls, path, string, append=True): - """log and fix bad chars""" + def log_to_file(cls, path, string, append=True): + """log to file""" string = fix_badchars(string) mode = 'w' if append: diff --git a/catcli/nodeprinter.py b/catcli/nodeprinter.py new file mode 100644 index 0000000..b43613b --- /dev/null +++ b/catcli/nodeprinter.py @@ -0,0 +1,61 @@ +""" +author: deadc0de6 (https://github.com/deadc0de6) +Copyright (c) 2022, deadc0de6 + +Class for printing nodes +""" + +import sys + +from catcli.colors import Colors +from catcli.utils import fix_badchars + + +class NodePrinter: + """a node printer class""" + + STORAGE = 'storage' + ARCHIVE = 'archive' + NBFILES = 'nbfiles' + + @classmethod + def print_storage_native(cls, pre, name, args, attr): + """print a storage node""" + end = '' + if attr: + end = f' {Colors.GRAY}({attr}){Colors.RESET}' + out = f'{pre}{Colors.UND}{cls.STORAGE}{Colors.RESET}:' + out += ' ' + Colors.PURPLE + fix_badchars(name) + \ + Colors.RESET + end + '\n' + out += f' {Colors.GRAY}{args}{Colors.RESET}' + sys.stdout.write(f'{out}\n') + + @classmethod + def print_file_native(cls, pre, name, attr): + """print a file node""" + nobad = fix_badchars(name) + out = f'{pre}{nobad}' + out += f' {Colors.GRAY}[{attr}]{Colors.RESET}' + sys.stdout.write(f'{out}\n') + + @classmethod + def print_dir_native(cls, pre, name, depth='', attr=None): + """print a directory node""" + end = [] + if depth != '': + end.append(f'{cls.NBFILES}:{depth}') + if attr: + end.append(' '.join([f'{x}:{y}' for x, y in attr])) + if end: + endstring = ', '.join(end) + end = f' [{endstring}]' + out = pre + Colors.BLUE + fix_badchars(name) + Colors.RESET + out += f'{Colors.GRAY}{end}{Colors.RESET}' + sys.stdout.write(f'{out}\n') + + @classmethod + def print_archive_native(cls, pre, name, archive): + """archive to stdout""" + out = pre + Colors.YELLOW + fix_badchars(name) + Colors.RESET + out += f' {Colors.GRAY}[{cls.ARCHIVE}:{archive}]{Colors.RESET}' + sys.stdout.write(f'{out}\n') diff --git a/catcli/noder.py b/catcli/noder.py index b3d4c3f..0e58a06 100644 --- a/catcli/noder.py +++ b/catcli/noder.py @@ -14,6 +14,7 @@ from pyfzf.pyfzf import FzfPrompt # local imports from catcli.utils import size_to_str, epoch_to_str, md5sum, fix_badchars from catcli.logger import Logger +from catcli.nodeprinter import NodePrinter from catcli.decomp import Decomp from catcli.version import __version__ as VERSION from catcli.exceptions import CatcliException @@ -343,11 +344,11 @@ class Noder: line = sep.join(['"' + o + '"' for o in out]) if len(line) > 0: - Logger.out(line) + Logger.stdout_nocolor(line) - def _print_node(self, node, pre='', withpath=False, - withdepth=False, withstorage=False, - recalcparent=False, raw=False): + def _print_node_native(self, node, pre='', withpath=False, + withdepth=False, withstorage=False, + recalcparent=False, raw=False): """ print a node @node: the node to print @@ -360,7 +361,7 @@ class Noder: """ if node.type == self.TYPE_TOP: # top node - Logger.out(f'{pre}{node.name}') + Logger.stdout_nocolor(f'{pre}{node.name}') elif node.type == self.TYPE_FILE: # node of type file name = node.name @@ -378,9 +379,9 @@ class Noder: size = size_to_str(node.size, raw=raw) compl = f'size:{size}{attr}' if withstorage: - content = Logger.bold(storage.name) + content = Logger.get_bold_text(storage.name) compl += f', storage:{content}' - Logger.file(pre, name, compl) + NodePrinter.print_file_native(pre, name, compl) elif node.type == self.TYPE_DIR: # node of type directory name = node.name @@ -399,8 +400,8 @@ class Noder: if node.size: attr.append(['totsize', size_to_str(node.size, raw=raw)]) if withstorage: - attr.append(['storage', Logger.bold(storage.name)]) - Logger.dir(pre, name, depth=depth, attr=attr) + attr.append(['storage', Logger.get_bold_text(storage.name)]) + NodePrinter.print_dir_native(pre, name, depth=depth, attr=attr) elif node.type == self.TYPE_STORAGE: # node of type storage sztotal = size_to_str(node.total, raw=raw) @@ -427,14 +428,14 @@ class Noder: 'du:' + f'{szused}/{sztotal}', timestamp] argsstring = ' | '.join(args) - Logger.storage(pre, - name, - argsstring, - node.attr) + NodePrinter.print_storage_native(pre, + name, + argsstring, + node.attr) elif node.type == self.TYPE_ARC: # archive node if self.arc: - Logger.arc(pre, node.name, node.archive) + NodePrinter.print_archive_native(pre, node.name, node.archive) else: Logger.err(f'bad node encountered: {node}') @@ -452,13 +453,14 @@ class Noder: # "tree" style rend = anytree.RenderTree(node, childiter=self._sort_tree) for pre, _, thenode in rend: - self._print_node(thenode, pre=pre, withdepth=True, raw=raw) + self._print_node_native(thenode, pre=pre, + withdepth=True, raw=raw) elif fmt == 'csv': # csv output self._to_csv(node, raw=raw) elif fmt == 'csv-with-header': # csv output - Logger.out(self.CSV_HEADER) + Logger.stdout_nocolor(self.CSV_HEADER) self._to_csv(node, raw=raw) def _to_csv(self, node, raw=False): @@ -560,14 +562,14 @@ class Noder: else: if fmt == 'native': for _, item in paths.items(): - self._print_node(item, withpath=True, - withdepth=True, - withstorage=True, - recalcparent=parentfromtree, - raw=raw) + self._print_node_native(item, withpath=True, + withdepth=True, + withstorage=True, + recalcparent=parentfromtree, + raw=raw) elif fmt.startswith('csv'): if fmt == 'csv-with-header': - Logger.out(self.CSV_HEADER) + Logger.stdout_nocolor(self.CSV_HEADER) for _, item in paths.items(): self._node_to_csv(item, raw=raw) @@ -643,8 +645,10 @@ class Noder: # print the parent if fmt == 'native': - self._print_node(found[0].parent, - withpath=False, withdepth=True, raw=raw) + self._print_node_native(found[0].parent, + withpath=False, + withdepth=True, + raw=raw) elif fmt.startswith('csv'): self._node_to_csv(found[0].parent, raw=raw) elif fmt.startswith('fzf'): @@ -652,13 +656,13 @@ class Noder: # print all found nodes if fmt == 'csv-with-header': - Logger.out(self.CSV_HEADER) + Logger.stdout_nocolor(self.CSV_HEADER) for item in found: if fmt == 'native': - self._print_node(item, withpath=False, - pre='- ', - withdepth=True, - raw=raw) + self._print_node_native(item, withpath=False, + pre='- ', + withdepth=True, + raw=raw) elif fmt.startswith('csv'): self._node_to_csv(item, raw=raw) elif fmt.startswith('fzf'): diff --git a/catcli/walker.py b/catcli/walker.py index 797f1ad..7063698 100644 --- a/catcli/walker.py +++ b/catcli/walker.py @@ -175,4 +175,4 @@ class Walker: if not self.lpath: return line = f'{string}\n' - Logger.flog(self.lpath, line, append=True) + Logger.log_to_file(self.lpath, line, append=True) diff --git a/tests.sh b/tests.sh index 35d5501..040de1a 100755 --- a/tests.sh +++ b/tests.sh @@ -7,9 +7,11 @@ cur=$(dirname "$(readlink -f "${0}")") # stop on first error set -ev +pycodestyle --version pycodestyle --ignore=W605 catcli/ pycodestyle tests/ +pyflakes --version pyflakes catcli/ pyflakes tests/ @@ -18,12 +20,15 @@ pyflakes tests/ # R0912: Too many branches # R0915: Too many statements # R0911: Too many return statements +# R0903: Too few public methods +pylint --version pylint \ --disable=R0914 \ --disable=R0913 \ --disable=R0912 \ --disable=R0915 \ --disable=R0911 \ + --disable=R0903 \ catcli/ pylint \ --disable=W0212 \