Add params and conditions for template

This commit is contained in:
Dmitriy Pleshevskiy 2018-06-11 07:37:28 +03:00
parent 77ba4c758d
commit 01bf72155c
5 changed files with 121 additions and 15 deletions

View file

@ -1,10 +1,11 @@
from .config import Config from .param import Param
from .ictmpl import Ictmpl
__all__ = ('Param', )
ictmpl = Ictmpl(Config())
if __name__ == '__main__': if __name__ == '__main__':
from .config import Config
from .ictmpl import Ictmpl
ictmpl = Ictmpl(Config())
ictmpl.run() ictmpl.run()

View file

@ -3,8 +3,8 @@
__title__ = 'ictmpl' __title__ = 'ictmpl'
__description__ = 'Generate projects from templates' __description__ = 'Generate projects from templates'
__url__ = 'https://github.com/ideascup/ictmpl/' __url__ = 'https://github.com/ideascup/ictmpl/'
__version__ = '1.0.0' __version__ = '1.1.0'
__build__ = 0x010000 __build__ = 0x010100
__author__ = 'Dmitriy Pleshevskiy' __author__ = 'Dmitriy Pleshevskiy'
__author_email__ = 'dmitriy@ideascup.me' __author_email__ = 'dmitriy@ideascup.me'
__license__ = 'MIT' __license__ = 'MIT'

View file

@ -1,5 +1,6 @@
import os import os
from re import compile, sub import json
from re import compile, sub, _pattern_type
from os.path import abspath, isdir, join from os.path import abspath, isdir, join
from shutil import copytree, rmtree from shutil import copytree, rmtree
@ -9,6 +10,8 @@ __all__ = ('parse_ignore_file', 'copytree_with_ignore', 'treewalk')
RE_DOUBLESTAR = compile(r'\*\*') RE_DOUBLESTAR = compile(r'\*\*')
RE_STAR = compile(r'\*') RE_STAR = compile(r'\*')
RE_IF_CONDITION = compile(r'\s*%\s*(endif|if\s+(.+))\s*%')
def parse_ignore_file(filepath): def parse_ignore_file(filepath):
regexes = [] regexes = []
@ -94,8 +97,45 @@ def replace_template_file(filepath, app):
params = app.params params = app.params
with open(filepath, 'r') as file: with open(filepath, 'r') as file:
filedata = file.read() filedata = file.read()
for key, value in params.items():
filedata = sub(r'%%{}%%'.format(key), value, filedata) # replace conditions
cut_info = None
cond_deep = 0
start_index = 0
while True:
match = RE_IF_CONDITION.search(filedata[start_index:])
if not match:
break
start, end = [start_index+v for v in match.span()]
statement = match.group(1)
if statement.startswith('if '):
cond_deep += 1
local = params.copy()
exec('result__=bool({})'.format(match.group(2)), local)
if local['result__']:
filedata = filedata[:start] + filedata[end:]
start_index = start
elif cut_info is None:
cut_info = (start, cond_deep)
start_index = end
else:
if cut_info is not None \
and cut_info[1] is cond_deep:
start = cut_info[0]
cut_info = None
filedata = filedata[:start] + filedata[end:]
start_index = start
# replace params
for key, value in params.items():
if isinstance(value, _pattern_type):
continue
elif value is None or isinstance(value, bool):
value = str(value)
else:
value = json.dumps(value)
filedata = sub(r'%%{}%%'.format(key), value, filedata)
with open(filepath, 'w') as file: with open(filepath, 'w') as file:
file.write(filedata) file.write(filedata)

View file

@ -7,6 +7,7 @@ from uuid import uuid4
from textwrap import dedent from textwrap import dedent
from shutil import rmtree from shutil import rmtree
from ictmpl import Param
from ictmpl.helpers.git import Git from ictmpl.helpers.git import Git
from ictmpl.helpers.fsutil import ( from ictmpl.helpers.fsutil import (
copytree_with_ignore, rmtree_without_ignore, replace_template_file) copytree_with_ignore, rmtree_without_ignore, replace_template_file)
@ -21,6 +22,28 @@ RE_GITLINK = compile(r'^(?:git@|https?://)')
RE_COMMAND_ENV = compile(r'#!(.+)') RE_COMMAND_ENV = compile(r'#!(.+)')
def ask_params(app, params=None, deep=0):
if not params:
return
for param in params:
if not isinstance(param, Param):
if isinstance(param, (list, tuple)):
app.params[param[0]] = param[1]
continue
while True:
value = input(' '*deep*4 + param.question) or param.default
try:
param_value = param.strparse(value)
app.params[param.name] = param_value
if param.children and param_value:
ask_params(app, param.children, deep=deep+1)
break
except Exception as e:
print(e)
def create_project(args, app): def create_project(args, app):
project_path = abspath(args.path) project_path = abspath(args.path)
@ -47,7 +70,8 @@ def create_project(args, app):
try: try:
with open('.ictmplrc', 'r') as file: with open('.ictmplrc', 'r') as file:
exec(file.read(), rc) exec(file.read(), rc)
except: except Exception as e:
print(e)
return return
dependencies = rc.get('sysDependencies', None) dependencies = rc.get('sysDependencies', None)
@ -68,12 +92,11 @@ def create_project(args, app):
'author_website', 'licence'): 'author_website', 'licence'):
app.params['__{}__'.format(key.upper())] = rc.get(key, '') app.params['__{}__'.format(key.upper())] = rc.get(key, '')
params = rc.get('params', {}) params = rc.get('params', [])
if params: if params:
print('Configure template:') print('Configure template:')
for param, default in params.items(): ask_params(app, params)
question = 'SET {}: ({}) '.format(param, default) print(app.params)
app.params[param] = input(question) or default
print('------------------\n') print('------------------\n')
print('Walking files and replace params') print('Walking files and replace params')
@ -81,6 +104,7 @@ def create_project(args, app):
if templates: if templates:
templates = map(lambda p: join(project_path, p), templates) templates = map(lambda p: join(project_path, p), templates)
for filepath in templates: for filepath in templates:
print(filepath)
replace_template_file(filepath, app) replace_template_file(filepath, app)
else: else:
for root, dirs, files in os.walk(project_path): for root, dirs, files in os.walk(project_path):
@ -108,6 +132,6 @@ def create_project(args, app):
proc.communicate() proc.communicate()
except KeyboardInterrupt: except KeyboardInterrupt:
proc.kill() proc.kill()
rmtree(project_path) # rmtree(project_path)
finally: finally:
os.remove(tmpfilename) os.remove(tmpfilename)

41
ictmpl/param.py Normal file
View file

@ -0,0 +1,41 @@
class Param:
def __init__(self, name, default, vtype=None, question=None, children=None):
self.name = name
self.default = default
self.vtype = vtype or type(default)
if not question:
question = 'SET {0}: ({1})'
try:
question = question.format(name, self.format(default))
except:
pass
self.question = question + ' '
self.children = children
def strparse(self, value):
if self.vtype is not str and type(value) is self.vtype:
return value
if self.vtype in (list, tuple) \
or (self.vtype is str and ',' in value):
return [v.strip() for v in value.split(',') if v.strip()]
elif self.vtype is bool:
return value[:1].lower() == 'y'
return self.vtype(value)
def format(self, value):
type_ = type(value)
if type_ in (list, tuple):
value = ', '.join(value)
elif type_ is bool:
nvindex = int(not value)
value = '/'.join(
v.upper() if nvindex is i else v
for i, v in enumerate('yn'))
return value