提交 2d91eab4 编写于 作者: W wjmcat

add devops options

上级 302d8056
...@@ -37,7 +37,7 @@ MANIFEST ...@@ -37,7 +37,7 @@ MANIFEST
pip-log.txt pip-log.txt
pip-delete-this-directory.txt pip-delete-this-directory.txt
# Unit test / coverage reports # Unit tests / coverage reports
htmlcov/ htmlcov/
.tox/ .tox/
.nox/ .nox/
......
# Makefile for Code Generator
#
# GitHb: https://github.com/wj-Mcat/code-generator
#
# Author: Jingjing WU (吴京京) <https://github.com/wj-Mcat>
SOURCE_GLOB=$(wildcard bin/*.py src/**/*.py tests/**/*.py examples/*.py)
IGNORE_PEP=E203,E221,E241,E272,E501,F811
# help scripts to find the right place of wechaty module
export PYTHONPATH=src/
.PHONY: all
all : clean lint
.PHONY: clean
clean:
rm -fr dist/* ./build/ ./dist/
.PHONY: lint
lint: pylint pycodestyle flake8 mypy
# disable: TODO list temporay
.PHONY: pylint
pylint:
pylint \
--load-plugins pylint_quotes \
--disable=W0511,R0801,cyclic-import \
$(SOURCE_GLOB)
.PHONY: pycodestyle
pycodestyle:
pycodestyle \
--statistics \
--count \
--ignore="${IGNORE_PEP}" \
$(SOURCE_GLOB)
.PHONY: flake8
flake8:
flake8 \
--ignore="${IGNORE_PEP}" \
$(SOURCE_GLOB)
.PHONY: mypy
mypy:
MYPYPATH=stubs/ mypy \
$(SOURCE_GLOB)
.PHONY: install
install:
pip install -r requirements.txt
pip install -r requirements-dev.txt
.PHONY: pytest
pytest:
pytest src/ tests/
.PHONY: test-unit
test-unit: pytest
.PHONY: test
test: lint pytest
code:
code .
.PHONY: dist
dist:
python setup.py sdist bdist_wheel
.PHONY: publish
publish:
PATH=~/.local/bin:${PATH} twine upload dist/*
.PHONY: version
version:
@newVersion=$$(awk -F. '{print $$1"."$$2"."$$3+1}' < VERSION) \
&& echo $${newVersion} > VERSION \
&& echo VERSION = \'$${newVersion}\' > src/version.py \
&& git add VERSION src/version.py \
&& git commit -m "$${newVersion}" > /dev/null \
&& git tag "v$${newVersion}" \
&& echo "Bumped version to $${newVersion}"
# code-generator
![](https://img.shields.io/badge/pypi-0.0.2-brightgreen)
![](https://img.shields.io/badge/build-passing-brightgreen)
![](https://img.shields.io/badge/python-3.7+-brightgreen)
![](./docs/logo.png)
## features
- can generate all-language code, eg: `python`, `vue`, `java`, `scala`, `go` and more
- generate code with powerful template **<jinja2>**
- template can contains control command, eg: `if`, `for`, `set variable`
- can **easily** run on other template repo.
## quick start
1 . install command
```shell script
pip install code-generator
```
2 . prepare `templates`, `plugins`, `config`
you should set the prepared
3 . generate codes
## changelog
- version 0.0.2
- complete the basic interface: `templates`, `plugins`, `config`
- can run well for template code generator
- version 0.0.1
- deploy the pypi package
- complete a simple code-generator
## Author
![[wj-Mcat](https://www.github.com/wj-Mcat)](https://avatars3.githubusercontent.com/u/10242208?s=260)
[wj-Mcat](https://www.github.com/wj-Mcat)
0.0.1 0.0.2
\ No newline at end of file \ No newline at end of file
flake8
mypy
mypy_extensions
pycodestyle
pylint
pylint-quotes
pytest
pytype==2020.2.20
semver
requests
twine
...@@ -26,18 +26,20 @@ with open("./VERSION", 'r+') as f: ...@@ -26,18 +26,20 @@ with open("./VERSION", 'r+') as f:
with open('./requirements.txt', 'r+') as f: with open('./requirements.txt', 'r+') as f:
requirements = f.readlines() requirements = f.readlines()
with open('./README.md', 'r+') as f:
long_description = f.read()
setup( setup(
name='code-generator', name='code-generator',
version=VERSION, version=VERSION,
description="a simple code generator for ", description="a simple code generator for all-language",
long_description='a templated code generator for all language, especially ' long_description=long_description,
'for boring code',
keywords='code-gen,code-generator,python,code-snippet', keywords='code-gen,code-generator,python,code-snippet',
author='wj-Mcat', author='wj-Mcat',
author_email='1435130236@qq.com', author_email='1435130236@qq.com',
license='Apache 2', license='Apache 2',
packages=find_packages('src'), packages=find_packages('src'),
package_dir = { package_dir={
"": "src" "": "src"
}, },
include_package_data=True, include_package_data=True,
......
...@@ -21,16 +21,16 @@ from __future__ import annotations ...@@ -21,16 +21,16 @@ from __future__ import annotations
import logging import logging
from jinja2 import Template
def get_logger(): def get_logger():
"""get the logger""" """get the logger"""
log_formatter = logging.Formatter( log_formatter = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s') fmt='%(asctime)s - %(name)s - %(levelname)s - %(filename)s - '
'%(funcName)s - %(message)s')
logger = logging.getLogger('CodeGenerator')
logger = logging.getLogger("CodeGenerator") logger.handlers.clear()
logger.handlers = []
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
logger.propagate = False logger.propagate = False
......
...@@ -27,10 +27,11 @@ from jinja2.runtime import Macro ...@@ -27,10 +27,11 @@ from jinja2.runtime import Macro
from .config import get_logger from .config import get_logger
# pylint: disable=invalid-name
log = get_logger() log = get_logger()
# pylint: disable=too-few-public-methods
class Loader(metaclass=ABCMeta): class Loader(metaclass=ABCMeta):
"""load the plugins from local or default path""" """load the plugins from local or default path"""
def __init__(self, file_or_dir: str): def __init__(self, file_or_dir: str):
...@@ -77,6 +78,7 @@ class Loader(metaclass=ABCMeta): ...@@ -77,6 +78,7 @@ class Loader(metaclass=ABCMeta):
self.files[file_name] = code self.files[file_name] = code
# pylint: disable=too-few-public-methods
class TemplateLoader(Loader): class TemplateLoader(Loader):
"""template loader""" """template loader"""
def __init__(self, file_or_dir: str = 'templates'): def __init__(self, file_or_dir: str = 'templates'):
...@@ -89,7 +91,7 @@ class TemplateLoader(Loader): ...@@ -89,7 +91,7 @@ class TemplateLoader(Loader):
templates: Dict[str, Template] = {} templates: Dict[str, Template] = {}
for key, template in self.files.items(): for key, template in self.files.items():
if plugins is not None: if plugins is not None:
template = "{plugin}\n{template}".format( template = '{plugin}\n{template}'.format(
plugin=plugins, template=template plugin=plugins, template=template
) )
log.info(template) log.info(template)
...@@ -103,24 +105,30 @@ class PluginLoader(Loader): ...@@ -103,24 +105,30 @@ class PluginLoader(Loader):
super(PluginLoader, self).__init__(file_or_dir) super(PluginLoader, self).__init__(file_or_dir)
def _load_plugins(self) -> Dict[str, str]: def _load_plugins(self) -> Dict[str, str]:
"""load plugins to dict"""
self._load_files() self._load_files()
return self.files return self.files
def load_to_file(self) -> str: def load_to_file(self) -> str:
"""load plugins content to a single file content, so we can compile it
and add it to all template"""
files = self._load_plugins() files = self._load_plugins()
return '\n'.join(files.values()) return '\n'.join(files.values())
def load_plugin_descriptions(self) -> Dict[str, str]: def load_plugin_descriptions(self) -> Dict[str, str]:
"""we can set plugin with different description, so that we can use it
to select different plugins to different field"""
descriptions: Dict[str, str] = {} descriptions: Dict[str, str] = {}
plugins = self._load_plugins() plugins = self._load_plugins()
for name, plugin in plugins.items(): for _, plugin in plugins.items():
module = Template(plugin).module module = Template(plugin).module
attrs = dir(module) attrs = dir(module)
macros = [(attr, getattr(module, attr)) for attr in attrs macros = [(attr, getattr(module, attr)) for attr in attrs
if isinstance(getattr(module, attr), Macro)] if isinstance(getattr(module, attr), Macro)]
# first we only load the name of plugin # first we only load the name of plugin
for macro_name, macro in macros: # TODO -> we can refactor it later
for macro_name, _ in macros:
if macro_name not in descriptions: if macro_name not in descriptions:
descriptions[macro_name] = macro_name descriptions[macro_name] = macro_name
......
...@@ -23,21 +23,21 @@ import json ...@@ -23,21 +23,21 @@ import json
from argparse import ArgumentParser from argparse import ArgumentParser
import os import os
from jinja2 import Template
from .config import get_logger from .config import get_logger
from .loader import TemplateLoader, PluginLoader from .loader import TemplateLoader, PluginLoader
# pylint: disable=invalid-name
log = get_logger() log = get_logger()
args = {} # pylint: disable=invalid-name
args: dict = {}
def run_server(): def run_server():
pass """we can run a simple http server to display the code-generator"""
def _save_to_file(template_dir: str, file_name: str, content: str): def _save_to_file(template_dir: str, file_name: str, content: str):
"""save template result to the file"""
if not os.path.exists(template_dir): if not os.path.exists(template_dir):
os.mkdir(template_dir) os.mkdir(template_dir)
path = os.path.join(template_dir, file_name) path = os.path.join(template_dir, file_name)
...@@ -56,6 +56,7 @@ def _read_to_json(file: str) -> dict: ...@@ -56,6 +56,7 @@ def _read_to_json(file: str) -> dict:
def render_by_config(): def render_by_config():
"""render the template with config file mode"""
config = _read_to_json(args['config']) config = _read_to_json(args['config'])
plugins = PluginLoader(args['plugins']).load_to_file() plugins = PluginLoader(args['plugins']).load_to_file()
log.info(plugins) log.info(plugins)
...@@ -67,6 +68,7 @@ def render_by_config(): ...@@ -67,6 +68,7 @@ def render_by_config():
def main(): def main():
"""main entry of the code-generator"""
parser = ArgumentParser() parser = ArgumentParser()
subparsers = parser.add_subparsers(help='sub command') subparsers = parser.add_subparsers(help='sub command')
serve_parser = subparsers.add_parser(name='serve') serve_parser = subparsers.add_parser(name='serve')
......
"""tests code"""
import pytest
def test_loader():
"""tests template loader"""
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册