diff --git a/swh/scanner/exceptions.py b/swh/scanner/exceptions.py new file mode 100644 index 0000000..5c8d6d8 --- /dev/null +++ b/swh/scanner/exceptions.py @@ -0,0 +1,8 @@ +class InvalidPath(Exception): + def __str__(self): + return 'the provided path is invalid: "%s"' % self.args + + +class APIError(Exception): + def __str__(self): + return 'API Error: "%s"' % self.args diff --git a/swh/scanner/logger.py b/swh/scanner/logger.py new file mode 100644 index 0000000..b45e7e3 --- /dev/null +++ b/swh/scanner/logger.py @@ -0,0 +1,61 @@ +# Copyright (C) 2020 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import logging + + +logger = None + + +def init(**kwargs): + def decorate(func): + for k in kwargs: + setattr(func, k, kwargs[k]) + return func + return decorate + + +def setup_logger(verbose: bool) -> None: + global logger + console = logging.FileHandler('scan.log') + console.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s | %(levelname)s: %(message)s') + console.setFormatter(formatter) + + logger = logging.getLogger('debug') + logger.addHandler(console) + if not verbose: + logger.propagate = False + + +@init(count=0) +def log_queries(n: int) -> None: + if logger is not None: + log_queries.count += n + + +def log_counters() -> None: + if logger is not None: + logger.info('number of queries: %s' % log_queries.count) + + +def error(*args) -> None: + if logger is not None: + logger.error(args) + + +def warning(*args) -> None: + if logger is not None: + logger.warning(args) + + +def info(*args) -> None: + if logger is not None: + logger.info(args) + + +def debug(*args): + if logger is not None: + logger.debug(args) diff --git a/swh/scanner/model.py b/swh/scanner/model.py new file mode 100644 index 0000000..c46e618 --- /dev/null +++ b/swh/scanner/model.py @@ -0,0 +1,76 @@ +# Copyright (C) 2020 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from __future__ import annotations +from pathlib import PosixPath +from typing import Any, Dict +from enum import Enum + +from swh.model.identifiers import ( + DIRECTORY, CONTENT +) + + +class Color(Enum): + blue = '\033[94m' + green = '\033[92m' + red = '\033[91m' + end = '\033[0m' + + +def colorize(text: str, color: Color): + return color.value + text + Color.end.value + + +class Tree: + """Representation of a file system structure + """ + def __init__(self, father: Tree, path: PosixPath): + self.father = father + self.path = path + self.otype = DIRECTORY if path.is_dir() else CONTENT + self.pid = '' + self.children: Dict[PosixPath, Tree] = {} + + def addNode(self, path: PosixPath, pid: str = None) -> None: + """Recursively add a new node path + """ + relative_path = path.relative_to(self.path) + + if relative_path == PosixPath('.'): + if pid is not None: + self.pid = pid + return + + new_path = self.path.joinpath(relative_path.parts[0]) + if new_path not in self.children: + self.children[new_path] = Tree(self, new_path) + + self.children[new_path].addNode(path, pid) + + def show(self) -> None: + """Print all the tree""" + print(Color.blue.value+str(self.path)+Color.end.value) + self.printChildren() + + def printChildren(self, inc: int = 0) -> None: + for path, node in self.children.items(): + self.printNode(node, inc) + if node.children: + node.printChildren(inc+1) + + def printNode(self, node: Any, inc: int) -> None: + rel_path = str(node.path.relative_to(self.path)) + if node.otype == DIRECTORY: + if node.pid: + print('│ '*inc + colorize(rel_path, Color.blue) + '/') + else: + print('│ '*inc + colorize(rel_path, Color.red) + '/') + + if node.otype == CONTENT: + if node.pid: + print('│ '*inc + colorize(rel_path, Color.green)) + else: + print('│ '*inc + colorize(rel_path, Color.red))