-
Notifications
You must be signed in to change notification settings - Fork 1
/
apply_configuration.py
142 lines (124 loc) · 4.72 KB
/
apply_configuration.py
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""A file for initializing the repository.
This file should be deleted after initial setup.
"""
import json
import re
import shutil
import subprocess
from pathlib import Path
def _multi_replace(substitutions: dict[str, str], text: str) -> str:
# Use re to replace everything in one pass, avoiding issues with the user's
# new values getting matched to my old values.
rep = dict((re.escape(k), v) for k, v in substitutions.items())
pattern = re.compile("|".join(rep.keys()))
return pattern.sub(lambda m: rep[re.escape(m.group(0))], text)
def _replace_all_occurences(
substitutions: dict[str, str],
exclude: set[Path] | None = None,
) -> None:
if exclude is None:
exclude = set()
# Get files in this repository (e.g., exclude venv/).
known_files: set[Path] = set()
outer_dir = Path(".").parent.resolve()
proc = subprocess.run(
["git", "ls-files"], encoding="utf-8", stdout=subprocess.PIPE, check=True
)
for line in proc.stdout.split("\n"):
known_files.add((outer_dir / line).resolve())
known_files -= exclude
for file_path in known_files:
if file_path.is_dir():
continue
with file_path.open("r", encoding="utf-8") as fp:
file_contents = fp.read()
updated_contents = _multi_replace(substitutions, file_contents)
if updated_contents != file_contents:
with file_path.open("w", encoding="utf-8") as file:
file.write(updated_contents)
def _main() -> None:
# Parse the config.
outer_dir = Path(".").parent.resolve()
config_file = outer_dir / "config.json"
assert config_file.exists(), "Missing config file"
with open(config_file, "r", encoding="utf-8") as fp:
config = json.load(fp)
# Validate the config.
assert "developer" in config, "Missing developer name in config file"
developer = config["developer"]
github_username = config["github-username"]
assert not " " in github_username, "Malformed GitHub username"
package_name = config["your-package-name"]
assert (
" " not in package_name
), "Package names cannot contain spaces (you want to `import package_name`)"
assert (
"-" not in package_name
), "Package names cannot dashes (you want to `import package_name`)"
python_version = config["python-version"]
assert python_version.startswith("3"), "Only Python 3 is supported"
assert python_version.startswith(
"3."
), "Missing dot in Python version (example: 3.10)"
python_subversion = python_version.split(".")[1]
assert python_subversion.isdigit()
# Get the repository name from this directory.
repo_name = outer_dir.name
# Delete the existing git files if they are from the starter repo.
git_repo = outer_dir / ".git"
if git_repo.exists():
git_config_file = git_repo / "config"
with open(git_config_file, "r", encoding="utf-8") as fp:
git_config_contents = fp.read()
if "[email protected]:tomsilver/python-starter.git" in git_config_contents:
shutil.rmtree(git_repo)
# Initialize the repo anew.
subprocess.run(["git", "init"], check=True, capture_output=True)
subprocess.run(["git", "checkout", "-b", "main"], check=True, capture_output=True)
subprocess.run(["git", "add", "."], check=True, capture_output=True)
# Check if the remote already exists (if this script is being run twice).
# This can happen if the user makes a mistake in their GitHub username.
ret = subprocess.run(
["git", "remote", "get-url", "origin"],
check=False,
capture_output=True,
)
# Remote already exists, so set the URL.
if ret.returncode == 0:
remote_command = "set-url"
# Remote doesn't exist, so add the URL.
else:
remote_command = "add"
subprocess.run(
[
"git",
"remote",
remote_command,
"origin",
f"[email protected]:{github_username}/{repo_name}.git",
],
check=True,
capture_output=True,
)
# Replace all occurrences of default names.
substitutions = {
"Tom Silver": developer,
"tomsilver": github_username,
"python-starter": repo_name,
"python_starter": package_name,
"3.10": f"3.{python_subversion}",
"310": f"3{python_subversion}",
}
_replace_all_occurences(
substitutions, exclude={outer_dir / "apply_configuration.py", config_file}
)
# Rename the package repo.
subprocess.run(
["mv", "src/python_starter", f"src/{package_name}"],
check=True,
capture_output=True,
)
# Report succcess.
print("Configuration applied successfully.")
if __name__ == "__main__":
_main()