secure-gate 0.3.2

Zero-overhead, feature-gated secure wrappers for secrets
#!/usr/bin/env python3
"""
package_aescrypt_rs.py
Packages Cargo.toml + all .rs files from src/ and tests/ (with recursive subfolders)
into a single .txt with TOC and timestamps.

Fixed: No duplicate files (e.g. src/crypto/mod.rs appears only once)
"""

from datetime import datetime
from pathlib import Path

# ========================== CONFIGURATION ==========================
PROJECT_TITLE = "secure_gate"
OUTPUT_DIR = "code_packages"
DEFAULT_OUTPUT_FILE = "secure_gate_package"
ENCODING = "utf-8"
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
OUTPUT_TIMESTAMP_FORMAT = "%Y%m%d_%H%M%S"

# Scan these base directories RECURSIVELY for *.rs
# Each base is scanned fully — no overlapping subpaths
RECURSIVE_BASES = [
    # "src",
    # "tests",
    "fuzz/fuzz_targets"
]

ROOT_FILES = [
    # "Cargo.toml",
    "fuzz/Cargo.toml"
]

# ===================================================================


def format_timestamp(ts):
    return datetime.fromtimestamp(ts).strftime(TIMESTAMP_FORMAT)[:-3]


def format_output_timestamp():
    return datetime.now().strftime(OUTPUT_TIMESTAMP_FORMAT)


def add_file(contents, toc, file_path: Path, root: Path):
    rel_path = file_path.relative_to(root).as_posix()
    content = file_path.read_text(encoding=ENCODING)
    ctime = format_timestamp(file_path.stat().st_ctime)
    mtime = format_timestamp(file_path.stat().st_mtime)
    idx = len(toc) + 1

    header = (
        f"\n\n\n================================================================================\n"
        f"// SECTION {idx:03d}: {rel_path}\n"
        f"// FILE: {rel_path}\n"
        f"// Created: {ctime}\n"
        f"// Modified: {mtime}\n"
        f"================================================================================\n"
    )

    contents.append(header + content.rstrip() + "\n")
    toc.append(rel_path)


def package_all_files(project_root=None, output_file=None):
    root = Path(project_root or Path.cwd()).resolve()
    output_file = output_file or DEFAULT_OUTPUT_FILE

    if not root.is_dir():
        raise FileNotFoundError(f"Project root not found: {root}")

    # Output setup
    out_dir = root / OUTPUT_DIR
    out_dir.mkdir(exist_ok=True)
    timestamp = format_output_timestamp()
    output_path = out_dir / f"{output_file}_{timestamp}.txt"

    file_contents = []
    toc_entries = []
    header_time = format_timestamp(datetime.now().timestamp())

    seen_paths = set()  # Prevent duplicates (safety)

    # === 1. Add root files ===
    for name in ROOT_FILES:
        path = root / name
        if path.is_file():
            rel = path.relative_to(root).as_posix()
            if rel not in seen_paths:
                add_file(file_contents, toc_entries, path, root)
                seen_paths.add(rel)
        else:
            print(f"Warning: Missing root file: {name}")

    # === 2. Add recursive .rs files from base dirs ===
    for base in RECURSIVE_BASES:
        base_dir = root / base
        if not base_dir.is_dir():
            print(f"Warning: Missing directory: {base_dir}")
            continue

        rs_files = sorted(
            base_dir.rglob("*.rs"),
            key=lambda p: p.relative_to(root).as_posix().lower()

        )

        for rs_file in rs_files:
            if not rs_file.is_file():
                continue
            rel = rs_file.relative_to(root).as_posix()
            if rel not in seen_paths:
                add_file(file_contents, toc_entries, rs_file, root)
                seen_paths.add(rel)

    # === 3. Build TOC ===
    toc_lines = [
        "// ============================================================================\n",
        "// Table of Contents\n",
        "// ============================================================================\n",
    ]
    for i, entry in enumerate(toc_entries, 1):
        toc_lines.append(f"// {i:03d}. {entry}\n")
    if not toc_entries:
        toc_lines.append("// None\n")
    toc_lines.append(
        "// ============================================================================\n\n")

    # === 4. Write package ===
    with output_path.open("w", encoding=ENCODING) as f:
        f.write(
            "// ============================================================================\n")
        f.write(f"// {PROJECT_TITLE} Project Package\n")
        f.write("// Package: Cargo.toml + All .rs files from src/** and tests/**\n")
        f.write(f"// Generated by: {Path(__file__).name}\n")
        f.write(f"// Timestamp: {header_time}\n")
        f.write(
            "// ============================================================================\n\n")
        f.writelines(toc_lines)
        f.writelines(file_contents)

    print(f"Success: Package created → {output_path.name}")
    print(f"Info: Included {len(file_contents)} unique files")


if __name__ == "__main__":
    package_all_files()