import sys
import pathlib
import os
import shutil
import re
from itertools import count
from glob import iglob
from dataclasses import dataclass
from configparser import ConfigParser
from typing import Optional
@dataclass(init=False)
class ScriptInfo:
name_target: Optional[str] = None
name_original: Optional[str] = None
path_original: Optional[pathlib.Path] = None
path_target: Optional[pathlib.Path] = None
new_created: bool = False
@staticmethod
def config_path() -> pathlib.Path:
return pathlib.Path("./setup.cfg").absolute()
def load_cfg(config_path: pathlib.Path) -> ConfigParser:
config = ConfigParser()
config.read(str(config_path))
return config
def load_target_name(script_info: ScriptInfo) -> None:
try:
script_info.name_target = sys.argv[1]
except IndexError:
raise ValueError("new name must be passed with name=[name] param")
if not script_info.name_target:
raise ValueError("new name must be passed with name=[name] param")
def make_new_directory(script_info: ScriptInfo) -> None:
script_info.path_original = pathlib.Path(".").absolute()
script_info.path_target = (
script_info.path_original.parent / f"{script_info.name_target}-py"
)
if script_info.path_target.exists():
raise FileExistsError(f"directory {script_info.path_target} exists")
shutil.copytree(str(script_info.path_original), str(script_info.path_target))
script_info.new_created = True
def edit_cfg(script_info: ScriptInfo) -> str:
target_name = script_info.name_target
config = load_cfg(script_info.config_path())
old_name = config.get("metadata", "name")
config.set("metadata", "name", target_name)
config.set("coverage:run", "source", target_name)
config.set("coverage:html", "title", f"coverage report for {target_name}")
config.set("build_sphinx", "project", target_name)
with open(str(script_info.config_path()), mode="w") as f:
config.write(f)
return old_name
def rewrite_sphinx_conf(target_name: str) -> None:
template_path = pathlib.Path("./zdocs/source/conf-template").absolute()
conf_path = pathlib.Path("./zdocs/source/conf.py").absolute()
template_text = template_path.read_text()
conf_text = template_text.replace("{lib-name-goes-here}", target_name)
conf_path.write_text(conf_text)
def rename_packages(old_name: str, target_name: str) -> None:
search_pattern = "./*/__init__.py"
i = None
for init_path, i in zip(iglob(search_pattern, recursive=True), count(1)):
parent_path: pathlib.Path = pathlib.Path(init_path).parent
parent_name = parent_path.name
if parent_name.lower() == "zdevelop":
continue
if old_name.lower() in parent_name.lower():
new_name = re.sub(parent_name, old_name, target_name, flags=re.IGNORECASE)
else:
new_name = target_name
target_path = parent_path.with_name(new_name)
try:
parent_path.rename(target_path)
except FileExistsError as this_error:
sys.stderr.write(
f"package '{target_name}' already exists, your current package names"
f"may not conform to illuscio's standards. All packages names should "
f"contain the root name of the library"
)
raise this_error
if i is None:
raise FileNotFoundError("no packages found in library")
def alter_new(script_info: ScriptInfo) -> None:
old_name = edit_cfg(script_info)
assert script_info.name_target is not None
rewrite_sphinx_conf(script_info.name_target)
path_egg = f"{old_name}.egg-info"
try:
shutil.rmtree(path_egg)
except PermissionError:
os.chmod(path_egg, mode=0o007)
shutil.rmtree(path_egg)
except FileNotFoundError:
pass
rename_packages(old_name, script_info.name_target)
def main() -> None:
script_info = ScriptInfo()
try:
load_target_name(script_info)
make_new_directory(script_info)
os.chdir(str(script_info.path_target))
alter_new(script_info)
sys.stdout.write(str(script_info.path_target))
except BaseException as this_error:
if script_info.new_created:
shutil.rmtree(str(script_info.path_target))
raise this_error
else:
shutil.rmtree(str(script_info.path_original))
if __name__ == "__main__":
try:
main()
except BaseException as error:
sys.stdout.write("0")
raise error