Merge pull request #194 from grooverdan/defination-substitution

ENH: Allow recursive tag substitution in action files
pull/199/merge
Yaroslav Halchenko 2013-04-30 06:47:30 -07:00
commit cb6e47c871
3 changed files with 60 additions and 1 deletions

View File

@ -92,6 +92,8 @@ Borreli, blotus:
* [c8c7b0b,23bbc60] Better logging of log file read errors.
* [3665e6d] Added code coverage to development process.
* [41b9f7b,32d10e9] More complete ssh filter rules to match openssh source.
* [1d9abd1] Action files can have tags in definition that refer to other
tags.
Pascal Borreli
* [a2b29b4] Fixed lots of typos in config files and documentation.
hamilton5

View File

@ -28,7 +28,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging, os
import threading
import threading, re
#from subprocess import call
# Gets the instance of the logger.
@ -143,6 +143,10 @@ class Action:
# @return True if the command succeeded
def execActionStart(self):
if self.__cInfo:
if not Action.substituteRecursiveTags(self.__cInfo):
logSys.error("Cinfo/definitions contain self referencing definitions and cannot be resolved")
return False
startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
return Action.executeCmd(startCmd)
@ -242,6 +246,38 @@ class Action:
stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
return Action.executeCmd(stopCmd)
##
# Sort out tag definitions within other tags
#
# so: becomes:
# a = 3 a = 3
# b = <a>_3 b = 3_3
# @param tags, a dictionary
# @returns tags altered or False if there is a recursive definition
#@staticmethod
def substituteRecursiveTags(tags):
t = re.compile(r'<([^ >]+)>')
for tag, value in tags.iteritems():
value = str(value)
m = t.search(value)
while m:
if m.group(1) == tag:
# recursive definitions are bad
return False
else:
if tags.has_key(m.group(1)):
value = value[0:m.start()] + tags[m.group(1)] + value[m.end():]
m = t.search(value, m.start())
else:
# Missing tags are ok so we just continue on searching.
# cInfo can contain aInfo elements like <HOST> and valid shell
# constructs like <STDIN>.
m = t.search(value, m.start() + 1)
tags[tag] = value
return tags
substituteRecursiveTags = staticmethod(substituteRecursiveTags)
#@staticmethod
def escapeTag(tag):
for c in '\\#&;`|*?~<>^()[]{}$\n\'"':
if c in tag:

View File

@ -61,6 +61,27 @@ class ExecuteAction(unittest.TestCase):
def _is_logged(self, s):
return s in self._log.getvalue()
def testSubstituteRecursiveTags(self):
aInfo = {
'HOST': "192.0.2.0",
'ABC': "123 <HOST>",
'xyz': "890 <ABC>",
}
# Recursion is bad
self.assertFalse(Action.substituteRecursiveTags({'A': '<A>'}))
self.assertFalse(Action.substituteRecursiveTags({'A': '<B>', 'B': '<A>'}))
self.assertFalse(Action.substituteRecursiveTags({'A': '<B>', 'B': '<C>', 'C': '<A>'}))
# missing tags are ok
self.assertEquals(Action.substituteRecursiveTags({'A': '<C>'}), {'A': '<C>'})
self.assertEquals(Action.substituteRecursiveTags({'A': '<C> <D> <X>','X':'fun'}), {'A': '<C> <D> fun', 'X':'fun'})
self.assertEquals(Action.substituteRecursiveTags({'A': '<C> <B>', 'B': 'cool'}), {'A': '<C> cool', 'B': 'cool'})
# rest is just cool
self.assertEquals(Action.substituteRecursiveTags(aInfo),
{ 'HOST': "192.0.2.0",
'ABC': '123 192.0.2.0',
'xyz': '890 123 192.0.2.0',
})
def testReplaceTag(self):
aInfo = {
'HOST': "192.0.2.0",