from __future__ import (
annotations,
)
import tarfile
import urllib.request
from pathlib import (
Path,
)
from tempfile import (
TemporaryDirectory,
)
from typing import (
Any,
Final,
Optional,
)
from ..consoles import (
console,
)
TEMPLATE_URL: Final[str] = "https://github.com/minos-framework/minos-templates/releases/download"
TEMPLATE_VERSION: Final[str] = "v0.3.0"
[docs]class TemplateFetcher:
"""Template Fetcher class."""
[docs] def __init__(self, uri: str, metadata: Optional[dict[str, Any]] = None):
if metadata is None:
metadata = dict()
self.uri = uri
self.metadata = metadata
self._tmp = None
[docs] @classmethod
def from_url(cls, url: str) -> TemplateFetcher:
"""Build a new instance from url.
:param url: The url of the template.
:return: A ``TemplateFetcher`` instance.
"""
registry, name = url.rsplit("/", 1)
stem = name.split(".", 1)[0]
metadata = {"template_registry": registry, "template_name": stem}
return cls(url, metadata)
[docs] @classmethod
def from_path(cls, path: Path) -> TemplateFetcher:
"""Build a new instance from path.
:param path: The path of the template.
:return: A ``TemplateFetcher`` instance.
"""
metadata = {"template_registry": path.parent.as_uri(), "template_name": path.name.split(".", 1)[0]}
return cls(path.as_uri(), metadata)
[docs] @classmethod
def from_name(cls, name: str, version: str = TEMPLATE_VERSION) -> TemplateFetcher:
"""Build a new instance from name and version.
:param name: The name of the template.
:param version: The version of the template.
:return: A ``TemplateFetcher`` instance.
"""
registry = f"{TEMPLATE_URL}/{version}"
url = f"{registry}/{name}.tar.gz"
metadata = {"template_registry": registry, "template_version": version, "template_name": name}
return cls(url, metadata)
@property
def path(self) -> Path:
"""Get the local path of the template.
:return: A ``Path`` instance.
"""
return Path(self.tmp.name)
@property
def tmp(self) -> TemporaryDirectory:
"""Get the temporal directory in which the template is downloaded.
:return: A ``TemporaryDirectory`` instance.
"""
if self._tmp is None:
cache_dir = Path.home() / ".minos" / "tmp"
cache_dir.mkdir(parents=True, exist_ok=True)
tmp = TemporaryDirectory(dir=str(cache_dir))
self.fetch_tar(self.uri, tmp.name)
self._tmp = tmp
return self._tmp
def __repr__(self) -> str:
return f"{type(self).__name__}({self.uri!r}, {self.metadata!r})"
def __eq__(self, other: Any) -> bool:
return isinstance(other, type(self)) and self.uri == other.uri and self.metadata == other.metadata
[docs] @staticmethod
def fetch_tar(url: str, path: str) -> None:
"""Fetch a tar file from the given url and uncompress it onn the given path.
:param url: The url of the tar file.
:param path: The location of the uncompressed file.
:return: This method does not return anything.
"""
with console.status(f"Downloading template from {url!r}...", spinner="moon"):
stream = urllib.request.urlopen(url)
console.print(f":moon: Downloaded template from {url!r}!\n")
tar = tarfile.open(fileobj=stream, mode="r|gz")
with console.status(f"Extracting template into {path!r}...", spinner="moon"):
tar.extractall(path=path)
console.print(f":moon: Extracted template into {path!r}!\n")