rougail/creole/lint/creolelint.py

1196 lines
44 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
creole lint main module
"""
import types
import sys
import re
from glob import glob
from os.path import join, basename, isfile, abspath, normpath, isabs
from lxml.etree import parse
from creole import config, eosfunc
from pyeole.process import system_code
from creole.lint.parsetemplate import parse_templates
from creole.lint.normalize import is_correct
from creole.var_loader import parse_dtd
from creole.lxml_parser import parse_xml_file
from creole.config import FLATTENED_CREOLE_DIR, dtdfilename
from creole.loader import PopulateTiramisuObjects
# variables internes aux dictionnaires
DICO_TEST_VARS = ['test_', 'tmp_']
# variables de conteneur calculées dynamiquement
CONTAINER_VARS = ['container_path_', 'container_ip_', 'container_name_',
'adresse_ip_ftp', 'adresse_ip_mysql', 'adresse_ip_dhcp',
'adresse_ip_internet', 'adresse_ip_interbase',
'adresse_ip_postgresql']
# faux-positifs sur les variables d'activation
EXCLUDE_ACTIVATION_VARS = ['activer_cntlm_eth0', 'activer_cntlm_eth1',
'activer_cntlm_eth2', 'activer_cntlm_eth3',
'activer_cntlm_eth4', 'activer_supp_proxy_eth0',
'activer_bash_completion', 'activer_log_martian',
'activer_dns_eth0', 'activer_ctrl_alt_suppr',
'activer_ipv6', 'activer_courier_commun',
'activer_web_valider_ca', 'activer_admin_passfile',
'activer_regles_filtrage_port_source',
'activer_ftp_anonymous_access', 'activer_ftp_access',
'activer_pydio_local', 'activer_courier_imap_sso',
'activer_pydio_ftp', 'activer_client_ldap',
]
# templates à ne pas tester par défaut
EXCLUDE_TMPL = ['/usr/share/eole/creole/distrib/named.conf',
'/usr/share/eole/creole/distrib/common-squid1.conf',
'/usr/share/eole/creole/distrib/zstats.cfg',
'/usr/share/eole/creole/distrib/hosts',
'/usr/share/eole/creole/distrib/active_tags',
]
# dictionnaires conservés pour compatibilité 2.3
OLD_DICOS = ['/usr/share/eole/creole/dicos/51_gepi.xml',
'/usr/share/eole/creole/dicos/51_taskfreak.xml',
'/usr/share/eole/creole/dicos/51_wordpress.xml',
'/usr/share/eole/creole/dicos/60_roundcube.xml',
'/usr/share/eole/creole/dicos/61_ajaxplorer.xml',
'/usr/share/eole/creole/dicos/61_dokuwiki.xml',
'/usr/share/eole/creole/dicos/61_fluxbb.xml',
'/usr/share/eole/creole/dicos/61_piwigo.xml',
'/usr/share/eole/creole/dicos/51_grr.xml',
'/usr/share/eole/creole/dicos/51_cdt.xml',
'/usr/share/eole/creole/dicos/51_piwik.xml',
'/usr/share/eole/creole/dicos/51_spip.xml',
]
starttoken = '%'
varstarttoken = '%%'
builts = [u'ArithmeticError', u'AssertionError', u'AttributeError',
u'BaseException', u'DeprecationWarning', u'EOFError', u'Ellipsis',
u'EnvironmentError', u'Exception', u'False', u'FloatingPointError',
u'FutureWarning', u'GeneratorExit', u'IOError', u'ImportError',
u'ImportWarning', u'IndentationError', u'IndexError', u'KeyError',
u'KeyboardInterrupt', u'LookupError', u'MemoryError', u'NameError',
u'None', u'NotImplemented', u'NotImplementedError', u'OSError',
u'OverflowError', u'PendingDeprecationWarning', u'ReferenceError',
u'RuntimeError', u'RuntimeWarning', u'StandardError',
u'StopIteration', u'SyntaxError', u'SyntaxWarning', u'SystemError',
u'SystemExit', u'TabError', u'True', u'TypeError',
u'UnboundLocalError', u'UnicodeDecodeError', u'UnicodeEncodeError',
u'UnicodeError', u'UnicodeTranslateError', u'UnicodeWarning',
u'UserWarning', u'ValueError', u'Warning', u'ZeroDivisionError',
u'_', u'__debug__', u'__doc__', u'__import__', u'__name__', u'abs',
u'all', u'any', u'apply', u'basestring', u'bool', u'buffer',
u'callable', u'chr', u'classmethod', u'cmp', u'coerce', u'compile',
u'complex', u'copyright', u'credits', u'delattr', u'dict', u'dir',
u'divmod', u'enumerate', u'eval', u'execfile', u'exit', u'file',
u'filter', u'float', u'frozenset', u'getattr', u'globals',
u'hasattr', u'hash', u'help', u'hex', u'id', u'input', u'int',
u'intern', u'isinstance', u'issubclass', u'iter', u'len',
u'license', u'list', u'locals', u'long', u'map', u'max', u'min',
u'object', u'oct', u'open', u'ord', u'pow', u'property', u'quit',
u'range', u'raw_input', u'reduce', u'reload', u'repr', u'reversed',
u'round', u'set', u'setattr', u'slice', u'sorted', u'staticmethod',
u'str', u'sum', u'super', u'tuple', u'type', u'unichr', u'unicode',
u'vars', u'xrange', u'zip']
builts.append(u'is_defined')
builts.append(u'split')
builts.append(u'lower')
cmd_client = (u'creole_client', ('get', 'get_containers'))
for func in dir(eosfunc):
if not func.startswith('_'):
builts.append(unicode(func, 'utf-8'))
# FIXME: je sais pas où la mettre
def is_container_var(varname):
"""
variables de conteneur calculées dynamiquement
"""
for var in CONTAINER_VARS:
if varname.startswith(var):
return True
return False
class TmplVar():
def __init__(self, name, fd, line):
self.name = name
self.location = []
self.add_location(fd, line)
def add_location(self, fd, line):
fd = basename(fd)
self.location.append((fd, line+1))
def set_location(self, location):
self.location = location
def get_location(self):
return self.location
class Var():
def __init__(self, name, description, separator, help, defaultvalue, is_slave):
self.name = name
self.description = description
self.separator = separator
self.help = help
self.defaultvalue = defaultvalue
self.is_slave = is_slave
class CreoleLinter:
"""Base class for linters, collects creole vars and templates
**has to be launched once and only once**
"""
display = True
class __impl:
warnno = 1
warncomment = "Undefined comment"
""" Implementation of the singleton interface """
def set_config(self, tmpl_dir_or_file=None):
if tmpl_dir_or_file != None and type(tmpl_dir_or_file) != str:
raise TypeError('tmpl_dir_or_file doit être une string')
if self.tmpl_dir_or_file != None:
sys.stderr('Tentative de redefinition de tmpl_dir_or_file')
if tmpl_dir_or_file == None:
self.tmpl_dir_or_file = config.distrib_dir
else:
if not isabs(tmpl_dir_or_file):
tmpl_dir_or_file = normpath(join(config.distrib_dir, tmpl_dir_or_file))
if not isfile(tmpl_dir_or_file):
raise Exception("template doit etre le nom d'un template valide")
self.tmpl_dir_or_file = tmpl_dir_or_file
self.eoledirs = config.eoledirs
self.dtddir = config.dtddir
self.exclude_var = []
self.pkgname = None
def load_dics(self):
if self.config is None:
self._collect_vars_in_dicos()
# def load_tmpls(self):
# if self.tmplvars == None:
# self._collect_set_vars()
# self._collect_def_vars()
# self._collect_for_vars()
# self._collect_define_vars()
# self._collect_vars_in_tmplfiles()
#
def get_dicos_name(self):
if self.config is None:
raise Exception('Dictionnaire non chargé')
dic = self.variables.keys()
dic.sort()
return dic
# def get_dicos_files(self):
# if self.creoledic == None:
# raise Exception('Dictionnaire non chargé')
# dic = []
# for name in self.creoledic.generic['files']:
# dic.append(basename(name['source']))
# dic.sort()
# return dic
#
# def get_tmplvars_name(self):
# if self.tmplvars == None:
# raise Exception('Template non chargé')
# tmpl = self.tmplvars.keys()
# tmpl.sort()
# return tmpl
#
# def get_defvars_name(self):
# if self.defvars == None:
# raise Exception('Template non chargé')
# defv = self.defvars.keys()
# defv.sort()
# return defv
#
# def get_setvars_name(self):
# if self.setvars == None:
# raise Exception('Fonction non chargé')
# var = self.setvars.keys()
# var.sort()
# return var
#
# def get_forvars_name(self):
# if self.forvars == None:
# raise Exception('Fonction non chargé')
# var = self.forvars.keys()
# var.sort()
# return var
#
# def get_tmplvar(self, name):
# return self.tmplvars[name]
#
# def get_separators(self):
# return self.creoledic.get_separators()
#
def get_dico_file_names(self):
if self.eoledirs == None or self.tmpl_dir_or_file == None:
raise Exception('Utiliser la methode set_config avant')
ret = []
for eoledir in self.eoledirs:
eoledir = abspath(eoledir)
if isfile(eoledir):
ret.append(eoledir)
else:
ret.extend(glob(join(eoledir, '*.xml')))
return ret
def get_dtd(self):
if self.dtddir == None:
raise Exception('Utiliser la methode set_config avant')
return join(self.dtddir, 'creole.dtd')
def _collect_vars_in_dicos(self):
if self.eoledirs == None or self.tmpl_dir_or_file == None:
raise Exception('Utiliser la methode set_config avant')
flattened = join(FLATTENED_CREOLE_DIR, 'flattened_creole.xml')
with file(flattened, 'r') as fhd:
xmlroot = parse(fhd).getroot()
tiramisu_objects = PopulateTiramisuObjects()
tiramisu_objects.parse_dtd(dtdfilename)
tiramisu_objects.make_tiramisu_objects(xmlroot)
self.config = tiramisu_objects.build()
self.config.read_write()
self.config.cfgimpl_get_settings().remove('hidden')
self.config.cfgimpl_get_settings().remove('validator')
self.config.cfgimpl_get_settings().remove('disabled')
for path in self.config.creole.make_dict():
spath = path.split('.')
vname = spath[-1]
fname = spath[0]
is_slave = False
if len(spath) == 3:
master = spath[1]
if master != vname:
is_slave = True
option = self.config.unwrap_from_path('creole.' + path)
self.variables[vname] = Var(vname, option.impl_get_information('doc', None),
option.impl_get_information('separator', ''),
option.impl_get_information('help', None),
option.impl_getdefault(),
is_slave)
if fname not in self.families:
self.families.append(fname)
def _parse_tabs_in_dicos(self):
if self.eoledirs == None or self.tmpl_dir_or_file == None:
raise Exception('Utiliser la methode set_config avant')
tabs_in_dics = []
fnames = []
for directory in self.eoledirs:
if isfile(directory):
fnames.append(directory)
else:
fnames.extend(glob(join(directory, "*.xml")))
for fname in fnames:
fh = file(fname, 'r')
content = fh.read()
if '\t' in content:
tabs_in_dics.append(fname)
fh.close()
return tabs_in_dics
def _list_tmpl_files(self):
if isfile(self.tmpl_dir_or_file):
return [self.tmpl_dir_or_file]
ret = []
for filename in glob(join(self.tmpl_dir_or_file, '*')):
if filename.startswith('.') or filename.endswith('~'):
continue
if filename in EXCLUDE_TMPL:
print " \\-- template desactivé : {0}".format(filename)
continue
ret.append(filename)
return ret
# def _add_collected_var(self, dvar, var, fd, linenb):
# if dvar.has_key(var):
# dvar[var].add_location(fd=fd, line=linenb)
# else:
# dvar[var] = TmplVar(name=var, fd=fd, line=linenb)
#
# def _collect_var_in(self, dvar, var, fd, linenb, exists=False):
# not_added=True
# if exists == True:
# if self.forvars.has_key(var):
# #si deja en memoire
# if (basename(fd), linenb+1) in self.forvars[var].location:
# return
# self._add_collected_var(self.forvars, var, fd, linenb)
# not_added=False
# if self.setvars.has_key(var):
# self._add_collected_var(self.setvars, var, fd, linenb)
# not_added=False
# if self.defvars.has_key(var):
# self._add_collected_var(self.defvars, var, fd, linenb)
# not_added=False
# #test les builtsin seulement si variable
# if not_added == True and unicode(var, 'utf-8') in builts:
# #self.builtsvar.append(var)
# return
# if not_added == True:
# self._add_collected_var(dvar, var, fd, linenb)
#
# def _collect_vars_in(self, expr, dvar, fd, linenb, tvarstarttoken,
# exists=False):
# if self.unknown_client == None:
# self.unknown_client = []
# varcreole = re.compile(tvarstarttoken+'([a-zA-Z0-9_\.{}]+)')
# varcreole2 = re.compile(tvarstarttoken+'(\w+)')
# varcreolebr = re.compile(tvarstarttoken+'{(\w+)}')
# varmulti = re.compile('(\w+)\.(\w+)')
# for var in varcreole.findall(expr):
# ret = varmulti.match(var)
# if ret != None:
# if ret.group(1) == cmd_client[0]:
# if ret.group(2) not in cmd_client[1]:
# self.unknown_client.append(TmplVar(name=ret.group(2), fd=fd, line=linenb))
# else:
# #%%var.sousvar
# self._collect_var_in(dvar, ret.group(1), fd, linenb, exists)
# self._collect_var_in(dvar, ret.group(2), fd, linenb, exists)
# else:
# #%%var
# for var2 in varcreole2.findall(tvarstarttoken+var):
# self._collect_var_in(dvar, var2, fd, linenb, exists)
# #%%{var}
# for var2 in varcreolebr.findall(tvarstarttoken+var):
# self._collect_var_in(dvar, var2, fd, linenb, exists)
#
# def _collect_vars(self, tvars, tpattern, all_char=False, with_var=False, with_vars=True, broken=None):
# """
# collect vars in template for a specified pattern
#
# :tvars: all collected var are store in this variable
# :tpattern: re pattern
# :broken: if set, store broken variable
# """
# if tvars == None:
# tvars = {}
# tstarttoken = ''
# tvarstarttoken = ''
# for tmplfd in self._list_tmpl_files():
# fh = open(tmplfd, 'r')
# lines = fh.readlines()
# length = len(lines)
# settings = False
# if tstarttoken != starttoken or \
# tvarstarttoken != varstarttoken:
# if all_char:
# char = '(.*)'
# else:
# char = '( *)'
# pattern = re.compile(char+starttoken+tpattern)
# tstarttoken = starttoken
# tvarstarttoken = varstarttoken
# for linenb in range(length):
# line = lines[linenb]
# if line.strip() == '%compiler-settings':
# settings = True
# if settings and line.strip() == \
# '%end compiler-settings'.strip():
# settings = False
# if not settings:
# ret = pattern.match(line.strip())
# if ret != None:
# expr = ret.group(2).strip()
# if with_var:
# self._collect_var_in(tvars, expr, tmplfd, linenb)
# if with_vars:
# self._collect_vars_in(expr,
# tvars, tmplfd, linenb,
# tvarstarttoken)
# len_token = len(varstarttoken)
# if broken is not None and expr.strip()[:len_token] != tvarstarttoken:
# broken.append(TmplVar(
# name=line.strip(),
# fd=tmplfd, line=linenb))
# else:
# tline = line.split('=')
# tkey = tline[0].strip()
# if tkey == 'cheetahVarStartToken':
# tvarstarttoken = tline[1].strip()
# elif tkey == 'directiveStartToken':
# tstarttoken = tline[1].strip()
# pattern = re.compile(tstarttoken+tpattern)
# fh.close()
# return tvars
#
# def _collect_for_vars(self):
# """
# collect all vars generate in 'for'
# """
# self.brokenfor = []
# self.forvars = self._collect_vars(self.forvars, 'for (.+) in (.*)', broken=self.brokenfor)
#
# def _collect_def_vars(self):
# """
# collect all vars generate in 'def'
# """
# self.defvars = self._collect_vars(self.defvars, 'def (.*)\((.*)\)', with_var=True)
#
# def _collect_set_vars(self):
# """
# collect all vars generate in 'set'
# """
# self.setvars = self._collect_vars(self.setvars, 'set (.*)=.*')
#
# def _collect_define_vars(self):
# """
# collect all vars generate in 'def'
# """
# self.var_with_is_defined = self._collect_vars(
# self.var_with_is_defined,
# "is_defined\(\'(\w+)\'\)",
# all_char=True,
# with_var=True, with_vars=False)
# ##FIXME pas de support de cheetahVarStartToken, ...
# #if self.var_with_is_defined == None:
# # self.var_with_is_defined = {}
# # pattern = re.compile('(.*) %sis_defined\(\'(\w+)\'\)'%varstarttoken)
# # for tmplfd in self._list_tmpl_files():
# # fh = open(tmplfd, 'r')
# # lines = fh.readlines()
# # length = len(lines)
# # for linenb in range(length):
# # line = lines[linenb]
# # ret = pattern.match(line)
# # if ret != None:
# # self._collect_var_in(self.var_with_is_defined, ret.group(2), tmplfd, linenb)
# # fh.close()
#
# def _collect_vars_in_tmplfiles(self):
# if self.eoledirs == None or self.tmpl_dir_or_file == None:
# raise Exception('Utiliser la methode set_config avant')
# # XXX ".eolvars" is a good placeholder for var names to be kept in touch
# if self.tmplvars == None:
# self.tmplvars = {}
# for tmplfd in self._list_tmpl_files():
# fh = open(tmplfd, 'r')
# lines = fh.readlines()
# length = len(lines)
# settings = False
# tvarstarttoken = varstarttoken
# for linenb in range(length):
# line = lines[linenb]
# if line.strip() == '%compiler-settings':
# settings = True
# if settings and line.strip() == \
# '%end compiler-settings'.strip():
# settings = False
# if not settings:
# self._collect_vars_in(line, self.tmplvars, tmplfd,
# linenb, tvarstarttoken, True)
# else:
# tline = line.split('=')
# tkey = tline[0].strip()
# if tkey == 'cheetahVarStartToken':
# tvarstarttoken = tline[1].strip()
#
# fh.close()
#
# storage for the instance reference
__instance = None
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if CreoleLinter.__instance is None:
# Create and remember instance
CreoleLinter.__instance = CreoleLinter.__impl()
self.tmpl_dir_or_file = None
self.eoledirs = None
self.config = None
self.variables = {}
self.families = []
self.tmplvars = None
self.forvars = None
self.defvars = None
self.setvars = None
self.unknown_client = None
self.brokenfor = None
self.var_with_is_defined = None
self.exclude_var = None
self.skip_var = {}
self.conflevel = 'eole'
# Store instance reference as the only member in the handle
self.__dict__['_CreoleLinter__instance'] = CreoleLinter.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
#class SaveItem(CreoleLinter):
# """
# eolvars not present in the dicos
# """
# name = 'save'
# warnno = 1
# warncomment = "Ne pas utiliser la fonction SaveItem comme un test"
#
# def process(self):
# self.load_dics()
# if self.pkgname == None:
# raise Exception('fichier creolelint.conf incomplet (name)')
# filename = join(expanduser('~/.creolelint'), self.pkgname+'.conf')
# fh = open(filename, 'w')
# fh.write('vardico = '+str(self.get_dicos_name())+'\n')
# fh.close()
# print('fichier sauvegardé')
#
# def check(self):
# return []
#
#class OrphansInDicosItem(CreoleLinter):
# """
# eolvars not present in the dicos
# """
# name = 'orphans_in_dicos'
# warnno = 8
# warncomment = "Variable dictionnaire non utilisée dans un template"
#
# def check(self):
# self.load_dics()
# self.load_tmpls()
#
# vars_name = set(self.get_dicos_name())
# tmplvars_name = set(self.get_tmplvars_name())
# only_in_dicos = vars_name - tmplvars_name
# ret = []
# skip_var = self.skip_var.get(self.name, {})
# for var in only_in_dicos:
# if skip_var.has_key(var):
# continue
# test_start = False
# for start in DICO_TEST_VARS:
# if var.startswith(start):
# test_start = True
# break
# if not test_start:
# ret.append(self.variables[var])
# return ret
#
#class OrphansInTmplItem(CreoleLinter):
# """
# eolvars not present in the templates
# """
# name = 'orphans_in_tmpl'
# warnno = 8
# warncomment = "Variable template non présente dans le dictionnaire"
#
# def check(self):
# self.load_dics()
# self.load_tmpls()
#
# vars_name = self.get_dicos_name()
# if self.exclude_var != None:
# vars_name.extend(self.exclude_var)
# vars_name=set(vars_name)
# tmplvars_name = set(self.get_tmplvars_name())
# only_in_tmpl = tmplvars_name - vars_name
# #remove is_defined
# is_defined_name = set(self.var_with_is_defined.keys())
# only_in_tmpl = only_in_tmpl - is_defined_name
# set_var = set(self.get_setvars_name())
# only_in_tmpl = only_in_tmpl - set_var
# ret = []
# for var in only_in_tmpl:
# skipped_location = []
# for location in self.tmplvars[var].location:
# if self.skip_var.has_key(self.name) and self.skip_var[self.name].has_key(var):
# if not location in self.skip_var[self.name][var]:
# skipped_location.append(location)
# else:
# skipped_location.append(location)
# if skipped_location != []:
# tmplvar = TmplVar(var, '', 0)
# tmplvar.set_location(skipped_location)
# ret.append(tmplvar)
# #results.append(self.tmplvars[var])
# return ret
#
#class OrphansDefItem(CreoleLinter):
# name = 'orphans_def'
# warnno = 7
# warncomment = "Fonction définie mais non utilisée"
#
# def check(self):
# self.load_tmpls()
# results = []
# for defvar in self.get_defvars_name():
# defname = {}
# for filedesc, linenb in self.defvars[defvar].location:
# if not defname.has_key((defvar, filedesc)):
# defname[(defvar, filedesc)]=linenb
# else:
# defname[(defvar, filedesc)]="exists"
# for defvar, filedesc in defname.keys():
# if defname[(defvar, filedesc)] != "exists":
# results.append(TmplVar(name=defvar, fd=filedesc, line=defname[(defvar, filedesc)]))
#
# return results
#
#class OrphansSetItem(CreoleLinter):
# name = 'orphans_set'
# warnno = 7
# warncomment = "Variable définie dans le template mais non utilisée"
#
# def check(self):
# self.load_tmpls()
# results = []
# tmpl_vars = set(self.get_tmplvars_name())
# for setvar in self.get_setvars_name():
# setname = {}
# for filedesc, linenb in self.setvars[setvar].location:
# if setname.has_key((setvar, filedesc)) == False:
# setname[(setvar, filedesc)]=linenb
# else:
# setname[(setvar, filedesc)]="exists"
#
# for setvar, filedesc in setname.keys():
# if setname[(setvar, filedesc)] != "exists":
# results.append(TmplVar(name=setvar, fd=filedesc, line=setname[(setvar, filedesc)]))
#
# return results
#
#class OrphansForItem(CreoleLinter):
# name = 'orphans_for'
# warnno = 7
# warncomment = "Variable définie dans une boucle mais non utilisée"
#
# def check(self):
# self.load_tmpls()
# results = []
# for forvar in self.get_forvars_name():
# forname = {}
# for filedesc, linenb in self.forvars[forvar].location:
# if forname.has_key((forvar, filedesc)) == False:
# forname[(forvar, filedesc)]=linenb
# else:
# forname[(forvar, filedesc)]="exists"
#
# for forvar, filedesc in forname.keys():
# if forname[(forvar, filedesc)] != "exists":
# results.append(TmplVar(name=forvar, fd=filedesc, line=forname[(forvar, filedesc)]))
# return results
#
#class OrphansDicosFilesItem(CreoleLinter):
# """
# """
# name = 'orphans_dicos_files'
# warnno = 1
# warncomment = "Template déclaré dans le dicos inexistant"
#
# def check(self):
# self.load_dics()
#
# dicos_files = []
# for filen in self.get_dicos_files():
# dicos_files.append(basename(filen))
# dicos_files = set(dicos_files)
# tmpl_files = []
# for filen in self._list_tmpl_files():
# tmpl_files.append(unicode(basename(filen), 'utf-8'))
# tmpl_files=set(tmpl_files)
# orphans = dicos_files - tmpl_files
# ret = []
# for var in orphans:
# if self.skip_var.has_key(self.name) and not self.skip_var[self.name].has_key(var):
# ret.append(var)
# else:
# ret.append(var)
#
# return ret
#
#class OrphansTmplFilesItem(CreoleLinter):
# """
# """
# name = 'orphans_tmpl_files'
# warnno = 1
# warncomment = "Template non déclaré dans le dicos"
#
# def check(self):
# self.load_dics()
#
# dicos_files = []
# for filen in self.get_dicos_files():
# dicos_files.append(basename(filen))
# dicos_files = set(dicos_files)
# tmpl_files = []
# for filen in self._list_tmpl_files():
# tmpl_files.append(unicode(basename(filen), 'utf-8'))
# tmpl_files=set(tmpl_files)
# return tmpl_files - dicos_files
#
class WrongDicosNameItem(CreoleLinter):
name = 'wrong_dicos_name'
warnno = 6
warncomment = "Dictionnaire avec un nom invalide"
def check(self):
if self.conflevel == 'common':
pattern = '(0'
elif self.conflevel == 'conf':
pattern = '(1'
elif self.conflevel == 'eole':
pattern = '(2'
else:
pattern = '([3-9]'
pattern += '[0-9]_[a-z0-9_]+)'
cpattern = re.compile(pattern)
ret = []
for filename in self.get_dico_file_names():
name = basename(filename)
if cpattern.match(name) == None:
ret.append(name)
return ret
class HiddenIfInDicosItem(CreoleLinter):
name = 'hidden_if_in_dicos'
warnno = 5
warncomment = "Dictionnaire contenant un hidden_if_*"
def check(self):
ret = []
dtd = parse_dtd(self.get_dtd())
for filename in self.get_dico_file_names():
if filename in OLD_DICOS:
continue
parse = parse_xml_file(filename, dtd, parse_all=False)
for cond in parse['conditions'].values():
if cond[0]['name'].startswith('hidden_if_'):
ret.append(filename)
break
return ret
class ConditionWithoutTarget(CreoleLinter):
name = 'condition_without_target'
warnno = 5
warncomment = "Dictionnaire contenant une condition sans target"
def check(self):
ret = []
dtd = parse_dtd(self.get_dtd())
for filename in self.get_dico_file_names():
if filename in OLD_DICOS:
continue
parse = parse_xml_file(filename, dtd, parse_all=False)
for cond in parse['conditions'].values():
for con in cond:
if con['family'] == con['list'] == con['variable'] == []:
ret.append(filename)
break
return ret
class ObligatoireInDicosItem(CreoleLinter):
name = 'obligatoire_in_dicos'
warnno = 5
warncomment = "Dictionnaire contenant un check \"obligatoire\""
def check(self):
ret = []
dtd = parse_dtd(self.get_dtd())
for filename in self.get_dico_file_names():
if filename in OLD_DICOS:
continue
parse = parse_xml_file(filename, dtd, parse_all=False)
for cond in parse['checks'].values():
if cond[0][0] == 'obligatoire':
ret.append(filename)
break
return ret
class FamilyWithoutHelp(CreoleLinter):
name = 'family_without_help'
warnno = 5
warncomment = "Famille sans balise d'aide"
def check(self):
self.load_dics()
ret = []
for grp in self.config.creole.iter_groups():
doc = grp[1].cfgimpl_get_description().impl_get_information('help', None)
if doc is None:
ret.append(grp[0])
return ret
class FamilyWithoutIcon(CreoleLinter):
name = 'family_without_icon'
warnno = 5
warncomment = "Famille sans icône spécifique"
def check(self):
self.load_dics()
ret = []
for grp in self.config.creole.iter_groups():
if grp[1].cfgimpl_get_description().impl_get_information('icon') is None:
ret.append(grp[0])
return ret
#class DefineItem(CreoleLinter):
# """
# check for syntaxes
# """
# name = 'define'
# warnno = 4
# warncomment = "Redéfinition d'un variable d'un dictionnaire"
#
# def check(self):
# """
# verifie si une variable définie est une variable du dictionnaire
# """
# self.load_dics()
# self.load_tmpls()
# dicos = set(self.get_dicos_name())
# defv = set(self.get_defvars_name())
# ret=[]
# for var in defv & dicos:
# ret.append(self.defvars[var])
# return ret
#
class BuiltinsItem(CreoleLinter):
"""
verifier si une variable de dico n'est pas dans l'espace de nommage
"""
name = 'builtins'
warnno = 4
warncomment = "Variable identitique à une fonction python"
def check(self):
self.load_dics()
# self.load_tmpls()
ret = []
#dans le dictionnaire
for var in set(builts) & set(self.get_dicos_name()):
ret.append(self.variables[var])
# #dans les variables de template
# for var in set(builts) & set(self.get_tmplvars_name()):
# ret.append(self.tmplvars[var])
# #dans les boucles for
# for var in set(builts) & set(self.get_forvars_name()):
# ret.append(self.forvars[var])
# #dans la definition de variable dans un template
# for var in set(builts) & set(self.get_setvars_name()):
# ret.append(self.setvars[var])
# #dans les noms de fonction
# for var in set(builts) & set(self.get_defvars_name()):
# ret.append(self.defvars[var])
return ret
#class SyntaxForItem(CreoleLinter):
# """
# verifie la syntaxe de la ligne for
# """
# name = 'syntax_for'
# warnno = 1
# warncomment = "Syntaxe de la ligne for incorrect"
# def check(self):
# self.load_tmpls()
# return self.brokenfor
#
#class SyntaxVarItem(CreoleLinter):
# """
# verifie les variables suivant la syntaxe de pattern
# """
# name = 'syntax_var'
# pattern = '([a-z0-9][a-z0-9]+_[a-z0-9_]+)'
# warnno = 6
# warncomment = "La variable ne respecte pas la regexp %s" % pattern
#
# def check(self):
# cpattern = re.compile(self.pattern)
# self.load_dics()
# self.load_tmpls()
# ret=[]
# #dans le dictionnaire
# for var in self.get_dicos_name():
# if cpattern.match(var) == None:
# ret.append(self.variables[var])
# #dans les variables de template
# for var in self.get_tmplvars_name():
# if cpattern.match(var) == None:
# skipped_location = []
# for location in self.tmplvars[var].location:
# if self.skip_var.has_key(self.name) and self.skip_var[self.name].has_key(var):
# if not location in self.skip_var[self.name][var]:
# skipped_location.append(location)
# else:
# skipped_location.append(location)
# if skipped_location != []:
# tmplvar = TmplVar(var, '', 0)
# tmplvar.set_location(skipped_location)
# ret.append(tmplvar)
# #ret.append(self.tmplvars[var])
# #dans les boucles for
# for var in self.get_forvars_name():
# if cpattern.match(var) == None:
# ret.append(self.forvars[var])
# #dans la definition de variable dans un template
# for var in self.get_setvars_name():
# if cpattern.match(var) == None:
# ret.append(self.setvars[var])
# return ret
#
#class ForbiddenTemplateVarItem(CreoleLinter):
# """
# vérifie la présence des noms de variable interdits dans les templates
# """
# name = 'syntax_var2'
# warnno = 6
# warncomment = "Nom de variable interdit dans un template"
#
# def check(self):
# #self.load_dics()
# self.load_tmpls()
# ret=[]
# #dans les variables de template
# for var in self.get_tmplvars_name():
# for start in DICO_TEST_VARS:
# if var.startswith(start):
# ret.append(var)
# break
# return ret
#
#class SyntaxFunctionItem(CreoleLinter):
# """
# verifie les fonctions suivant la syntaxe de pattern
# """
# name = 'syntax_function'
# pattern = '([a-z0-9][a-z0-9]+_[a-z0-9_]+)'
# warnno = 6
# warncomment = "La fonction ne respecte pas la regexp %s" % pattern
#
# def check(self):
# cpattern = re.compile(self.pattern)
# self.load_tmpls()
# ret=[]
# #dans les noms de fonction
# for var in self.get_defvars_name():
# if cpattern.match(var) == None:
# ret.append(self.defvars[var])
# return ret
#
#class OrphansVarHelpItem(CreoleLinter):
# name = 'orphans_var_help'
# warnno = 3
# warncomment = "Aide définie dans le dictionnaire pour une variable inexistante"
#
# def check(self):
# self.load_dics()
# vars_name = set(self.get_dicos_name())
# vars_help = set(self.creoledic.get_helps()['variables'].keys())
# #print vars_help
# only_in_help = vars_help - vars_name
# results = []
# for tmpl in only_in_help:
# results.append(tmpl)
# return results
#class OrphansFamHelpItem(CreoleLinter):
# name = 'orphans_fam_help'
# warnno = 3
# warncomment = "Aide définie dans le dictionnaire pour une famille inexistante"
#
# def check(self):
# self.load_dics()
# #FIXME
# vars_name = set(self.families)
# vars_help = set(self.creoledic.get_helps()['families'].keys())
# only_in_help = vars_help - vars_name
# results = []
# for tmpl in only_in_help:
# results.append(tmpl)
# return results
#
class ValidVarLabelItem(CreoleLinter):
name = 'valid_var_label'
warnno = 5
warncomment = "Libellé de variable non valide dans un dictionnaire"
def check(self):
self.load_dics()
ret = []
for var in self.variables.values():
if not is_container_var(var.name):
ret.extend(is_correct(var.description, var.name))
return ret
class ActivationVarWithoutHelp(CreoleLinter):
name = 'activation_var_without_help'
warnno = 5
warncomment = "Variable d'activation sans balise d'aide"
def check(self):
self.load_dics()
ret = []
for var, var_obj in self.variables.items():
if var.startswith('activer_') and var not in EXCLUDE_ACTIVATION_VARS:
if var_obj.help is None:
ret.append(var)
return ret
class ValidSeparatorLabelItem(CreoleLinter):
name = 'valid_separator_label'
warnno = 5
warncomment = "Libellé de séparateur non valide dans un dictionnaire"
def check(self):
self.load_dics()
ret = []
for var, var_obj in self.variables.items():
if var_obj.separator == '':
#FIXME: variables de conteneur dynamiques
continue
ret.extend(is_correct(var_obj.separator[0], var))
return ret
class ValidHelpLabelItem(CreoleLinter):
name = 'valid_help_label'
warnno = 5
warncomment = "Libellé d'aide non valide dans un dictionnaire"
def check(self):
self.load_dics()
ret = []
for var, var_obj in self.variables.items():
# help/variable
ret.extend(is_correct(var_obj.help, var))
for grp in self.config.creole.iter_groups():
# help/family
ret.extend(is_correct(grp[1].cfgimpl_get_description().impl_get_information('help', ''),
grp[0], family=True))
return ret
class ValidSlaveValue(CreoleLinter):
name = 'valid_slave_value'
warnno = 5
warncomment = "Variable esclave avec une liste en valeur défaut"
def check(self):
self.load_dics()
ret = []
for var, var_obj in self.variables.items():
if var_obj.is_slave:
if len(var_obj.defaultvalue) > 1:
ret.append(var)
return ret
##class ValidCheckEnumOuiNon(CreoleLinter):
## name = 'valid_check_enum_ouinon'
## warnno = 6
## warncomment = "Variable avec un valid_enum à oui/non au lieu du type oui/non"
##
## def check(self):
## ret = []
## for var, content in self.creoledic.variables.items():
## print content
## if str(type(content)) != "<class 'creole.typeole.OuiNon'>":
## for check in content.choices:
## if check[0] == u'valid_enum':
## for valid_enum in check[1]:
## if valid_enum['value'].startswith('['):
## eval_valid_enum = eval(valid_enum['value'])
## if set(eval_valid_enum) == set(['non', 'oui']):
## ret.append(var)
## return ret
#
##class ValidCheckEnumOnOff(CreoleLinter):
## name = 'valid_check_enum_onoff'
## warnno = 6
## warncomment = "Variable avec un valid_enum à on/off au lieu du type on/off"
##
## def check(self):
## ret = []
## for var, content in self.creoledic.variables.items():
## if str(type(content)) != "<class 'creole.typeole.OnOff'>":
## for check in content.checks:
## if check[0] == u'valid_enum':
## for valid_enum in check[1]:
## if valid_enum['value'].startswith('['):
## eval_valid_enum = eval(valid_enum['value'])
## if set(eval_valid_enum) == set(['on', 'off']):
## ret.append(var)
## return ret
#
class TabsInDicosItem(CreoleLinter):
name = 'tabs_in_dicos'
warnno = 5
warncomment = "Tabulation dans le dictionnaire au lieu de 4 espaces"
def check(self):
return self._parse_tabs_in_dicos()
#class ValidClientOption(CreoleLinter):
# name = 'valid_client_option'
# warnno = 6
# warncomment = "Option inconnu pour %s" % cmd_client[0]
#
# def check(self):
# self.load_tmpls()
# return self.unknown_client
class ValidParseTmpl(CreoleLinter):
name = 'valid_parse_tmpl'
warnno = 1
warncomment = "Template Non valide"
display = False
def check(self):
parse_templates(self._list_tmpl_files())
return []
class ValidDTDItem(CreoleLinter):
name = 'valid_dtd'
warnno = 1
warncomment = "DTD Non valide"
display = False
def check(self):
dtd = self.get_dtd()
for filename in self.get_dico_file_names():
system_code(['xmllint', '--noout', '--dtdvalid', dtd, filename])
return []
class OldFwFile(CreoleLinter):
name = 'old_fw_file'
warnno = 5
warncomment = "Ancien fichier eole-firewall présent sur le serveur"
def check(self):
fw_templates = '/usr/share/eole/creole/distrib/*.fw'
fw_files = '/usr/share/eole/firewall/*.fw'
return glob(fw_files) + glob(fw_templates)
def validate(keyword, ansi, tmpl):
globs = globals()
classitem = None
for cls in globs:
if cls.startswith('_') and type(globs[cls])!=types.ClassType and cls == 'CreoleLinter' and cls == 'TmplVar':
continue
if hasattr(globs[cls], 'name'):
if globs[cls].name == keyword:
classitem = globs[cls]
break
if classitem == None:
raise Exception('test %s inconnu'%keyword)
cl = classitem()
if cl.eoledirs == None:
cl.set_config(tmpl_dir_or_file=tmpl)
ansi.process(cl)