From d8a360d3b57525a914365eb4a30df91df9365bbb Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 21 Oct 2022 23:06:54 +0200 Subject: [PATCH] fix fzf find --- catcli/catcli.py | 18 ++++---- catcli/exceptions.py | 14 ++++++ catcli/noder.py | 102 ++++++++++++++++++++++++------------------- tests/test_update.py | 4 +- 4 files changed, 83 insertions(+), 55 deletions(-) create mode 100644 catcli/exceptions.py diff --git a/catcli/catcli.py b/catcli/catcli.py index 48bd596..e3077a3 100755 --- a/catcli/catcli.py +++ b/catcli/catcli.py @@ -20,6 +20,7 @@ from .catalog import Catalog from .walker import Walker from .noder import Noder from .utils import ask, edit +from .exceptions import BadFormatException, CatcliException NAME = 'catcli' CUR = os.path.dirname(os.path.abspath(__file__)) @@ -33,6 +34,7 @@ BANNER = f""" +-+-+-+-+-+-+ |c|a|t|c|l|i| +-+-+-+-+-+-+ v{VERSION}""" +# TODO add grep format for output USAGE = f""" {BANNER} @@ -155,7 +157,7 @@ def cmd_ls(args, noder, top): fmt = args['--format'] if fmt.startswith('fzf'): - raise Exception('fzf is not supported in ls') + raise BadFormatException('fzf is not supported in ls, use find') found = noder.walk(top, path, rec=args['--recursive'], fmt=fmt, @@ -188,9 +190,9 @@ def cmd_find(args, noder, top): raw = args['--raw-size'] script = args['--script'] search_for = args[''] - return noder.find_name(top, search_for, script=script, - startpath=startpath, directory=directory, - parentfromtree=fromtree, fmt=fmt, raw=raw) + noder.find_name(top, search_for, script=script, + startpath=startpath, directory=directory, + parentfromtree=fromtree, fmt=fmt, raw=raw) def cmd_tree(args, noder, top): @@ -261,9 +263,9 @@ def print_supported_formats(): """print all supported formats to stdout""" print('"native" : native format') print('"csv" : CSV format') - print(f' {Noder.CSV_HEADER}') - print('"fzf-native" : fzf with native output for selected entries') - print('"fzf-csv" : fzf with native output for selected entries') + print(f' {Noder.CSV_HEADER}') + print('"fzf-native" : fzf to native (only for find)') + print('"fzf-csv" : fzf to csv (only for find)') def main(): @@ -331,7 +333,7 @@ def main(): cmd_rename(args, catalog, top) elif args['edit']: cmd_edit(args, noder, catalog, top) - except Exception as exc: + except CatcliException as exc: Logger.out_err('ERROR ' + str(exc)) return False diff --git a/catcli/exceptions.py b/catcli/exceptions.py new file mode 100644 index 0000000..fce8f80 --- /dev/null +++ b/catcli/exceptions.py @@ -0,0 +1,14 @@ +""" +author: deadc0de6 (https://github.com/deadc0de6) +Copyright (c) 2022, deadc0de6 + +Catcli exceptions +""" + + +class CatcliException(Exception): + """generic catcli exception""" + + +class BadFormatException(CatcliException): + """use of bad format""" diff --git a/catcli/noder.py b/catcli/noder.py index 5e78855..3a7004f 100644 --- a/catcli/noder.py +++ b/catcli/noder.py @@ -402,7 +402,6 @@ class Noder: Logger.dir(pre, name, depth=depth, attr=attr) elif node.type == self.TYPE_STORAGE: # node of type storage - szfree = size_to_str(node.free, raw=raw) sztotal = size_to_str(node.total, raw=raw) szused = size_to_str(node.total - node.free, raw=raw) nbchildren = len(node.children) @@ -438,7 +437,7 @@ class Noder: else: Logger.err(f'bad node encountered: {node}') - def print_tree(self, top, node, + def print_tree(self, node, fmt='native', raw=False): """ @@ -455,14 +454,11 @@ class Noder: self._print_node(thenode, pre=pre, withdepth=True, raw=raw) elif fmt == 'csv': # csv output - self._to_csv(node, with_header=header, raw=raw) + self._to_csv(node, raw=raw) elif fmt == 'csv-with-header': # csv output Logger.out(self.CSV_HEADER) - self._to_csv(node, with_header=header, raw=raw) - elif fmt.startswith('fzf'): - # flat - self._to_fzf(top, node, fmt) + self._to_csv(node, raw=raw) def _to_csv(self, node, raw=False): """print the tree to csv""" @@ -476,10 +472,9 @@ class Noder: selected = fzf.prompt(strings) return selected - def _to_fzf(self, top, node, fmt): + def _to_fzf(self, node, fmt): """ print node to fzf - @top: top node @node: node to start with @fmt: output format for selected nodes """ @@ -503,7 +498,7 @@ class Noder: if path not in nodes: continue rend = nodes[path] - self.print_tree(top, rend, fmt=subfmt) + self.print_tree(rend, fmt=subfmt) def to_dot(self, node, path='tree.dot'): """export to dot for graphing""" @@ -529,72 +524,81 @@ class Noder: @fmt: output format @raw: raw size output """ - ## TODO error with fzf self._debug(f'searching for \"{key}\"') - if not key: - # nothing to search for - return None + + # search for nodes based on path start = top if startpath: start = self.get_node(top, startpath) - found = anytree.findall(start, filter_=self._callback_find_name(key)) + filterfunc = self._callback_find_name(key, directory) + found = anytree.findall(start, filter_=filterfunc) nbfound = len(found) self._debug(f'found {nbfound} node(s)') # compile found nodes paths = {} - nodes = [] for item in found: - if item.type == self.TYPE_STORAGE: - # ignore storage nodes - continue - if directory and item.type != self.TYPE_DIR: - # ignore non directory - continue - nodes.append(item) - + item = self._sanitize(item) if parentfromtree: paths[self._get_parents(item)] = item else: paths[item.relpath] = item - if fmt == 'native': - for item in nodes: - self._print_node(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) - for item in nodes: - self._node_to_csv(item, raw=raw) - - elif fmt.startswith('fzf'): - selected = self._fzf_prompt(paths) + # handle fzf mode + if fmt.startswith('fzf'): + selected = self._fzf_prompt(paths.keys()) newpaths = {} subfmt = fmt.replace('fzf-', '') for item in selected: if item not in paths: continue newpaths[item] = paths[item] - self.print_tree(top, newpaths[item], fmt=subfmt) + self.print_tree(newpaths[item], fmt=subfmt) paths = newpaths + else: + if fmt == 'native': + for _, item in paths.items(): + self._print_node(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) + for _, item in paths.items(): + self._node_to_csv(item, raw=raw) + # execute script if any if script: tmp = ['${source}/' + x for x in paths] tmpstr = ' '.join(tmp) cmd = f'op=file; source=/media/mnt; $op {tmpstr}' Logger.info(cmd) - return found - - def _callback_find_name(self, term): + def _callback_find_name(self, term, directory): """callback for finding files""" def find_name(node): + if node.type == self.TYPE_STORAGE: + # ignore storage nodes + return False + if node.type == self.TYPE_TOP: + # ignore top nodes + return False + if node.type == self.TYPE_META: + # ignore meta nodes + return False + if directory and node.type != self.TYPE_DIR: + # ignore non directory + return False + + # filter + if not term: + return True if term.lower() in node.name.lower(): return True + + # ignore return False return find_name @@ -623,7 +627,7 @@ class Noder: if rec: # print the entire tree - self.print_tree(top, found[0].parent, fmt=fmt, raw=raw) + self.print_tree(found[0].parent, fmt=fmt, raw=raw) return found # sort found nodes @@ -650,7 +654,7 @@ class Noder: elif fmt.startswith('csv'): self._node_to_csv(item, raw=raw) elif fmt.startswith('fzf'): - self._to_fzf(top, item, fmt) + self._to_fzf(item, fmt) except anytree.resolver.ChildResolverError: pass @@ -732,6 +736,14 @@ class Noder: """return md5 hash of node""" return md5sum(path) + def _sanitize(self, node): + """sanitize node string""" + node.name = node.name.encode('utf-8', + errors='ignore').decode('utf-8') + node.relpath = node.relpath.encode('utf-8', + errors='ignore').decode('utf-8') + return node + def _debug(self, string): """print debug""" if not self.debug: diff --git a/tests/test_update.py b/tests/test_update.py index e385cb1..fc478e7 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -78,7 +78,7 @@ class TestUpdate(unittest.TestCase): self.assertTrue(nod.md5 == f4_md5) # print catalog - noder.print_tree(top, top) + noder.print_tree(top) # add some files and directories new1 = create_rnd_file(dir1, 'newf1') @@ -120,7 +120,7 @@ class TestUpdate(unittest.TestCase): # print catalog # print(read_from_file(catalogpath)) - noder.print_tree(top, top) + noder.print_tree(top) # explore the top node to find all nodes self.assertTrue(len(top.children) == 1)