gtl 0.5.24

gtl is a Git-based tool designed to simplify the management of multiple remote repositories. It extends Git's functionality by providing one-click initialization and pushing to multiple remote repositories, making it especially useful for developers who need to maintain multiple remote repositories simultaneously.
#!/usr/bin/env python3
"""Normalize tracked files covered by .gitattributes before git push."""

from pathlib import Path
import subprocess
import sys

ROOT = Path(__file__).resolve().parents[1]
ATTRIBUTES = ROOT / ".gitattributes"


def tracked_files():
    result = subprocess.run(
        ["git", "ls-files", "-z"],
        cwd=ROOT,
        check=True,
        stdout=subprocess.PIPE,
    )
    return [ROOT / Path(item.decode("utf-8")) for item in result.stdout.split(b"\0") if item]


def attribute_patterns():
    patterns = []
    for line in ATTRIBUTES.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        parts = line.split()
        if len(parts) < 2 or parts[1] == "binary":
            continue
        if parts[1] == "text" and any(part == "eol=lf" for part in parts[2:]):
            patterns.append(parts[0])
    return patterns


def matches(path, patterns):
    relative = path.relative_to(ROOT).as_posix()
    name = path.name
    for pattern in patterns:
        if pattern.startswith("*.") and name.endswith(pattern[1:]):
            return True
        if pattern == relative or pattern == name:
            return True
    return False


def main():
    patterns = attribute_patterns()
    changed = []
    for path in tracked_files():
        if not matches(path, patterns):
            continue
        raw = path.read_bytes()
        normalized = raw.replace(b"\r\n", b"\n")
        if normalized != raw:
            path.write_bytes(normalized)
            changed.append(path.relative_to(ROOT).as_posix())
    for path in changed:
        print(f"LF: {path}")
    print(f"normalized {len(changed)} file(s)")
    return 0


if __name__ == "__main__":
    sys.exit(main())