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 .param import Param
|
||||||
|
from .dependency import SysDep
|
||||||
|
|
||||||
__all__ = ('Param', )
|
__all__ = ('Param', 'SysDep')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from .config import Config
|
from .config import Config
|
||||||
|
|
|
@ -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.1.2'
|
__version__ = '1.2.0'
|
||||||
__build__ = 0x010102
|
__build__ = 0x010200
|
||||||
__author__ = 'Dmitriy Pleshevskiy'
|
__author__ = 'Dmitriy Pleshevskiy'
|
||||||
__author_email__ = 'dmitriy@ideascup.me'
|
__author_email__ = 'dmitriy@ideascup.me'
|
||||||
__license__ = 'MIT'
|
__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 os
|
||||||
import json
|
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
|
||||||
|
|
||||||
__all__ = ('parse_ignore_file', 'copytree_with_ignore', 'treewalk')
|
__all__ = ('parse_ignore_file', 'copytree_with_ignore', 'treewalk')
|
||||||
|
|
||||||
|
|
||||||
RE_DOUBLESTAR = compile(r'\*\*')
|
RE_DOUBLESTAR = re.compile(r'\*\*')
|
||||||
RE_STAR = 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):
|
def parse_ignore_file(filepath):
|
||||||
|
@ -30,7 +36,7 @@ def parse_ignore_file(filepath):
|
||||||
if line.startswith('/'):
|
if line.startswith('/'):
|
||||||
line = '^'+line
|
line = '^'+line
|
||||||
|
|
||||||
regexes.append(compile(line))
|
regexes.append(re.compile(line))
|
||||||
return regexes
|
return regexes
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,34 +114,62 @@ def replace_template_file(filepath, app):
|
||||||
break
|
break
|
||||||
|
|
||||||
start, end = [start_index+v for v in match.span()]
|
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 '):
|
if statement.startswith('if '):
|
||||||
cond_deep += 1
|
cond_deep += 1
|
||||||
|
if cut_info is not None:
|
||||||
|
continue
|
||||||
|
|
||||||
local = params.copy()
|
local = params.copy()
|
||||||
exec('result__=bool({})'.format(match.group(2)), local)
|
exec('result__=bool({})'.format(match.group(2)), local)
|
||||||
if local['result__']:
|
if local['result__']:
|
||||||
filedata = filedata[:start] + filedata[end:]
|
filedata = filedata[:start] + filedata[end:]
|
||||||
start_index = start
|
start_index = start
|
||||||
elif cut_info is None:
|
else:
|
||||||
cut_info = (start, cond_deep)
|
cut_info = (start, cond_deep)
|
||||||
start_index = end
|
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 \
|
if cut_info is not None \
|
||||||
and cut_info[1] is cond_deep:
|
and cut_info[1] is cond_deep:
|
||||||
start = cut_info[0]
|
start = cut_info[0]
|
||||||
cut_info = None
|
cut_info = None
|
||||||
filedata = filedata[:start] + filedata[end:]
|
filedata = filedata[:start] + filedata[end:]
|
||||||
start_index = start
|
start_index = start
|
||||||
|
cond_deep -= 1
|
||||||
|
|
||||||
# replace params
|
# replace params
|
||||||
for key, value in params.items():
|
for key, value in params.items():
|
||||||
if isinstance(value, _pattern_type):
|
if isinstance(value, re._pattern_type):
|
||||||
continue
|
continue
|
||||||
elif value is None or isinstance(value, bool):
|
elif value is None or isinstance(value, bool):
|
||||||
value = str(value)
|
value = str(value)
|
||||||
else:
|
else:
|
||||||
value = json.dumps(value)
|
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:
|
with open(filepath, 'w') as file:
|
||||||
file.write(filedata)
|
file.write(filedata)
|
||||||
|
|
|
@ -7,7 +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 import Param, SysDep
|
||||||
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)
|
||||||
|
@ -74,29 +74,19 @@ def create_project(args, app):
|
||||||
print(e)
|
print(e)
|
||||||
return
|
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',
|
for key in ('name', 'version', 'description', 'author', 'author_email',
|
||||||
'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 and isinstance(params, (list, tuple)):
|
||||||
print('Configure template:')
|
print('Configure template:')
|
||||||
ask_params(app, params)
|
try:
|
||||||
print(app.params)
|
ask_params(app, params)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
rmtree(project_path)
|
||||||
|
exit()
|
||||||
print('------------------\n')
|
print('------------------\n')
|
||||||
|
|
||||||
print('Walking files and replace params')
|
print('Walking files and replace params')
|
||||||
|
@ -111,6 +101,29 @@ def create_project(args, app):
|
||||||
for filename in files:
|
for filename in files:
|
||||||
replace_template_file(join(root, filename), app)
|
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)
|
setup_command = rc.get('commands', {}).get('setup', None)
|
||||||
if setup_command:
|
if setup_command:
|
||||||
if isinstance(setup_command, (list, tuple)):
|
if isinstance(setup_command, (list, tuple)):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
class auto(str): pass
|
||||||
|
|
||||||
|
|
||||||
class Param:
|
class Param:
|
||||||
def __init__(self, name, default, vtype=None, question=None, children=None):
|
def __init__(self, name, default, vtype=None, question=None, children=None):
|
||||||
|
@ -13,20 +15,30 @@ class Param:
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.question = question + ' '
|
self.question = question.rstrip() + ' '
|
||||||
self.children = children
|
self.children = children
|
||||||
|
|
||||||
def strparse(self, value):
|
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
|
return value
|
||||||
|
|
||||||
if self.vtype in (list, tuple) \
|
lvalue = value.lower()
|
||||||
or (self.vtype is str and ',' in value):
|
if vtype in (list, tuple) \
|
||||||
|
or (vtype is auto and ',' in value):
|
||||||
return [v.strip() for v in value.split(',') if v.strip()]
|
return [v.strip() for v in value.split(',') if v.strip()]
|
||||||
elif self.vtype is bool:
|
elif vtype is bool \
|
||||||
return value[:1].lower() == 'y'
|
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):
|
def format(self, value):
|
||||||
type_ = type(value)
|
type_ = type(value)
|
||||||
|
|
Reference in a new issue