diff --git a/services/tools/cli/base.py b/services/tools/cli/base.py index 219b4bb..29121c6 100644 --- a/services/tools/cli/base.py +++ b/services/tools/cli/base.py @@ -11,6 +11,9 @@ class Colors: WHITE = "\033[37m" class BaseCli: + def __init__(self, debug=False): + self.debug_enabled=debug + def info(self, message): print(f'[{Colors.GREEN}INFO{Colors.RESET}] {message}') @@ -19,4 +22,9 @@ class BaseCli: def error(self, message, exit_code=1): print(f'[{Colors.RED}ERROR{Colors.RESET}] {message}') - sys.exit(exit_code) \ No newline at end of file + sys.exit(exit_code) + + def debug(self, message): + if not self.debug_enabled: + return + print(f'[{Colors.BLUE}DEBUG{Colors.RESET}] {message}') \ No newline at end of file diff --git a/services/tools/cli/create_hardlinks.py b/services/tools/cli/create_hardlinks.py new file mode 100755 index 0000000..ecaaeb8 --- /dev/null +++ b/services/tools/cli/create_hardlinks.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +from argparse import ArgumentParser + +from args_utils import dir_arg_type +from base import BaseCli + +CLI_DESCRIPTION=''' +Create hard links of files from source to destination. +''' + +class CreateHardlinksCli(BaseCli): + + def configure_args(self, parser: ArgumentParser): + parser.add_argument( + '-s', + '--source', + required=True, + help="Source folder" + ) + parser.add_argument( + '-d', + '--destination', + required=True, + help="Destination folder", + ) + parser.add_argument( + '-v', + '--verbose', + help="Increase verbosity", + default=False, + action='store_true' + ) + + def process_args(self, parser: ArgumentParser): + args = parser.parse_args() + return args + + def __init__(self): + parser = ArgumentParser(description=CLI_DESCRIPTION) + self.configure_args(parser) + self.args = self.process_args(parser) + super().__init__(debug=self.args.verbose) + + def __create_file_ln__(self, src, dest): + if os.path.exists(dest): + self.debug(f"Hard link already exists: {dest} -> {src}") + else: + os.link(src, dest) + self.debug(f"Created hard link: {dest} -> {src}") + + def create_hardlinks(self, src, dest): + if not os.path.exists(dest): + os.makedirs(dest) + self.info(f"Created destination directory: {dest}") + + if os.path.isfile(src): + self.info('Source is a file. Hardlinking and quitting.') + dest_file = os.path.join(dest, os.path.basename(src)) + self.__create_file_ln__(src, dest_file) + return + + for dirpath, dirnames, filenames in os.walk(src): + relative_path = os.path.relpath(dirpath, src) + dest_dir = os.path.join(dest, relative_path) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + self.debug(f"Created directory: {dest_dir}") + + for filename in filenames: + src_file = os.path.join(dirpath, filename) + dest_file = os.path.join(dest_dir, filename) + self.__create_file_ln__(src_file, dest_file) + + + def print_tree(self, directory, level=0): + """Print the directory tree.""" + if level == 0: + self.info('Hardlinked Result:') + indent = " " * (level * 4) + print(f"{indent}{os.path.basename(directory)}/") + for item in os.listdir(directory): + path = os.path.join(directory, item) + if os.path.isdir(path): + self.print_tree(path, level + 1) + else: + print(f"{indent} {item}") + + + def count_files_in_directory(self, directory): + if not os.path.isdir(directory): + self.warning(f"Can't count files in {directory}, because it is a file") + return 0 + total_files = 0 + for dirpath, dirnames, filenames in os.walk(directory): + total_files += len(filenames) + return total_files + + def start(self): + self.create_hardlinks( + self.args.source, + self.args.destination + ) + self.print_tree(self.args.destination) + src_files = self.count_files_in_directory(self.args.source) + dest_files = self.count_files_in_directory(self.args.destination) + self.info(f'Files in source direcotry: {src_files}') + self.info(f'Files in destination directory: {dest_files}') + +def main(): + cli = CreateHardlinksCli() + cli.start() + +if __name__ == "__main__": + main()