Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new --templates-path option #78

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/ansible_creator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ def parse_args(self: Cli) -> argparse.Namespace:
"current working directory.",
)

init_command_parser.add_argument(
"--templates-path",
help="Path to a directory containing custom template for collection skeleton."
" When provided, this will be used to scaffold the collection instead of the"
" in-built template.",
)

init_command_parser.add_argument(
"--force",
default=False,
Expand Down
18 changes: 18 additions & 0 deletions src/ansible_creator/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Compat library for ansible-creator.

This contains compatibility definitions for older python
When we need to import a module differently depending on python versions, we do it
here.
"""

# ruff: noqa: F401
ssbarnea marked this conversation as resolved.
Show resolved Hide resolved

# pylint: disable=unused-import

import sys


if sys.version_info >= (3, 11):
from importlib.resources.abc import Traversable
else:
from importlib.abc import Traversable
4 changes: 4 additions & 0 deletions src/ansible_creator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Config:
no_ansi: bool
subcommand: str
verbose: int
templates_path: str

collection: str = ""
force: bool = False
Expand All @@ -36,4 +37,7 @@ def __post_init__(self: Config) -> None:
object.__setattr__(self, "namespace", fqcn[0])
object.__setattr__(self, "collection_name", fqcn[-1])

if self.templates_path:
object.__setattr__(self, "template", expand_path(self.init_path))

object.__setattr__(self, "init_path", expand_path(self.init_path))
35 changes: 35 additions & 0 deletions src/ansible_creator/subcommands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import os
import re
import shutil

from typing import TYPE_CHECKING
Expand Down Expand Up @@ -36,6 +37,7 @@ def __init__(
self._force = config.force
self._creator_version = config.creator_version
self._templar = Templar()
self._templates_path = config.templates_path
self.output: Output = output

def run(self: Init) -> None:
Expand All @@ -47,6 +49,38 @@ def run(self: Init) -> None:

self.output.debug(msg=f"final collection path set to {col_path}")

# validate custom templates
if self._templates_path:
full_templates_path = os.path.join(self._templates_path, "new_collection")

# verify that templates path exists and has "new_collection" dir
if not os.path.exists(full_templates_path):
msg = f"could not find templates for new collection at {self._templates_path}."
raise CreatorError(msg)

# ensure that "new_collection" dir is not empty
if len(os.listdir(full_templates_path)) == 0:
msg = (
"please ensure that a directory named `new_collection` exists"
f" at {self._templates_path} and is not empty."
)
raise CreatorError(msg)

# ensure that a template for galaxy file exists in "new_collection" dir
if (
len(
list(
filter(
re.compile("(?:galaxy.)(?:yml|yaml)(?:.j2)?").match,
os.listdir(full_templates_path),
),
),
)
== 0
):
msg = f"template for Ansible galaxy file not found in {full_templates_path!s}."
raise CreatorError(msg)

# check if init_path already exists
if os.path.exists(col_path):
if os.path.isfile(col_path):
Expand Down Expand Up @@ -86,6 +120,7 @@ def run(self: Init) -> None:
source="new_collection",
dest=col_path,
templar=self._templar,
templates_path=self._templates_path,
template_data={
"namespace": self._namespace,
"collection_name": self._collection_name,
Expand Down
22 changes: 17 additions & 5 deletions src/ansible_creator/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

from dataclasses import dataclass
from importlib import resources
from pathlib import Path
from typing import TYPE_CHECKING

from ansible_creator.exceptions import CreatorError


if TYPE_CHECKING:
from importlib import abc

from ansible_creator.compat import Traversable
from ansible_creator.output import Output
from ansible_creator.templar import Templar

Expand Down Expand Up @@ -84,6 +84,7 @@ def copy_container( # noqa: PLR0913
output: Output,
templar: Templar,
template_data: dict[str, str],
templates_path: str,
allow_overwrite: list[str] | None = None,
) -> None:
"""Copy files and directories from a possibly nested source to a destination.
Expand All @@ -92,17 +93,21 @@ def copy_container( # noqa: PLR0913
:param dest: Absolute destination path.
:param templar: An object of template class.
:param template_data: A dictionary containing data to render templates with.
:param templates_path: A string representing path to custom templates
:param allow_overwrite: A list of paths that should be overwritten at destination.

:raises CreatorError: if allow_overwrite is not a list.
"""
output.debug(msg=f"starting recursive copy with source container '{source}'")
output.debug(msg=f"allow_overwrite set to {allow_overwrite}")

def _recursive_copy(root: abc.Traversable) -> None:
if templates_path:
output.debug(msg=f"custom templates path set to {templates_path}")

def _recursive_copy(root: Path | Traversable) -> None:
"""Recursively traverses a resource container and copies content to destination.

:param root: A traversable object representing root of the container to copy.
:param root: A traversable or Path object representing root of the container to copy.
"""
output.debug(msg=f"current root set to {root}")

Expand Down Expand Up @@ -142,4 +147,11 @@ def _recursive_copy(root: abc.Traversable) -> None:
with open(dest_file, "w", encoding="utf-8") as df_handle:
df_handle.write(content)

_recursive_copy(root=resources.files(f"ansible_creator.resources.{source}"))
if templates_path:
# use custom templates path
tp_root = Path(templates_path) / source
_recursive_copy(tp_root)
else:
# use built-in templates
ib_root = resources.files(f"ansible_creator.resources.{source}")
_recursive_copy(ib_root)
3 changes: 3 additions & 0 deletions tests/units/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def test_expand_path() -> None:
"collection": "testorg.testcol",
"init_path": "./",
"force": False,
"templates_path": None,
},
],
[
Expand Down Expand Up @@ -60,6 +61,7 @@ def test_expand_path() -> None:
"collection": "testorg.testcol",
"init_path": "/home/ansible",
"force": True,
"templates_path": None,
},
],
],
Expand All @@ -83,6 +85,7 @@ def test_configuration_class() -> None:
"verbose": 2,
"collection": "testorg.testcol",
"init_path": "$HOME",
"templates_path": None,
}
app_config = Config(**cli_args)
assert app_config.namespace == "testorg"
Expand Down
1 change: 1 addition & 0 deletions tests/units/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def cli_args(tmp_path) -> dict:
"verbose": 0,
"collection": "testorg.testcol",
"init_path": tmp_path,
"templates_path": None,
}


Expand Down