Update dependencies and update conditions
Add elif/else if/else for template Add SysDep class for template settings Update Param class. Now, supports callable vtype
This commit is contained in:
parent
642ba66405
commit
95a6bec274
7 changed files with 122 additions and 37 deletions
|
@ -1,6 +1,7 @@
|
|||
from .param import Param
|
||||
from .dependency import SysDep
|
||||
|
||||
__all__ = ('Param', )
|
||||
__all__ = ('Param', 'SysDep')
|
||||
|
||||
if __name__ == '__main__':
|
||||
from .config import Config
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
__title__ = 'ictmpl'
|
||||
__description__ = 'Generate projects from templates'
|
||||
__url__ = 'https://github.com/ideascup/ictmpl/'
|
||||
__version__ = '1.1.2'
|
||||
__build__ = 0x010102
|
||||
__version__ = '1.2.0'
|
||||
__build__ = 0x010200
|
||||
__author__ = 'Dmitriy Pleshevskiy'
|
||||
__author_email__ = 'dmitriy@ideascup.me'
|
||||
__license__ = 'MIT'
|
||||
|
|
25
ictmpl/dependency.py
Normal file
25
ictmpl/dependency.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from subprocess import Popen, PIPE
|
||||
|
||||
|
||||
class SysDep:
|
||||
def __init__(self, packages, checkcmd=None, checkparams=None):
|
||||
self.packages = packages
|
||||
self.checkcmd = checkcmd
|
||||
self.checkparams = checkparams
|
||||
|
||||
def check(self, app):
|
||||
if self.checkcmd:
|
||||
proc = Popen('command -v {}'.format(self.checkcmd), shell=True, stdout=PIPE)
|
||||
stdout = proc.communicate()[0]
|
||||
if not stdout:
|
||||
return True
|
||||
elif self.checkparams:
|
||||
if callable(self.checkparams):
|
||||
return bool(self.checkparams(app.params))
|
||||
elif isinstance(self.checkparams, str):
|
||||
return bool(app.params.get(self.checkparams))
|
||||
else:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
@ -1,16 +1,22 @@
|
|||
import re
|
||||
import os
|
||||
import json
|
||||
from re import compile, sub, _pattern_type
|
||||
from os.path import abspath, isdir, join
|
||||
from shutil import copytree, rmtree
|
||||
|
||||
__all__ = ('parse_ignore_file', 'copytree_with_ignore', 'treewalk')
|
||||
|
||||
|
||||
RE_DOUBLESTAR = compile(r'\*\*')
|
||||
RE_STAR = compile(r'\*')
|
||||
RE_DOUBLESTAR = re.compile(r'\*\*')
|
||||
RE_STAR = re.compile(r'\*')
|
||||
|
||||
RE_IF_CONDITION = compile(r'\s*%\s*(endif|if\s+(.+))\s*%')
|
||||
RE_IF_CONDITION = re.compile(r"""
|
||||
(?:
|
||||
^\s*%\s*(else|(?:el(?:se )?)?if\s+(.+))\s*%
|
||||
|
|
||||
\s*%\s*(endif)\s*%
|
||||
)
|
||||
""", re.VERBOSE|re.MULTILINE)
|
||||
|
||||
|
||||
def parse_ignore_file(filepath):
|
||||
|
@ -30,7 +36,7 @@ def parse_ignore_file(filepath):
|
|||
if line.startswith('/'):
|
||||
line = '^'+line
|
||||
|
||||
regexes.append(compile(line))
|
||||
regexes.append(re.compile(line))
|
||||
return regexes
|
||||
|
||||
|
||||
|
@ -108,34 +114,62 @@ def replace_template_file(filepath, app):
|
|||
break
|
||||
|
||||
start, end = [start_index+v for v in match.span()]
|
||||
statement = match.group(1)
|
||||
statement = match.group(1) or match.group(3)
|
||||
if statement.startswith('if '):
|
||||
cond_deep += 1
|
||||
if cut_info is not None:
|
||||
continue
|
||||
|
||||
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:
|
||||
else:
|
||||
cut_info = (start, cond_deep)
|
||||
start_index = end
|
||||
else:
|
||||
elif statement.startswith('elif ') \
|
||||
or statement.startswith('else if '):
|
||||
if cut_info is not None:
|
||||
start = cut_info[0]
|
||||
cut_info = None
|
||||
|
||||
local = params.copy()
|
||||
exec('result__=bool({})'.format(match.group(2)), local)
|
||||
if local['result__']:
|
||||
filedata = filedata[:start] + filedata[end:]
|
||||
start_index = start
|
||||
continue
|
||||
|
||||
cut_info = (start, cond_deep)
|
||||
start_index = end
|
||||
elif statement.startswith('else') \
|
||||
and not match.group(2):
|
||||
if cut_info is not None:
|
||||
start = cut_info[0]
|
||||
cut_info = None
|
||||
|
||||
filedata = filedata[:start] + filedata[end:]
|
||||
start_index = start
|
||||
|
||||
elif statement.startswith('endif'):
|
||||
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
|
||||
cond_deep -= 1
|
||||
|
||||
# replace params
|
||||
for key, value in params.items():
|
||||
if isinstance(value, _pattern_type):
|
||||
if isinstance(value, re._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 = re.sub(r'%%{}%%'.format(key), value, filedata)
|
||||
|
||||
with open(filepath, 'w') as file:
|
||||
file.write(filedata)
|
||||
|
|
|
@ -7,7 +7,7 @@ from uuid import uuid4
|
|||
from textwrap import dedent
|
||||
from shutil import rmtree
|
||||
|
||||
from ictmpl import Param
|
||||
from ictmpl import Param, SysDep
|
||||
from ictmpl.helpers.git import Git
|
||||
from ictmpl.helpers.fsutil import (
|
||||
copytree_with_ignore, rmtree_without_ignore, replace_template_file)
|
||||
|
@ -74,29 +74,19 @@ def create_project(args, app):
|
|||
print(e)
|
||||
return
|
||||
|
||||
dependencies = rc.get('sysDependencies', None)
|
||||
if dependencies and isinstance(dependencies, dict):
|
||||
commands = []
|
||||
for key, packages in dependencies.items():
|
||||
pipes = Popen('command -v %s' % key, shell=True, stdout=PIPE)
|
||||
stdout, _ = pipes.communicate()
|
||||
if not stdout:
|
||||
commands.append(packages)
|
||||
|
||||
if commands:
|
||||
# TODO: Need check platform
|
||||
command = 'sudo apt-get install %s' % ' '.join(commands)
|
||||
Popen(command, shell=True)
|
||||
|
||||
for key in ('name', 'version', 'description', 'author', 'author_email',
|
||||
'author_website', 'licence'):
|
||||
app.params['__{}__'.format(key.upper())] = rc.get(key, '')
|
||||
|
||||
params = rc.get('params', [])
|
||||
if params:
|
||||
if params and isinstance(params, (list, tuple)):
|
||||
print('Configure template:')
|
||||
ask_params(app, params)
|
||||
print(app.params)
|
||||
try:
|
||||
ask_params(app, params)
|
||||
except KeyboardInterrupt:
|
||||
rmtree(project_path)
|
||||
exit()
|
||||
print('------------------\n')
|
||||
|
||||
print('Walking files and replace params')
|
||||
|
@ -111,6 +101,29 @@ def create_project(args, app):
|
|||
for filename in files:
|
||||
replace_template_file(join(root, filename), app)
|
||||
|
||||
try:
|
||||
dependencies = rc.get('sys_dependencies', [])
|
||||
if dependencies and isinstance(dependencies, (list, tuple)):
|
||||
packages = ' '.join(
|
||||
sysdep.packages
|
||||
for sysdep in dependencies
|
||||
if isinstance(sysdep, SysDep) and sysdep.check(app)
|
||||
)
|
||||
|
||||
if packages:
|
||||
# TODO: Need check platform
|
||||
try:
|
||||
proc = Popen('sudo apt-get install {}'.format(packages),
|
||||
shell=True)
|
||||
proc.communicate()
|
||||
except KeyboardInterrupt:
|
||||
proc.kill()
|
||||
print(os.linesep)
|
||||
exit()
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
setup_command = rc.get('commands', {}).get('setup', None)
|
||||
if setup_command:
|
||||
if isinstance(setup_command, (list, tuple)):
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
class auto(str): pass
|
||||
|
||||
|
||||
class Param:
|
||||
def __init__(self, name, default, vtype=None, question=None, children=None):
|
||||
|
@ -13,20 +15,30 @@ class Param:
|
|||
except:
|
||||
pass
|
||||
|
||||
self.question = question + ' '
|
||||
self.question = question.rstrip() + ' '
|
||||
self.children = children
|
||||
|
||||
def strparse(self, value):
|
||||
if self.vtype is not str and type(value) is self.vtype:
|
||||
if not isinstance(self.vtype, type) and callable(self.vtype):
|
||||
vtype = self.vtype(value)
|
||||
else:
|
||||
vtype = self.vtype
|
||||
|
||||
if value is 'None':
|
||||
return None
|
||||
|
||||
if type(value) is vtype:
|
||||
return value
|
||||
|
||||
if self.vtype in (list, tuple) \
|
||||
or (self.vtype is str and ',' in value):
|
||||
lvalue = value.lower()
|
||||
if vtype in (list, tuple) \
|
||||
or (vtype is auto and ',' in value):
|
||||
return [v.strip() for v in value.split(',') if v.strip()]
|
||||
elif self.vtype is bool:
|
||||
return value[:1].lower() == 'y'
|
||||
elif vtype is bool \
|
||||
or (vtype is auto and lvalue in ('true', 'false')):
|
||||
return lvalue == 'y' or lvalue == 'true'
|
||||
|
||||
return self.vtype(value)
|
||||
return vtype(value)
|
||||
|
||||
def format(self, value):
|
||||
type_ = type(value)
|
||||
|
|
Reference in a new issue