-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbootstrap.py
More file actions
executable file
·101 lines (78 loc) · 3.14 KB
/
bootstrap.py
File metadata and controls
executable file
·101 lines (78 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env python3
from __future__ import annotations
from dataclasses import dataclass
from functools import reduce
from logging import basicConfig, getLogger
from pathlib import Path
from subprocess import PIPE, check_output
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterable, Iterator
basicConfig(
format="{asctime} | {message}", datefmt="%Y-%m-%d %H:%M:%S", style="{", level="INFO"
)
_LOGGER = getLogger()
_REPO_ROOT = Path(__file__).parent
@dataclass(frozen=True, kw_only=True)
class _Replacement:
from_: str
to: str
def main() -> None:
dashed = "dycw-template"
underscore = dashed.replace("-", "_")
name = _get_repo_name()
replacements = [
_Replacement(from_=dashed, to=name.replace("_", "-")),
_Replacement(from_=underscore, to=name.replace("-", "_")),
]
_process_file_contents(_REPO_ROOT, replacements)
_process_file_names(_REPO_ROOT, replacements)
def _get_repo_name() -> str:
"""Get the repo name."""
output = check_output(
["git", "remote", "get-url", "origin"], stderr=PIPE, cwd=_REPO_ROOT, text=True
)
return Path(output.strip("\n")).stem
def _process_file_contents(root: Path, replacements: Iterable[_Replacement], /) -> None:
replacements = list(replacements)
_LOGGER.info(
"Processing file contents: %s (%s)", root, _desc_replacements(replacements)
)
for path in _yield_paths(root):
if path.is_file():
try:
with path.open() as fh:
old_contents = fh.read()
except UnicodeDecodeError:
_LOGGER.exception("Failed to read %s", path)
else:
new_contents = _apply_replacements(old_contents, replacements)
if old_contents != new_contents:
_LOGGER.info("Re-writing %s...", path)
with path.open(mode="w") as fh:
_ = fh.write(new_contents)
def _desc_replacements(replacements: Iterable[_Replacement], /) -> str:
return ", ".join(f"{r.from_}->{r.to}" for r in replacements)
def _yield_paths(root: Path, /) -> Iterator[Path]:
skips = {root.joinpath(".git"), root.joinpath(".venv")}
for path in root.rglob("**/*"):
if not any(path.is_relative_to(skip) for skip in skips):
yield path
def _apply_replacements(text: str, replacements: Iterable[_Replacement], /) -> str:
def inner(text: str, replacement: _Replacement, /) -> str:
return text.replace(replacement.from_, replacement.to)
return reduce(inner, replacements, text)
def _process_file_names(root: Path, replacements: Iterable[_Replacement], /) -> None:
replacements = list(replacements)
_LOGGER.info(
"Processing file names: %s (%s)", root, _desc_replacements(replacements)
)
for path in list(_yield_paths(root)):
old_stem = path.stem
new_stem = _apply_replacements(old_stem, replacements)
new_path = path.with_stem(new_stem)
if path != new_path:
_LOGGER.info("Renaming %s -> %s...", path, new_path)
_ = path.rename(new_path)
if __name__ == "__main__":
main()