Skip to content

Commit

Permalink
feat: geny 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
oleoneto committed Jan 17, 2024
1 parent d0a4694 commit 116c02d
Show file tree
Hide file tree
Showing 76 changed files with 1,911 additions and 1 deletion.
38 changes: 38 additions & 0 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: tests

on:
push:
branches:
- '*'

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [ "pypy3.9", "pypy3.10", "3.9", "3.10", "3.11", "3.12" ]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Display Python version
run: python -c "import sys; print(sys.version)"

- name: Install dependencies
run: python -m pip install --upgrade pip setuptools wheel coverage ruff

- name: Lint with Ruff
run: |
ruff --output-format=github .
continue-on-error: true

- name: Run tests
run: |
pip install -e .
python -m unittest discover -s tests/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# geny
An extendable file and project generator
An extendable file generator
16 changes: 16 additions & 0 deletions geny/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# coding: utf-8
"""
geny: an extendable file generator
"""
import os

__version__ = "0.1.0"
__license__ = "BSD 3-Clause"
__author__ = "Leo Neto"
__copyright__ = "Copyright 2024 Leo Neto"

COMMANDS_FOLDER = os.path.join(os.path.dirname(__file__), "commands")

PLUGINS_FOLDER = os.environ.get("GENY_PLUGINS", None)

VERSION = __version__
1 change: 1 addition & 0 deletions geny/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# cli
88 changes: 88 additions & 0 deletions geny/cli/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import click
import logging
from pathlib import Path
from geny import VERSION
from geny.extensions.combined import AliasedAndDiscoverableGroup
from geny.core.templates.template import TemplateParser


@click.command(
cls=AliasedAndDiscoverableGroup, context_settings=dict(ignore_unknown_options=True)
)
@click.option("--debug", is_flag=True, help="Enable debug logs.")
@click.option("--dry", is_flag=True, help="Do not modify the file system.")
@click.option("-f", "--force", is_flag=True, help="Override any conflicting files.")
@click.option("--verbose", is_flag=True, help="Enable verbosity.")
@click.option(
"--templates-dir",
"-t",
envvar="GENY_TEMPLATES_DIR",
help="Template directory.",
type=click.Path(),
)
@click.version_option(version=VERSION)
@click.pass_context
def cli(ctx, debug, dry, force, verbose, templates_dir):
"""
geny
an extendable file generator.
"""

# Note for contributors:
#
# Commands are auto-discovered if they are placed under the commands directory.
# But please be sure to do the following for this to work:
# 1. Name your package and click command the same.
# 2. Place your command definition within your package's main.py module
# 3. Any sub-commands of your command should be added to the top-most command in the package's main.py module.
#
# Access your command like so:
# `geny my-command my-command-sub-command`
#
# If you would like to skip a plugin/command from being auto-discovered,
# simply rename the package by either prepending or appending any number of underscores (_).
# Any code contained within the package will be ignored.

ctx.ensure_object(dict)

from rich.logging import RichHandler

FORMAT = "[DRY] %(message)s" if dry else "%(message)s"

logging.basicConfig(
encoding="utf-8",
level=logging.DEBUG if verbose else logging.INFO,
format=FORMAT,
handlers=[
RichHandler(
log_time_format="",
show_path=False,
show_level=False,
enable_link_path=True,
markup=True,
)
],
)

templates = [Path(__file__).resolve().parent.parent / "template_files"]

if templates_dir is not None:
templates.append(Path(templates_dir))

TemplateParser(
templates_dir=templates,
context={},
)

ctx.obj["ENABLE_DEBUG"] = debug
ctx.obj["ENABLE_DRY_RUN"] = dry
ctx.obj["ENABLE_FORCE"] = force
ctx.obj["ENABLE_VERBOSITY"] = verbose


if __name__ == "__main__":
try:
cli()
except (KeyboardInterrupt, SystemExit) as e:
click.echo(f"Exited! {repr(e)}")
1 change: 1 addition & 0 deletions geny/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# commands
5 changes: 5 additions & 0 deletions geny/commands/callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from geny.core.utils import sanitized_string


def sanitized_string_callback(ctx, param, value):
return sanitized_string(value)
Empty file.
26 changes: 26 additions & 0 deletions geny/commands/destroy/dockerfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import click

from geny.core.filesystem.files import File


@click.command()
@click.option("--docker-compose", is_flag=True)
@click.pass_context
def dockerfile(ctx, docker_compose):
"""
Destroy a Dockerfile (and docker-compose.yaml).
"""

files = [
File(name="Dockerfile"),
]

if docker_compose:
files.append(File(name="docker-compose.yaml"))

[
file.destroy(
**ctx.obj,
)
for file in files
]
24 changes: 24 additions & 0 deletions geny/commands/destroy/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# commands:destroy
import click

from geny.commands.destroy.dockerfile import dockerfile
from geny.commands.destroy.template import template


@click.group()
@click.pass_context
def destroy(ctx):
"""
Destroy files.
"""

ctx.ensure_object(dict)


[
destroy.add_command(cmd)
for cmd in [
dockerfile,
template,
]
]
28 changes: 28 additions & 0 deletions geny/commands/destroy/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import click

from geny.commands.callbacks import sanitized_string_callback
from geny.core.filesystem.files import File


SUPPORTED_CLASSES = [
"create",
"detail",
"list",
"update",
]


@click.command(context_settings=dict(ignore_unknown_options=True))
@click.argument("name", required=True, callback=sanitized_string_callback)
@click.option("--class_", type=click.Choice(SUPPORTED_CLASSES))
@click.option("--full", is_flag=True, help="Destroy templates for all CRUD operations")
@click.pass_context
def template(ctx, name, class_, full):
"""
Destroy an html template.
"""

classes = SUPPORTED_CLASSES if full else [class_]

for k in classes:
File(name=f"templates/{name}{'_' + k if k else ''}.html").destroy(**ctx.obj)
39 changes: 39 additions & 0 deletions geny/commands/generate/dockerfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import click

from geny.core.filesystem.files import File


@click.command()
@click.option("--docker-compose", is_flag=True)
@click.pass_context
def dockerfile(ctx, docker_compose):
"""
Generate a Dockerfile.
"""

files = [
File(name="Dockerfile", template="docker/dockerfile.tpl", context={}),
]

if docker_compose:
files.append(
File(
name="docker-compose.yaml",
template="docker/docker-compose.tpl",
context={
"services": [
"celery",
"kafka",
"postgres",
"rabbitmq" "redis",
],
},
)
)

[
file.create(
**ctx.obj,
)
for file in files
]
24 changes: 24 additions & 0 deletions geny/commands/generate/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# commands:generate
import click

from geny.commands.generate.dockerfile import dockerfile
from geny.commands.generate.template import template


@click.group()
@click.pass_context
def generate(ctx):
"""
Create files.
"""

ctx.ensure_object(dict)


[
generate.add_command(cmd)
for cmd in [
dockerfile,
template,
]
]
37 changes: 37 additions & 0 deletions geny/commands/generate/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import click
import inflection

from geny.commands.callbacks import sanitized_string_callback
from geny.core.filesystem.files import File


SUPPORTED_CLASSES = [
"create",
"detail",
"list",
"update",
]


@click.command(context_settings=dict(ignore_unknown_options=True))
@click.argument("name", required=True, callback=sanitized_string_callback)
@click.option("--class_", type=click.Choice(SUPPORTED_CLASSES))
@click.option("--full", is_flag=True, help="Create templates for all CRUD operations")
@click.pass_context
def template(ctx, name, class_, full):
"""
Generate an html template.
"""

classes = SUPPORTED_CLASSES if full else [class_]

for k in classes:
file = File(
name=f"templates/{name}{'_' + k if k else ''}.html",
template=f"templates/{k if k else 'template'}.tpl",
context={
"classname": inflection.camelize(name),
},
)

file.create(**ctx.obj)
1 change: 1 addition & 0 deletions geny/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# core
1 change: 1 addition & 0 deletions geny/core/decorators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# core:decorators
13 changes: 13 additions & 0 deletions geny/core/decorators/error_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# core:decorators
import click


def halt_on_error(f):
def wrapper(*args, **kwargs):
try:
f(*args, **kwargs)
except Exception as err:
click.echo(repr(err), err=True)
raise click.Abort()

return wrapper
18 changes: 18 additions & 0 deletions geny/core/decorators/singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# core:decorators:singleton
import functools


def singleton(cls):
"""
Make a class a Singleton class (only one instance)
Source: https://realpython.com/primer-on-python-decorators/#stateful-decorators
"""

@functools.wraps(cls)
def wrapper_singleton(*args, **kwargs):
if not wrapper_singleton.instance:
wrapper_singleton.instance = cls(*args, **kwargs)
return wrapper_singleton.instance

wrapper_singleton.instance = None
return wrapper_singleton
1 change: 1 addition & 0 deletions geny/core/filesystem/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# core:filesystem
Loading

0 comments on commit 116c02d

Please sign in to comment.