diff --git a/catcli/catcli.py b/catcli/catcli.py index c7e9292..1bb6225 100755 --- a/catcli/catcli.py +++ b/catcli/catcli.py @@ -36,11 +36,11 @@ USAGE = """ {0} Usage: - {1} index [--catalog=] [--meta=...] [-fcuV] - {1} ls [--catalog=] [-rVS] [] + {1} index [--catalog=] [--meta=...] [-acfuV] + {1} ls [--catalog=] [-arVS] [] {1} find [--catalog=] [-bV] {1} rm [--catalog=] [-fV] - {1} tree [--catalog=] [-VS] [] + {1} tree [--catalog=] [-aVS] [] {1} rename [--catalog=] [-fV] {1} edit [--catalog=] [-fV] {1} graph [--catalog=] [-V] [] @@ -52,6 +52,7 @@ Options: --catalog= Path to the catalog [default: {2}]. --meta= Additional attribute to store [default: ]. -u --subsize Store size of folders [default: False]. + -a --archive Handle archive file [default: False]. -f --force Force overwrite [default: False]. -b --script Output script to manage found file(s) [default: False]. -S --sortsize Sort by size, largest first [default: False]. @@ -184,7 +185,8 @@ def main(): banner() # init noder - noder = Noder(verbose=args['--verbose'], sortsize=args['--sortsize']) + noder = Noder(verbose=args['--verbose'], sortsize=args['--sortsize'], + arc=args['--archive']) # init catalog catalog = Catalog(args['--catalog'], verbose=args['--verbose'], force=args['--force']) diff --git a/catcli/decomp.py b/catcli/decomp.py new file mode 100644 index 0000000..77e5cd1 --- /dev/null +++ b/catcli/decomp.py @@ -0,0 +1,52 @@ +""" +author: deadc0de6 (https://github.com/deadc0de6) +Copyright (c) 2017, deadc0de6 + +Catcli generic compressed data lister +""" + +import sys +import os +import tarfile +import zipfile + + +class Decomp: + + def __init__(self): + self.ext = { + 'tar': self._tar, + 'tgz': self._tar, + 'gz': self._tar, + 'tar.gz': self._tar, + 'xz': self._tar, + 'tar.xz': self._tar, + 'lzma': self._tar, + 'tar.lzma': self._tar, + 'tlz': self._tar, + 'bz2': self._tar, + 'tar.bz2': self._tar, + 'zip': self._zip + } + + def get_format(self): + return list(self.ext.keys()) + + def get_names(self, path): + ''' get tree of compressed archive ''' + ext = os.path.splitext(path)[1][1:] + if ext in list(self.ext.keys()): + return self.ext[ext](path) + return None + + def _tar(self, path): + if not tarfile.is_tarfile(path): + return None + tar = tarfile.open(path, "r") + return tar.getnames() + + def _zip(self, path): + if not zipfile.is_zipfile(path): + return None + z = zipfile.ZipFile(path) + return z.namelist() diff --git a/catcli/logger.py b/catcli/logger.py index 0acfebe..5d77f4a 100644 --- a/catcli/logger.py +++ b/catcli/logger.py @@ -56,6 +56,11 @@ class Logger: s += '{}{}{}'.format(Logger.GRAY, end, Logger.RESET) sys.stdout.write(s+'\n') + def arc(pre, name, archive): + s = '{}{}{}{}'.format(pre, Logger.YELLOW, name, Logger.RESET) + s += ' {}[archive:{}]{}'.format(Logger.GRAY, archive, Logger.RESET) + sys.stdout.write(s+'\n') + ###################################################################### # generic output ###################################################################### diff --git a/catcli/noder.py b/catcli/noder.py index 59551ad..6ddad8d 100644 --- a/catcli/noder.py +++ b/catcli/noder.py @@ -14,6 +14,7 @@ import time from . import __version__ as VERSION import catcli.utils as utils from catcli.logger import Logger +from catcli.decomp import Decomp ''' There are 4 types of node: @@ -31,13 +32,17 @@ class Noder: TYPE_TOP = 'top' # tip top ;-) TYPE_FILE = 'file' TYPE_DIR = 'dir' + TYPE_ARC = 'arc' TYPE_STORAGE = 'storage' TYPE_META = 'meta' - def __init__(self, verbose=False, sortsize=False): + def __init__(self, verbose=False, sortsize=False, arc=False): self.hash = True self.verbose = verbose self.sortsize = sortsize + self.arc = arc + if self.arc: + self.decomp = Decomp() def set_hashing(self, val): self.hash = val @@ -96,8 +101,15 @@ class Noder: md5 = utils.md5sum(path) relpath = os.path.join(os.path.basename(storagepath), os.path.relpath(path, start=storagepath)) - return self._node(name, self.TYPE_FILE, relpath, parent, - size=st.st_size, md5=md5) + + n = self._node(name, self.TYPE_FILE, relpath, parent, + size=st.st_size, md5=md5) + if self.arc: + ext = os.path.splitext(path)[1][1:] + if ext in self.decomp.get_format(): + names = self.decomp.get_names(path) + self.list_to_tree(n, names) + return n def dir_node(self, name, path, parent, storagepath): ''' create a new node representing a directory ''' @@ -114,6 +126,11 @@ class Noder: return anytree.AnyNode(name=name, type=self.TYPE_STORAGE, free=free, total=total, parent=parent, attr=attr, ts=epoch) + def archive_node(self, name, path, parent, archive): + return anytree.AnyNode(name=name, type=self.TYPE_ARC, relpath=path, + parent=parent, size=0, md5=None, + archive=archive) + def _node(self, name, type, relpath, parent, size=None, md5=None): ''' generic node creation ''' return anytree.AnyNode(name=name, type=type, relpath=relpath, @@ -160,6 +177,9 @@ class Noder: ht = utils.human(node.total) name = '{} (free:{}, total:{})'.format(node.name, hf, ht) Logger.storage(pre, name, node.attr) + elif node.type == self.TYPE_ARC: + if self.arc: + Logger.arc(pre, node.name, node.archive) else: Logger.err('Weird node encountered: {}'.format(node)) # Logger.out('{}{}'.format(pre, node.name)) @@ -224,6 +244,36 @@ class Noder: pass return found + ############################################################### + # tree creationg + ############################################################### + def _add_entry(self, name, top, resolv): + ''' add an entry to the tree ''' + entries = name.rstrip(os.sep).split(os.sep) + if len(entries) == 1: + self.archive_node(name, name, top, top.name) + return + sub = os.sep.join(entries[:-1]) + f = entries[-1] + try: + parent = resolv.get(top, sub) + parent = self.archive_node(f, name, parent, top.name) + except anytree.resolver.ChildResolverError: + self.archive_node(f, name, top, top.name) + + def list_to_tree(self, parent, names): + ''' convert list of files to a tree ''' + if not names: + return + r = anytree.resolver.Resolver('name') + # dirty trick for zip lists + first = names[0].split(os.sep) + if len(first) > 1: + self.archive_node(first[0], first[0], parent, parent.name) + + for name in names: + self._add_entry(name, parent, r) + ############################################################### # diverse ###############################################################