|
| 1 | +""" |
| 2 | +Module for creating and populating yaml files |
| 3 | +""" |
| 4 | + |
| 5 | +import logging |
| 6 | +import os |
| 7 | +import platform |
| 8 | +import pathlib |
| 9 | +import subprocess |
| 10 | +from datetime import datetime |
| 11 | +from importlib.metadata import version |
| 12 | +if platform.system() != "Windows": |
| 13 | + import grp |
| 14 | + import pwd |
| 15 | +else: |
| 16 | + import getpass |
| 17 | + |
| 18 | + |
| 19 | +logger = logging.getLogger(__name__) |
| 20 | + |
| 21 | +def get_dust_metrics(path): |
| 22 | + """Calls dust to get size and file count.""" |
| 23 | + # Check if dust is installed in the current environment |
| 24 | + if subprocess.run(["which", "dust"], capture_output=True, check=False).returncode != 0: |
| 25 | + return "N/A (dust not found)", "N/A" |
| 26 | + |
| 27 | + size_cmd = ["dust", "-s", "-c", "-b", path] |
| 28 | + inode_cmd = ["dust", "-s", "-c", "-b", "-i", path] |
| 29 | + size_out = subprocess.check_output(size_cmd, text=True).split()[0] |
| 30 | + inode_out = subprocess.check_output(inode_cmd, text=True).split()[0] |
| 31 | + return size_out, inode_out |
| 32 | + |
| 33 | + |
| 34 | +def get_folder_context(path): |
| 35 | + """Retrieves owner, group, leader, and folder creation/change time.""" |
| 36 | + path_obj = pathlib.Path(path) |
| 37 | + stat_info = path_obj.stat() |
| 38 | + |
| 39 | + # Folder Creation Time |
| 40 | + try: |
| 41 | + created_ts = stat_info.st_birthtime |
| 42 | + except AttributeError: |
| 43 | + created_ts = stat_info.st_ctime |
| 44 | + folder_origin = datetime.fromtimestamp(created_ts).strftime('%Y-%m-%d') |
| 45 | + |
| 46 | + if platform.system() != "Windows": |
| 47 | + owner = pwd.getpwuid(stat_info.st_uid).pw_name |
| 48 | + process_owner = pwd.getpwuid(os.getuid()).pw_name |
| 49 | + group = grp.getgrgid(stat_info.st_gid).gr_name |
| 50 | + leader = "Manual Entry Required" |
| 51 | + else: |
| 52 | + owner = getpass.getuser() |
| 53 | + process_owner = owner |
| 54 | + group = os.environ.get("USERDOMAIN", "LocalGroup") |
| 55 | + leader = "N/A" |
| 56 | + |
| 57 | + return owner, process_owner, group, leader, folder_origin |
| 58 | + |
| 59 | + |
| 60 | +def generate_metadata(path, needed_until:str=None, overwrite:bool = False, verbose: bool = False): |
| 61 | + """ |
| 62 | + Generates meta.yml. |
| 63 | +
|
| 64 | + :param needed_until: Until when this folder is expected to be needed, |
| 65 | + can be a string in format '%Y-%m-%d' (e.g., "2026-12-31" ) or None. |
| 66 | + :param overwrite: Overwrite if metadata already exists? Default False |
| 67 | + :param verbose: enable verbose logging |
| 68 | + """ |
| 69 | + if verbose: |
| 70 | + logging.basicConfig(level=logging.DEBUG) |
| 71 | + file_path = os.path.join(path, "meta.yml") |
| 72 | + if os.path.exists(file_path) and not overwrite: |
| 73 | + logger.debug("Skipping: '%s' already exists.", file_path) |
| 74 | + logger.debug("Use 'overwrite=True' if you want to replace it.") |
| 75 | + return |
| 76 | + |
| 77 | + owner, process_owner, group, leader, folder_created = get_folder_context(path) |
| 78 | + size, inodes = get_dust_metrics(path) |
| 79 | + |
| 80 | + template = f"""# identification: |
| 81 | +pathtraits_version: {version("pathtraits")} |
| 82 | +yml_created_date: {datetime.now().strftime('%Y-%m-%d')} |
| 83 | +yml_created_by: "{process_owner}" |
| 84 | +folder_created_date: {folder_created} |
| 85 | +folder_owner: "{owner}" |
| 86 | +folder_owner_group: "{group}" |
| 87 | +folder_owner_group_lead: “{leader}" |
| 88 | +folder_no.files: {inodes} |
| 89 | +folder_size: {size} |
| 90 | +folder_needed_until: "{needed_until}" |
| 91 | +
|
| 92 | +# --- OPTIONAL FIELDS --- |
| 93 | +# project: "..." |
| 94 | +# tags: [] |
| 95 | +""" |
| 96 | + |
| 97 | + with open(file_path, "w", encoding="utf-8") as f: |
| 98 | + f.write(template) |
| 99 | + |
| 100 | + logger.debug("Successfully generated template at: %s", file_path) |
0 commit comments