tools: add cli for hardlinks

This commit is contained in:
tylen 2025-06-17 00:44:34 +03:00
parent 1f8a64601b
commit bb49652985
2 changed files with 127 additions and 1 deletions

View File

@ -11,6 +11,9 @@ class Colors:
WHITE = "\033[37m" WHITE = "\033[37m"
class BaseCli: class BaseCli:
def __init__(self, debug=False):
self.debug_enabled=debug
def info(self, message): def info(self, message):
print(f'[{Colors.GREEN}INFO{Colors.RESET}] {message}') print(f'[{Colors.GREEN}INFO{Colors.RESET}] {message}')
@ -20,3 +23,8 @@ class BaseCli:
def error(self, message, exit_code=1): def error(self, message, exit_code=1):
print(f'[{Colors.RED}ERROR{Colors.RESET}] {message}') print(f'[{Colors.RED}ERROR{Colors.RESET}] {message}')
sys.exit(exit_code) sys.exit(exit_code)
def debug(self, message):
if not self.debug_enabled:
return
print(f'[{Colors.BLUE}DEBUG{Colors.RESET}] {message}')

View File

@ -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()