import pkg_resources
from pathlib import Path
import distutils.dir_util
from typing import NamedTuple
from .os import chdir
# The folder where DFFML is installed
INSTALL_LOCATION = Path(
pkg_resources.resource_filename("dffml", "skel")
).parent
[docs]class SkelTemplateConfig(NamedTuple):
"""
Variables used to find are replace strings starting with ``REPLACE_`` in
``skel/`` sub directories.
"""
org: str
package: str
description: str
name: str
email: str
dffml_version: str
class Skel:
@property
def skel(self):
return Path(INSTALL_LOCATION, "skel")
@property
def common(self):
return self.skel / Path("common")
def common_files(self):
"""
Files that are in common skeleton
"""
return [path for path in self.common.rglob("*") if not path.is_dir()]
def plugins(self):
return [
path
for path in self.skel.glob("*")
if "common" != path.name and path.is_dir()
]
def create_symlinks(self, plugin):
with chdir(plugin):
for filepath in self.common_files():
linkpath = filepath.relative_to(self.common)
# Don't symlink if we already have
if linkpath.is_symlink():
continue
# Make links relative
filepath = filepath.relative_to(self.common.parent)
for path in linkpath.parents:
filepath = Path("..") / filepath
if self.common == path:
break
# Create parent directories of link if they do not exist
if not linkpath.parent.is_dir():
linkpath.parent.mkdir(parents=True)
# Resolving first gives more helpful error message if it fails
if not linkpath.resolve().is_file():
linkpath.resolve().symlink_to(filepath)
def copy_template(self, plugin, target):
# Recursive copy (shutil.copytree doesn't do the right thing if
# target exists)
distutils.dir_util.copy_tree(self.common, target)
distutils.dir_util.copy_tree(plugin, target)
def rename_template(self, target, config: SkelTemplateConfig):
# Rename
src = Path(target, "REPLACE_IMPORT_PACKAGE_NAME")
dest = Path(target, config.package.replace("-", "_"))
src.rename(dest)
# Rename all variables in all files
rename = {
"REPLACE_ORG_NAME": config.org,
"REPLACE_PACKAGE_NAME": config.package,
"REPLACE_IMPORT_PACKAGE_NAME": config.package.replace("-", "_"),
"REPLACE_DESCRIPTION": config.description,
"REPLACE_AUTHOR_NAME": config.name,
"REPLACE_AUTHOR_EMAIL": config.email,
"REPLACE_DFFML_VERSION": config.dffml_version,
}
for path in dest.parent.rglob("*"):
# Skip directories
if path.is_dir():
continue
# Skip egg-info and __pycache__ if present
if ".egg-info" in path.name or "__pycache__" in path.name:
continue
# Open file and find replace all variables
contents = path.read_bytes()
for find, replace in rename.items():
contents = contents.replace(find.encode(), replace.encode())
path.write_bytes(contents)
def from_template(self, plugin_name, target, config):
plugin = self.skel / Path(plugin_name)
self.copy_template(plugin, target)
self.rename_template(target, config)