106 lines
3.0 KiB
Python
Executable File
106 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from typing import Optional, Iterable
|
|
from pathlib import Path
|
|
from argparse import ArgumentParser
|
|
from os import SEEK_END
|
|
|
|
|
|
def check_line(path: Path, line: str) -> bool:
|
|
if not path.exists():
|
|
return False
|
|
elif path.is_file():
|
|
with open(path, "r") as f:
|
|
return line in f.read()
|
|
return True
|
|
|
|
|
|
def write_line(path: Path, line: str):
|
|
with open(path, "w+") as f:
|
|
f.seek(0, SEEK_END)
|
|
if f.tell() > 0:
|
|
f.seek(f.tell() - 1, 0)
|
|
last_char = f.read()
|
|
if last_char != "\n":
|
|
f.write("\n")
|
|
f.write(line + "\n")
|
|
|
|
|
|
def resolve(parent: Path, line: str) -> Iterable[str]:
|
|
if line.startswith("#") or len(line.strip()) == 0:
|
|
return
|
|
|
|
negate = line.startswith("!")
|
|
path = line.removeprefix("!").strip()
|
|
absolute = "/" in line.removesuffix("/")
|
|
|
|
prefix = ""
|
|
if negate:
|
|
prefix += "!"
|
|
else:
|
|
# gitignore lines to recursively delete
|
|
if (
|
|
"target" in path
|
|
or "generated" in path
|
|
or "output" in path
|
|
or "cache" in path
|
|
or "build" in path
|
|
or "node_modules" in path
|
|
):
|
|
prefix += "(?d)"
|
|
# gitignore lines to exclude
|
|
if "[._]" in path:
|
|
return
|
|
|
|
yield "// " + str(parent) + ": " + line.strip()
|
|
if absolute:
|
|
yield prefix + str(parent) + "/" + path.removeprefix("/")
|
|
else:
|
|
yield prefix + str(parent) + "/" + path.removeprefix("/")
|
|
yield prefix + str(parent) + "/**/" + path.removeprefix("/")
|
|
|
|
|
|
def scan(directory: Path) -> Iterable[str]:
|
|
# Useful defaults
|
|
yield "// Always included"
|
|
yield "(?d)node_modules"
|
|
# Scan .gitignore
|
|
for path in directory.rglob(".gitignore"):
|
|
parent = path.parent
|
|
if not path.is_file():
|
|
continue
|
|
with open(path, "r") as f:
|
|
for line in f:
|
|
yield from resolve(parent, line)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser()
|
|
parser.add_argument(
|
|
"-w", "--write", action="store_const", const=True, default=False
|
|
)
|
|
parser.add_argument(
|
|
"path", type=Path, nargs="*", default=[Path(".")]
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if args.write:
|
|
ignore = Path(".stignore")
|
|
ignore_gen = Path(".stignore.gen")
|
|
with open(ignore_gen, "w") as f:
|
|
for path in args.path:
|
|
for line in scan(Path(path)):
|
|
f.write(line + "\n")
|
|
ignore_line = "#include " + str(ignore_gen)
|
|
if not check_line(ignore, ignore_line):
|
|
print("WARNING: .stignore does not exist or is missing the include line")
|
|
response = input("append an include line for the generated file? (y/n) ")
|
|
if response.lower() == "y":
|
|
write_line(ignore, ignore_line)
|
|
else:
|
|
for path in args.path:
|
|
for line in scan(Path(path)):
|
|
print(line)
|
|
|
|
# vim: set et ts=4 sw=4:
|