Add params and conditions for template
This commit is contained in:
parent
77ba4c758d
commit
01bf72155c
5 changed files with 121 additions and 15 deletions
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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,7 +97,44 @@ 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()
|
||||||
|
|
||||||
|
# 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():
|
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)
|
filedata = sub(r'%%{}%%'.format(key), value, filedata)
|
||||||
|
|
||||||
with open(filepath, 'w') as file:
|
with open(filepath, 'w') as 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
41
ictmpl/param.py
Normal 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
|
Reference in a new issue