Compare commits

...

2 Commits

20 changed files with 169 additions and 32 deletions

View File

@ -9,8 +9,8 @@ from shutil import copy
import logging
from typing import Dict, Any
from subprocess import call
from os import listdir, makedirs
from os.path import dirname, join, isfile, abspath, normpath
from os import listdir, makedirs, getcwd, chdir
from os.path import dirname, join, isfile, abspath, normpath, relpath
from Cheetah.Template import Template as ChtTemplate
from Cheetah.NameMapper import NotFound as CheetahNotFound
@ -79,7 +79,8 @@ class CheetahTemplate(ChtTemplate):
context,
eosfunc: Dict,
destfilename,
variable):
variable,
):
"""Initialize Creole CheetahTemplate
"""
extra_context = {'is_defined' : IsDefined(context),
@ -93,11 +94,15 @@ class CheetahTemplate(ChtTemplate):
searchList=[context, eosfunc, extra_context])
# FORK of Cheetah fonction, do not replace '\\' by '/'
def serverSidePath(self, path=None,
def serverSidePath(self,
path=None,
normpath=normpath,
abspath=abspath
):
# strange...
if path is None and isinstance(self, str):
path = self
if path:
return normpath(abspath(path))
# return normpath(abspath(path.replace("\\", '/')))
@ -107,7 +112,6 @@ class CheetahTemplate(ChtTemplate):
return None
class CreoleLeader:
def __init__(self, value, follower=None, index=None):
"""
@ -302,37 +306,43 @@ class CreoleTemplateEngine:
return CreoleExtra(families)
def patch_template(self,
filename: str):
filename: str,
tmp_dir: str,
patch_dir: str,
) -> None:
"""Apply patch to a template
"""
patch_cmd = ['patch', '-d', self.tmp_dir, '-N', '-p1']
patch_cmd = ['patch', '-d', tmp_dir, '-N', '-p1']
patch_no_debug = ['-s', '-r', '-', '--backup-if-mismatch']
# patches variante + locaux
for directory in [join(Config['patch_dir'], 'variante'), Config['patch_dir']]:
patch_file = join(directory, f'{filename}.patch')
if isfile(patch_file):
log.info(_("Patching template '{filename}' with '{patch_file}'"))
ret = call(patch_cmd + patch_no_debug + ['-i', patch_file])
if ret:
patch_cmd_err = ' '.join(patch_cmd + ['-i', patch_file])
log.error(_(f"Error applying patch: '{patch_file}'\nTo reproduce and fix this error {patch_cmd_err}"))
copy(filename, self.tmp_dir)
patch_file = join(patch_dir, f'{filename}.patch')
if isfile(patch_file):
log.info(_("Patching template '{filename}' with '{patch_file}'"))
rel_patch_file = relpath(patch_file, tmp_dir)
ret = call(patch_cmd + patch_no_debug + ['-i', rel_patch_file])
if ret:
patch_cmd_err = ' '.join(patch_cmd + ['-i', rel_patch_file])
log.error(_(f"Error applying patch: '{rel_patch_file}'\nTo reproduce and fix this error {patch_cmd_err}"))
copy(join(self.distrib_dir, filename), tmp_dir)
def prepare_template(self,
filename: str):
filename: str,
tmp_dir: str,
patch_dir: str,
) -> None:
"""Prepare template source file
"""
log.info(_("Copy template: '{filename}' -> '{self.tmp_dir}'"))
copy(filename, self.tmp_dir)
self.patch_template(filename)
log.info(_("Copy template: '{filename}' -> '{tmp_dir}'"))
copy(filename, tmp_dir)
self.patch_template(filename, tmp_dir, patch_dir)
def process(self,
source: str,
true_destfilename: str,
destfilename: str,
filevar: Dict,
variable: Any):
variable: Any,
):
"""Process a cheetah template
"""
# full path of the destination file
@ -356,7 +366,10 @@ class CreoleTemplateEngine:
def instance_file(self,
filevar: Dict,
service_name: str) -> None:
service_name: str,
tmp_dir: str,
dest_dir: str,
) -> None:
"""Run templatisation on one file
"""
log.info(_("Instantiating file '{filename}'"))
@ -370,13 +383,13 @@ class CreoleTemplateEngine:
if variable:
variable = [variable]
for idx, filename in enumerate(filenames):
destfilename = join(self.dest_dir, filename[1:])
destfilename = join(dest_dir, filename[1:])
makedirs(dirname(destfilename), exist_ok=True)
if variable:
var = variable[idx]
else:
var = None
source = join(self.tmp_dir, filevar['source'])
source = join(tmp_dir, filevar['source'])
if filevar['templating']:
self.process(source,
filename,
@ -389,6 +402,11 @@ class CreoleTemplateEngine:
async def instance_files(self) -> None:
"""Run templatisation on all files
"""
ori_dir = getcwd()
tmp_dir = relpath(self.tmp_dir, self.distrib_dir)
dest_dir = relpath(self.dest_dir, self.distrib_dir)
patch_dir = relpath(Config['patch_dir'], self.distrib_dir)
chdir(self.distrib_dir)
for option in await self.config.option.list(type='all'):
namespace = await option.option.name()
if namespace == Config['variable_namespace']:
@ -397,8 +415,8 @@ class CreoleTemplateEngine:
families = await self.load_eole_variables(namespace,
option)
self.rougail_variables_dict[namespace] = families
for template in listdir(self.distrib_dir):
self.prepare_template(join(self.distrib_dir, template))
for template in listdir('.'):
self.prepare_template(template, tmp_dir, patch_dir)
for service_obj in await self.config.option('services').list('all'):
service_name = await service_obj.option.doc()
for fills in await service_obj.list('all'):
@ -406,15 +424,17 @@ class CreoleTemplateEngine:
for fill_obj in await fills.list('all'):
fill = await fill_obj.value.dict()
filename = fill['source']
distib_file = join(self.distrib_dir, filename)
if not isfile(distib_file):
raise FileNotFound(_(f"File {distib_file} does not exist."))
if not isfile(filename):
raise FileNotFound(_(f"File {filename} does not exist."))
if fill.get('activate', False):
self.instance_file(fill,
service_name,
tmp_dir,
dest_dir,
)
else:
log.debug(_("Instantiation of file '{filename}' disabled"))
chdir(ori_dir)
async def generate(config: Config,

View File

@ -0,0 +1,20 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services>
<service name="test">
<file name="/etc/file"/>
</service>
</services>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="Description">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "services.test.files.file.group": "root", "services.test.files.file.mode": "0644", "services.test.files.file.name": "/etc/file", "services.test.files.file.owner": "root", "services.test.files.file.source": "file", "services.test.files.file.templating": true, "services.test.files.file.activate": true}

View File

@ -0,0 +1 @@
non

View File

@ -0,0 +1,26 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='Description', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_8 = StrOption(name='group', doc='group', multi=False, default='root')
option_9 = StrOption(name='mode', doc='mode', multi=False, default='0644')
option_10 = StrOption(name='name', doc='name', multi=False, default='/etc/file')
option_11 = StrOption(name='owner', doc='owner', multi=False, default='root')
option_12 = StrOption(name='source', doc='source', multi=False, default='file')
option_13 = BoolOption(name='templating', doc='templating', multi=False, default=True)
option_14 = BoolOption(name='activate', doc='activate', multi=False, default=True)
option_7 = OptionDescription(name='file', doc='file', children=[option_8, option_9, option_10, option_11, option_12, option_13, option_14])
option_6 = OptionDescription(name='files', doc='files', children=[option_7])
option_5 = OptionDescription(name='test', doc='test', children=[option_6])
option_5.impl_set_information("manage", True)
option_4 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_5])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_4])

View File

@ -0,0 +1 @@
%include "incfile"

View File

@ -0,0 +1 @@
%%mode_conteneur_actif

View File

@ -0,0 +1,20 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services>
<service name="test">
<file name="/etc/file"/>
</service>
</services>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="Description">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "services.test.files.file.group": "root", "services.test.files.file.mode": "0644", "services.test.files.file.name": "/etc/file", "services.test.files.file.owner": "root", "services.test.files.file.source": "file", "services.test.files.file.templating": true, "services.test.files.file.activate": true}

View File

@ -0,0 +1,5 @@
--- tmpl/file 2020-11-20 07:44:38.588472784 +0100
+++ dest/file 2020-11-20 07:44:54.588536011 +0100
@@ -1 +1 @@
-unpatched
+patched

View File

@ -0,0 +1 @@
patched

View File

@ -0,0 +1,26 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='Description', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_8 = StrOption(name='group', doc='group', multi=False, default='root')
option_9 = StrOption(name='mode', doc='mode', multi=False, default='0644')
option_10 = StrOption(name='name', doc='name', multi=False, default='/etc/file')
option_11 = StrOption(name='owner', doc='owner', multi=False, default='root')
option_12 = StrOption(name='source', doc='source', multi=False, default='file')
option_13 = BoolOption(name='templating', doc='templating', multi=False, default=True)
option_14 = BoolOption(name='activate', doc='activate', multi=False, default=True)
option_7 = OptionDescription(name='file', doc='file', children=[option_8, option_9, option_10, option_11, option_12, option_13, option_14])
option_6 = OptionDescription(name='files', doc='files', children=[option_7])
option_5 = OptionDescription(name='test', doc='test', children=[option_6])
option_5.impl_set_information("manage", True)
option_4 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_5])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_4])

View File

@ -0,0 +1 @@
unpatched

View File

@ -1,4 +1,5 @@
from lxml import etree
from os import getcwd
from os.path import isfile, join, isdir
from pytest import fixture, raises
from os import listdir
@ -25,11 +26,14 @@ for test in listdir(dico_dirs):
test_raise.add(test)
excludes = set([])
#excludes = set(['01base_file_utfchar'])
test_ok -= excludes
test_raise -= excludes
#test_ok = ['10leadership_autoleader']
#test_raise = []
ORI_DIR = getcwd()
debug = False
#debug = True
@ -80,6 +84,7 @@ def launch_flattener(test_dir, test_ok=False):
if isdir(subfolder):
eolobj.create_or_populate_from_xml('extra1', [subfolder])
eosfunc = join(dico_dirs, '../eosfunc/test.py')
Config['patch_dir'] = join(test_dir, 'patches')
eolobj.space_visitor(eosfunc)
tiramisu_objects = eolobj.save()
tiramisu_dir = join(test_dir, 'tiramisu')
@ -109,14 +114,18 @@ def teardown_module(module):
def test_dictionary(test_dir):
assert getcwd() == ORI_DIR
test_dir = join(dico_dirs, test_dir)
launch_flattener(test_dir, True)
assert getcwd() == ORI_DIR
def test_error_dictionary(test_dir_error):
assert getcwd() == ORI_DIR
test_dir = join(dico_dirs, test_dir_error)
with raises(DictConsistencyError):
launch_flattener(test_dir)
assert getcwd() == ORI_DIR
def test_no_dtd():

View File

@ -20,7 +20,7 @@ for test in listdir(dico_dirs):
debug = False
#debug = True
excludes = set([])
#excludes = set(['70container_services'])
#excludes = set(['01base_file_utfchar'])
test_ok -= excludes
#test_ok = ['10check_valid_ipnetmask']

View File

@ -9,7 +9,10 @@ from rougail import template
template_dirs = 'tests/dictionaries'
test_ok = [f for f in listdir(template_dirs) if not f.startswith('_') and isdir(join(template_dirs, f, 'tmpl'))]
excludes = set([])
#excludes = set(['01base_file_utfchar'])
test_ok = {f for f in listdir(template_dirs) if not f.startswith('_') and isdir(join(template_dirs, f, 'tmpl'))}
test_ok -= excludes
#test_ok = ['60extra_group']
@ -55,6 +58,7 @@ async def test_dictionary(test_dir):
if isdir(dest_dir):
rmtree(dest_dir)
mkdir(dest_dir)
template.Config['patch_dir'] = join(test_dir, 'patches')
await template.generate(config,
funcs_file,
distrib_dir,