[lnst] lnst-ctl: Output usage when no action was specified
by Jiří Pírko
commit 20ffd6301e20e8231c38208a994151221eb11701
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Fri Aug 30 14:49:38 2013 +0200
lnst-ctl: Output usage when no action was specified
This commit fixes Issue #6.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst-ctl | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
---
diff --git a/lnst-ctl b/lnst-ctl
index 39bb5cf..55e2dd1 100755
--- a/lnst-ctl
+++ b/lnst-ctl
@@ -58,9 +58,6 @@ def process_recipe(action, file_path, cleanup, res_serializer,
return nettestctl.config_only_recipe()
elif action == "match_setup":
return nettestctl.match_setup()
- else:
- logging.error("Unknown action \"%s\"" % action)
- usage();
def get_recipe_result(args, file_path, cleanup, res_serializer, packet_capture,
log_ctl, pool_checks):
@@ -144,11 +141,14 @@ def main():
log_dir=lnst_config.get_option('environment', 'log_dir'),
log_subdir=date, colours=coloured_output)
- action = args.pop()
+ if len(args) <= 0:
+ logging.error("No action specified")
+ usage()
+ action = args.pop()
if not action in ['run', 'dump', 'config_only', 'match_setup']:
- logging.error("No action command passed")
- usage();
+ logging.error("Action '%s' not recognised" % action)
+ usage()
summary = []
10 years, 1 month
[PATCH] lnst-ctl: Output usage when no action was specified
by Radek Pazdera
This commit fixes Issue #6.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
lnst-ctl | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lnst-ctl b/lnst-ctl
index 39bb5cf..55e2dd1 100755
--- a/lnst-ctl
+++ b/lnst-ctl
@@ -58,9 +58,6 @@ def process_recipe(action, file_path, cleanup, res_serializer,
return nettestctl.config_only_recipe()
elif action == "match_setup":
return nettestctl.match_setup()
- else:
- logging.error("Unknown action \"%s\"" % action)
- usage();
def get_recipe_result(args, file_path, cleanup, res_serializer, packet_capture,
log_ctl, pool_checks):
@@ -144,11 +141,14 @@ def main():
log_dir=lnst_config.get_option('environment', 'log_dir'),
log_subdir=date, colours=coloured_output)
- action = args.pop()
+ if len(args) <= 0:
+ logging.error("No action specified")
+ usage()
+ action = args.pop()
if not action in ['run', 'dump', 'config_only', 'match_setup']:
- logging.error("No action command passed")
- usage();
+ logging.error("Action '%s' not recognised" % action)
+ usage()
summary = []
--
1.8.3.1
10 years, 1 month
[PATCH] Fix typo introduced after SlaveMachineParse rename
by Jan Tluka
This is a typo fix introduced after moving SlaveMachineParse.py to SlaveMachineParser.py.
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
---
lnst/Controller/SlavePool.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index 5872b0c..a6eb794 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -23,8 +23,8 @@ from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.NetUtils import test_tcp_connection
from lnst.Common.XmlProcessing import XmlProcessingError, XmlData
from lnst.Controller.Machine import Machine
-from lnst.Controller.SlaveMachineParse import SlaveMachineParser
-from lnst.Controller.SlaveMachineParse import SlaveMachineError
+from lnst.Controller.SlaveMachineParser import SlaveMachineParser
+from lnst.Controller.SlaveMachineParser import SlaveMachineError
class SlavePool:
"""
--
1.8.1.4
10 years, 1 month
[lnst] Fix typo introduced after SlaveMachineParse rename
by Jiří Pírko
commit 1fdf737b8161eee40961ea8bb39334c51b4c106f
Author: Jan Tluka <jtluka(a)redhat.com>
Date: Thu Aug 29 21:56:05 2013 +0200
Fix typo introduced after SlaveMachineParse rename
This is a typo fix introduced after moving SlaveMachineParse.py to SlaveMachineParser.py.
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/SlavePool.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
---
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index 5872b0c..a6eb794 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -23,8 +23,8 @@ from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.NetUtils import test_tcp_connection
from lnst.Common.XmlProcessing import XmlProcessingError, XmlData
from lnst.Controller.Machine import Machine
-from lnst.Controller.SlaveMachineParse import SlaveMachineParser
-from lnst.Controller.SlaveMachineParse import SlaveMachineError
+from lnst.Controller.SlaveMachineParser import SlaveMachineParser
+from lnst.Controller.SlaveMachineParser import SlaveMachineError
class SlavePool:
"""
10 years, 1 month
[PATCH 00/10] Switching XML parser from DOM to lxml.etree
by Radek Pazdera
Hello everyone,
this is the final part of the refactoring/redesign that happened on
the controller over the last month or two.
This series adds a dependency on python-lxml. However, the library is
quite common and in wide-spread use.
Apart from the formating of some error messages, there should be no
visible changes to LNST from the outside.
Cheers
-Radek
Radek Pazdera (10):
schema: Updating the cmd-sequence to task
schema: Removing 'source' and changing 'defines'
schema: Adding a schema for slavemachine xml
install: Adding schemes to the distribution
XmlParser: Moving the parser from DOM to etree
XmlProcessing: Updating the objects to support etree
XmlProcessing: Removing the XmlDomTreeInit
XmlTemplates: Changing to support etree
controller: Rewriting recipe parsing
controller: Rewriting slavemachine parsing
install/lnst-ctl.conf.in | 65 +++--
lnst/Common/Config.py | 5 +
lnst/Common/XmlParser.py | 303 ++++----------------
lnst/Common/XmlProcessing.py | 101 ++-----
lnst/Common/XmlTemplates.py | 104 +++----
lnst/Controller/NetTestController.py | 7 +-
lnst/Controller/RecipeParse.py | 394 --------------------------
lnst/Controller/RecipeParser.py | 255 +++++++++++++++++
lnst/Controller/SlaveMachineParse.py | 72 -----
lnst/Controller/SlaveMachineParser.py | 69 +++++
lnst/Controller/SlavePool.py | 18 +-
recipe-schema.rng | 515 ----------------------------------
schema-recipe.rng | 391 ++++++++++++++++++++++++++
schema-sm.rng | 82 ++++++
setup.py | 8 +-
15 files changed, 995 insertions(+), 1394 deletions(-)
delete mode 100644 lnst/Controller/RecipeParse.py
create mode 100644 lnst/Controller/RecipeParser.py
delete mode 100644 lnst/Controller/SlaveMachineParse.py
create mode 100644 lnst/Controller/SlaveMachineParser.py
delete mode 100644 recipe-schema.rng
create mode 100644 schema-recipe.rng
create mode 100644 schema-sm.rng
--
1.8.3.1
10 years, 1 month
[lnst] controller: Rewriting slavemachine parsing
by Jiří Pírko
commit aa964f7db3349fdbe5e439c20bebeaf980581879
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Wed Aug 28 16:41:30 2013 +0200
controller: Rewriting slavemachine parsing
With the changes in recipe parser, the slave machine parser has been
changed to use etree as well. Again, due to validation using the schema,
the code is now much simpler.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/SlaveMachineParse.py | 72 ---------------------------------
lnst/Controller/SlaveMachineParser.py | 69 +++++++++++++++++++++++++++++++
lnst/Controller/SlavePool.py | 18 ++------
3 files changed, 73 insertions(+), 86 deletions(-)
---
diff --git a/lnst/Controller/SlaveMachineParser.py b/lnst/Controller/SlaveMachineParser.py
new file mode 100644
index 0000000..02374cb
--- /dev/null
+++ b/lnst/Controller/SlaveMachineParser.py
@@ -0,0 +1,69 @@
+"""
+This module defines SlaveMachineParser class useful to parse XML machine
+descriptions for the slave pool
+
+Copyright 2013 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import logging
+import os
+import re
+from lxml import etree
+from lnst.Common.XmlParser import XmlParser
+from lnst.Common.XmlProcessing import XmlProcessingError, XmlData, XmlCollection
+
+class SlaveMachineError(XmlProcessingError):
+ pass
+
+class SlaveMachineParser(XmlParser):
+ def __init__(self, sm_path):
+ super(SlaveMachineParser, self).__init__("schema-sm.rng", sm_path)
+
+ def _process(self, sm_tag):
+ sm = XmlData(sm_tag)
+
+ # params
+ params_tag = sm_tag.find("params")
+ params = self._process_params(params_tag)
+ if len(params) > 0:
+ sm["params"] = params
+
+ # interfaces
+ interfaces_tag = sm_tag.find("interfaces")
+ if interfaces_tag is not None and len(interfaces_tag) > 0:
+ sm["interfaces"] = XmlCollection(interfaces_tag)
+ for eth_tag in interfaces_tag:
+ interface = self._process_interface(eth_tag)
+ sm["interfaces"].append(interface)
+
+ return sm
+
+ def _process_params(self, params_tag):
+ params = XmlCollection(params_tag)
+ if params_tag is not None:
+ for param_tag in params_tag:
+ param = XmlData(param_tag)
+ param["name"] = self._get_attribute(param_tag, "name")
+ param["value"] = self._get_attribute(param_tag, "value")
+ params.append(param)
+ return params
+
+ def _process_interface(self, iface_tag):
+ iface = XmlData(iface_tag)
+ iface["id"] = self._get_attribute(iface_tag, "id")
+ iface["network"] = self._get_attribute(iface_tag, "network")
+ iface["type"] = "eth"
+
+ # interface parameters
+ params_tag = iface_tag.find("params")
+ params = self._process_params(params_tag)
+ if len(params) > 0:
+ iface["params"] = params
+
+ return iface
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index e8baf83..5872b0c 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -18,13 +18,12 @@ import os
import re
import copy
from xml.dom import minidom
+from lnst.Common.Config import lnst_config
from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.NetUtils import test_tcp_connection
-from lnst.Common.XmlProcessing import XmlDomTreeInit
from lnst.Common.XmlProcessing import XmlProcessingError, XmlData
from lnst.Controller.Machine import Machine
-from lnst.Common.Config import lnst_config
-from lnst.Controller.SlaveMachineParse import SlaveMachineParse
+from lnst.Controller.SlaveMachineParse import SlaveMachineParser
from lnst.Controller.SlaveMachineParse import SlaveMachineError
class SlavePool:
@@ -56,20 +55,11 @@ class SlavePool:
def add_file(self, filepath):
if os.path.isfile(filepath) and re.search("\.xml$", filepath, re.I):
- dom_init = XmlDomTreeInit()
- dom = dom_init.parse_file(filepath)
-
dirname, basename = os.path.split(filepath)
-
- parser = SlaveMachineParse()
- parser.set_include_root(dirname)
- parser.disable_events()
-
m_id = re.sub("\.[xX][mM][lL]$", "", basename)
- slavemachine = dom.getElementsByTagName("slavemachine")[0]
- xml_data = parser.parse(slavemachine)
-
+ parser = SlaveMachineParser(filepath)
+ xml_data = parser.parse()
machine_spec = self._process_machine_xml_data(m_id, xml_data)
if self._pool_checks:
10 years, 1 month
[lnst] controller: Rewriting recipe parsing
by Jiří Pírko
commit a16ae22645e0c7610d79096768d63c9354a595bb
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Wed Aug 28 16:41:29 2013 +0200
controller: Rewriting recipe parsing
The RecipeParse class was renamed to RecipeParser and completely
rewritten to use the lxml etree instead of the Document Object Model for
processing XML files.
The etree supports document validation using the RelaxNG schema. Using
this lead to significant simplification of the parsing code.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/NetTestController.py | 7 +-
lnst/Controller/RecipeParse.py | 394 ----------------------------------
lnst/Controller/RecipeParser.py | 255 ++++++++++++++++++++++
3 files changed, 259 insertions(+), 397 deletions(-)
---
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index b8ffd26..33ead31 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -28,7 +28,7 @@ from lnst.Common.Utils import wait_for, md5sum, dir_md5sum, create_tar_archive
from lnst.Common.Utils import check_process_running, bool_it
from lnst.Common.NetTestCommand import NetTestCommandContext, NetTestCommand
from lnst.Common.NetTestCommand import str_command, CommandException
-from lnst.Controller.RecipeParse import RecipeParse, RecipeError
+from lnst.Controller.RecipeParser import RecipeParser, RecipeError
from lnst.Controller.SlavePool import SlavePool
from lnst.Controller.Machine import Machine, MachineError
from lnst.Common.ConnectionHandler import send_data, recv_data
@@ -64,9 +64,9 @@ class NetTestController:
mac_pool_range = lnst_config.get_option('environment', 'mac_pool_range')
self._mac_pool = MacPool(mac_pool_range[0], mac_pool_range[1])
- parser = RecipeParse(recipe_path)
+ parser = RecipeParser(recipe_path)
parser.set_machines(self._machines)
- self._recipe = parser.parse_recipe()
+ self._recipe = parser.parse()
modules_dirs = lnst_config.get_option('environment', 'module_dirs')
tools_dirs = lnst_config.get_option('environment', 'tool_dirs')
@@ -255,6 +255,7 @@ class NetTestController:
if not os.path.isfile(path):
msg = "Task file '%s' not found." % path
raise RecipeError(msg, task_data)
+ continue
task["commands"] = []
for cmd_data in task_data["commands"]:
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
new file mode 100644
index 0000000..9bebe8c
--- /dev/null
+++ b/lnst/Controller/RecipeParser.py
@@ -0,0 +1,255 @@
+"""
+This module defines RecipeParser class useful to parse xml recipes
+
+Copyright 2013 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import logging
+import os
+import re
+import sys
+from lnst.Common.Config import lnst_config
+from lnst.Common.NetUtils import normalize_hwaddr
+from lnst.Common.Utils import bool_it
+from lnst.Common.RecipePath import RecipePath
+from lnst.Common.XmlParser import XmlParser
+from lnst.Common.XmlProcessing import XmlProcessingError, XmlData, XmlCollection
+from lnst.Common.XmlTemplates import XmlTemplates, XmlTemplateError
+
+class RecipeError(XmlProcessingError):
+ pass
+
+class RecipeParser(XmlParser):
+ def __init__(self, recipe_path):
+ recipe_path = RecipePath(None, recipe_path).abs_path()
+ super(RecipeParser, self).__init__("schema-recipe.rng", recipe_path)
+
+ def _process(self, lnst_recipe):
+ recipe = XmlData(lnst_recipe)
+
+ # machines
+ machines_tag = lnst_recipe.find("machines")
+ if machines_tag is not None:
+ machines = recipe["machines"] = XmlCollection(machines_tag)
+ for machine_tag in machines_tag:
+ machines.append(self._process_machine(machine_tag))
+
+ # tasks
+ tasks = recipe["tasks"] = XmlCollection()
+ task_tags = lnst_recipe.findall("task")
+ for task_tag in task_tags:
+ tasks.append(self._process_task(task_tag))
+
+ return recipe
+
+ def _process_machine(self, machine_tag):
+ machine = XmlData(machine_tag)
+ machine["id"] = self._get_attribute(machine_tag, "id")
+
+ # params
+ params_tag = machine_tag.find("params")
+ params = self._process_params(params_tag)
+ if len(params) > 0:
+ machine["params"] = params
+
+ # interfaces
+ interfaces_tag = machine_tag.find("interfaces")
+ if interfaces_tag is not None and len(interfaces_tag) > 0:
+ machine["interfaces"] = XmlCollection(interfaces_tag)
+ for interface_tag in interfaces_tag:
+ interface = self._process_interface(interface_tag)
+ machine["interfaces"].append(interface)
+
+ return machine
+
+ def _process_params(self, params_tag):
+ params = XmlCollection(params_tag)
+ if params_tag is not None:
+ for param_tag in params_tag:
+ param = XmlData(param_tag)
+ param["name"] = self._get_attribute(param_tag, "name")
+ param["value"] = self._get_attribute(param_tag, "value")
+ params.append(param)
+
+ return params
+
+ def _process_interface(self, iface_tag):
+ iface = XmlData(iface_tag)
+ iface["id"] = self._get_attribute(iface_tag, "id")
+ iface["type"] = iface_tag.tag
+
+ if iface["type"] == "eth":
+ iface["network"] = self._get_attribute(iface_tag, "network")
+
+ # params
+ params_tag = iface_tag.find("params")
+ params = self._process_params(params_tag)
+ if len(params) > 0:
+ iface["params"] = params
+
+ # addresses
+ addresses_tag = iface_tag.find("addresses")
+ if addresses_tag is not None and len(addresses_tag) > 0:
+ iface["addresses"] = XmlCollection(addresses_tag)
+ for addr_tag in addresses_tag:
+ if self._has_attribute(addr_tag, "value"):
+ addr = self._get_attribute(addr_tag, "value")
+ else:
+ addr = self._get_content(addr_tag)
+ iface["addresses"].append(addr)
+
+
+ if iface["type"] in ["bond", "bridge", "vlan", "macvlan", "team"]:
+ # slaves
+ slaves_tag = iface_tag.find("slaves")
+ if slaves_tag is not None and len(slaves_tag) > 0:
+ iface["slaves"] = XmlCollection(slaves_tag)
+ for slave_tag in slaves_tag:
+ slave = XmlData(slave_tag)
+ slave["id"] = self._get_attribute(slave_tag, "id")
+
+ # slave options
+ opts_tag = slave_tag.find("options")
+ opts = self._proces_options(opts_tag)
+ if len(opts) > 0:
+ slave["options"] = opts
+
+ iface["slaves"].append(slave)
+
+ # interface options
+ opts_tag = iface_tag.find("options")
+ opts = self._proces_options(opts_tag)
+ if len(opts) > 0:
+ iface["options"] = opts
+
+ return iface
+
+ def _proces_options(self, opts_tag):
+ options = XmlCollection(opts_tag)
+ if opts_tag is not None:
+ for opt_tag in opts_tag:
+ opt = XmlData(opt_tag)
+ opt["name"] = self._get_attribute(opt_tag, "name")
+ if self._has_attribute(opt_tag, "value"):
+ opt["value"] = self._get_attribute(opt_tag, "value")
+ else:
+ opt["value"] = self._get_content(opt_tag)
+ options.append(opt)
+
+ return options
+
+ def _process_task(self, task_tag):
+ task = XmlData(task_tag)
+
+ if self._has_attribute(task_tag, "quit_on_fail"):
+ task["quit_on_fail"] = self._get_attribute(task_tag, "quit_on_fail")
+
+ if self._has_attribute(task_tag, "python"):
+ task["python"] = self._get_attribute(task_tag, "python")
+ return task
+
+ if len(task_tag) > 0:
+ task["commands"] = XmlCollection(task_tag)
+ for cmd_tag in task_tag:
+ if cmd_tag.tag == "run":
+ cmd = self._process_run_cmd(cmd_tag)
+ elif cmd_tag.tag == "config":
+ cmd = self._process_config_cmd(cmd_tag)
+ elif cmd_tag.tag == "ctl_wait":
+ cmd = self._process_ctl_wait_cmd(cmd_tag)
+ elif cmd_tag.tag in ["wait", "intr", "kill"]:
+ cmd = self._process_signal_cmd(cmd_tag)
+ else:
+ msg = "Unknown command '%s'." % cmd_tag.tag
+ raise RecipeError(msg, cmd_tag)
+
+ task["commands"].append(cmd)
+
+ return task
+
+ def _process_run_cmd(self, cmd_tag):
+ cmd = XmlData(cmd_tag)
+ cmd["machine"] = self._get_attribute(cmd_tag, "machine")
+
+ has_module = self._has_attribute(cmd_tag, "module")
+ has_command = self._has_attribute(cmd_tag, "command")
+ has_from = self._has_attribute(cmd_tag, "from")
+
+ if (has_module and has_command) or (has_module and has_from):
+ msg = "Invalid combination of attributes."
+ raise RecipeError(msg, cmd)
+
+ if has_module:
+ cmd["type"] = "test"
+ cmd["module"] = self._get_attribute(cmd_tag, "module")
+
+ # options
+ opts_tag = cmd_tag.find("options")
+ opts = self._proces_options(opts_tag)
+ if len(opts) > 0:
+ cmd["options"] = opts
+ elif has_command:
+ cmd["type"] = "exec"
+ cmd["command"] = self._get_attribute(cmd_tag, "command")
+
+ if self._has_attribute(cmd_tag, "from"):
+ cmd["from"] = self._get_attribute(cmd_tag, "from")
+
+ if self._has_attribute(cmd_tag, "bg_id"):
+ cmd["bg_id"] = self._get_attribute(cmd_tag, "bg_id")
+
+ if self._has_attribute(cmd_tag, "timeout"):
+ cmd["timeout"] = self._get_attribute(cmd_tag, "timeout")
+
+ if self._has_attribute(cmd_tag, "expect"):
+ cmd["expect"] = self._get_attribute(cmd_tag, "expect")
+
+ return cmd
+
+ def _process_config_cmd(self, cmd_tag):
+ cmd = XmlData(cmd_tag)
+ cmd["type"] = "config"
+ cmd["machine"] = self._get_attribute(cmd_tag, "machine")
+
+ if self._has_attribute(cmd_tag, "persistent"):
+ cmd["persistent"] = self._get_attribute(cmd_tag, "persistent")
+
+ # inline option
+ if self._has_attribute(cmd_tag, "option"):
+ cmd["options"] = XmlCollection(cmd_tag)
+ if self._has_attribute(cmd_tag, "value"):
+ opt = XmlData(cmd_tag)
+ opt["name"] = self._get_attribute(cmd_tag, "option")
+ opt["value"] = self._get_attribute(cmd_tag, "value")
+
+ cmd["options"] = XmlCollection(cmd_tag)
+ cmd["options"].append(opt)
+ else:
+ raise RecipeError("Missing option value.", cmd)
+ else:
+ # options
+ opts_tag = cmd_tag.find("options")
+ opts = self._proces_options(opts_tag)
+ if len(opts) > 0:
+ cmd["options"] = opts
+
+ return cmd
+
+ def _process_ctl_wait_cmd(self, cmd_tag):
+ cmd = XmlData(cmd_tag)
+ cmd["type"] = "ctl_wait"
+ cmd["seconds"] = self._get_attribute(cmd_tag, "seconds")
+ return cmd
+
+ def _process_signal_cmd(self, cmd_tag):
+ cmd = XmlData(cmd_tag)
+ cmd["type"] = cmd_tag.tag
+ cmd["machine"] = self._get_attribute(cmd_tag, "machine")
+ cmd["bg_id"] = self._get_attribute(cmd_tag, "bg_id")
+ return cmd
10 years, 1 month
[lnst] XmlTemplates: Changing to support etree
by Jiří Pírko
commit b45cd4d7aa819ae4562375d963f44030c59c8183
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Wed Aug 28 16:41:28 2013 +0200
XmlTemplates: Changing to support etree
The XML parser changed from DOM to etree. This patch changes the
XmlTemplates class to support etree. Some older code was also removed.
Alias and template functions processing is now handled separately.
Aliases are preprocessed before the document is parsed, while template
functions are expanded during the parsing.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/XmlTemplates.py | 104 +++++++++++++++++++++++--------------------
1 files changed, 55 insertions(+), 49 deletions(-)
---
diff --git a/lnst/Common/XmlTemplates.py b/lnst/Common/XmlTemplates.py
index e1f0f86..daa1254 100644
--- a/lnst/Common/XmlTemplates.py
+++ b/lnst/Common/XmlTemplates.py
@@ -239,37 +239,63 @@ class XmlTemplates:
err = "'%s' is not defined here" % name
raise XmlTemplateError(err)
- def expand_dom(self, node):
- """
- Traverse DOM tree from `node' down and expand any
- templates along the way.
+ def process_aliases(self, element):
+ """ Expand aliases within an element and its children
+
+ This method will iterate through the element tree that is
+ passed and expand aliases in all the text content and
+ attributes.
"""
+ if element.text != None:
+ element.text = self.expand_aliases(element.text)
- if node.nodeType == node.ELEMENT_NODE:
- i = 0
- num_attributes = node.attributes.length
- while(i < num_attributes):
- attr = node.attributes.item(i)
- attr.value = self.expand_string(str(attr.value))
- i += 1
- elif node.nodeType == node.TEXT_NODE:
- node.data = self.expand_string(str(node.data))
+ if element.tail != None:
+ element.tail = self.expand_aliases(element.tail)
- for child in node.childNodes:
- self.expand_dom(child)
+ for name, value in element.attrib.iteritems():
+ element.set(name, self.expand_aliases(value))
- def expand_group(self, group):
- """
- Behaves exactly the same as the `expand' method, but it
- operates on a group of DOM nodes stored within a list,
- rather than a single node.
- """
+ if element.tag == "define":
+ for alias in element.getchildren():
+ name = alias.attrib["name"]
+ value = alias.attrib["value"]
+ self.define_alias(name, value)
+ parent = element.getparent()
+ parent.remove(element)
+ return
+
+ self.add_namespace_level()
+
+ for child in element.getchildren():
+ self.process_aliases(child)
+
+ self.drop_namespace_level()
+
+ def expand_aliases(self, string):
+ while True:
+ alias_match = re.search(self._alias_re, string)
+
+ if alias_match:
+ template = alias_match.group(0)
+ result = self._process_alias_template(template)
+ string = string.replace(template, result)
+ else:
+ break
+
+ return string
+
+ def _process_alias_template(self, string):
+ result = None
+
+ alias_match = re.match(self._alias_re, string)
+ if alias_match:
+ alias_name = alias_match.group(1)
+ result = self._find_definition(alias_name)
- for node in group:
- self.expand_dom(node)
+ return result
- def expand_string(self, string, node=None):
- """ Process a string and expand it into a XmlTemplateString. """
+ def expand_functions(self, string, node=None):
+ """ Process a string and expand it into a XmlTemplateString """
parts = self._partition_string(string)
value = XmlTemplateString(node=node)
@@ -282,9 +308,8 @@ class XmlTemplates:
def _partition_string(self, string):
""" Process templates in a string
- This method will process and expand all templates contained
- within a string. It handles both aliases and template
- function.
+ This method will process and expand all template functions
+ in a string.
The function returns an array of string partitions and
unresolved template functions for further processing.
@@ -292,16 +317,6 @@ class XmlTemplates:
result = None
- while True:
- alias_match = re.search(self._alias_re, string)
-
- if alias_match:
- template = alias_match.group(0)
- result = self._process_alias_template(template)
- string = string.replace(template, result)
- else:
- break
-
func_match = re.search(self._func_re, string)
if func_match:
prefix = string[0:func_match.start(0)]
@@ -315,16 +330,6 @@ class XmlTemplates:
return [string]
- def _process_alias_template(self, string):
- result = None
-
- alias_match = re.match(self._alias_re, string)
- if alias_match:
- alias_name = alias_match.group(1)
- result = self._find_definition(alias_name)
-
- return result
-
def _process_func_template(self, string):
func_match = re.match(self._func_re, string)
if func_match:
@@ -350,4 +355,5 @@ class XmlTemplates:
func = self._func_map[func_name](param_values, self._machines)
return func
else:
- raise RuntimeError("The passed string is not a template function.")
+ msg = "The passed string is not a template function."
+ raise XmlTemplateError(msg)
10 years, 1 month
[lnst] XmlProcessing: Removing the XmlDomTreeInit
by Jiří Pírko
commit 6d351a4b6e7055c70516e027934205b525e84d1f
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Wed Aug 28 16:41:27 2013 +0200
XmlProcessing: Removing the XmlDomTreeInit
Removing some old DOM-tree related code.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/XmlProcessing.py | 66 ------------------------------------------
1 files changed, 0 insertions(+), 66 deletions(-)
---
diff --git a/lnst/Common/XmlProcessing.py b/lnst/Common/XmlProcessing.py
index 9c3e5fe..f4d9105 100644
--- a/lnst/Common/XmlProcessing.py
+++ b/lnst/Common/XmlProcessing.py
@@ -12,8 +12,6 @@ rpazdera(a)redhat.com (Radek Pazdera)
import os
import logging
-from xml.dom.minidom import parseString
-from xml import sax
class XmlProcessingError(Exception):
""" Exception thrown on parsing errors """
@@ -188,67 +186,3 @@ class XmlTemplateString(object):
def add_part(self, part):
self._parts.append(part)
-
-class XmlDomTreeInit:
- """ Handles creation/initialization of DOM trees
-
- It allows you to parse XML file or string into a DOM tree.
- It also adds an extra parameter to each node of the tree
- called `loc' which can be used to determine where exactly
- was the element placed in the original source XML file.
- This is useful for error reporting.
- """
-
- _sax = None
- _filename = None
- __orig_set_content_handler = None
-
- def __init__(self):
- self._init_sax()
-
- def _init_sax(self):
- parser = sax.make_parser()
- self.__orig_set_content_handler = parser.setContentHandler
- parser.setContentHandler = self.__set_content_handler
- self._sax = parser
-
- def __set_content_handler(self, dom_handler):
- def start_element_ns(name, tag_name , attrs):
- orig_start_cb(name, tag_name, attrs)
- cur_elem = dom_handler.elementStack[-1]
- loc = {"file": self._filename,
- "line": self._sax.getLineNumber(),
- "col": self._sax.getColumnNumber()}
- cur_elem.loc = loc
-
- orig_start_cb = dom_handler.startElementNS
- dom_handler.startElementNS = start_element_ns
- self.__orig_set_content_handler(dom_handler)
-
- @staticmethod
- def _load_file(filename):
- handle = open(filename, "r")
- data = handle.read()
- handle.close()
- return data
-
- def parse_file(self, xml_filepath):
- xml_text = self._load_file(xml_filepath)
- filename = os.path.basename(xml_filepath)
- return self.parse_string(xml_text, filename)
-
- def parse_string(self, xml_text, filename="xml_string"):
- self._filename = os.path.basename(filename)
- try:
- dom = parseString(xml_text, self._sax)
- except sax.SAXParseException as err:
- loc = {"file": self._filename,
- "line": err.getLineNumber(),
- "col": err.getColumnNumber()}
- exc = XmlProcessingError(err.getMessage())
- exc.set_loc(loc)
- raise exc
-
- loc = {"file": self._filename, "line": 0, "col": 0}
- dom.loc = loc
- return dom
10 years, 1 month
[lnst] XmlProcessing: Updating the objects to support etree
by Jiří Pírko
commit 3ad679f167b9d31d0c755903be670fc01b777d65
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Wed Aug 28 16:41:26 2013 +0200
XmlProcessing: Updating the objects to support etree
The XmlProcessingError, XmlCollection, and XmlData objects were updated,
so they support the etree nodes instead of the DOM nodes that were
previously used.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/XmlProcessing.py | 35 ++++++++++++++++++++++++++++-------
1 files changed, 28 insertions(+), 7 deletions(-)
---
diff --git a/lnst/Common/XmlProcessing.py b/lnst/Common/XmlProcessing.py
index a709659..9c3e5fe 100644
--- a/lnst/Common/XmlProcessing.py
+++ b/lnst/Common/XmlProcessing.py
@@ -24,18 +24,25 @@ class XmlProcessingError(Exception):
def __init__(self, msg, obj=None):
super(XmlProcessingError, self).__init__()
-
self._msg = msg
if obj and hasattr(obj, "loc"):
self.set_loc(obj.loc)
- #logging.error(self.__str__())
+ loc = {}
+ if obj:
+ if hasattr(obj, "base") and obj.base != None:
+ loc["file"] = os.path.basename(obj.base)
+ if hasattr(obj, "sourceline"):
+ loc["line"] = obj.sourceline
+ self.set_loc(loc)
+
def set_loc(self, loc):
self._filename = loc["file"]
self._line = loc["line"]
- #self._col = loc["col"]
+ if "col" in loc:
+ self._col = loc["col"]
def __str__(self):
line = ""
@@ -82,8 +89,15 @@ class XmlDataIterator:
class XmlCollection(list):
def __init__(self, node=None):
super(XmlCollection, self).__init__()
- if node:
- self.loc = node.loc
+ if node is not None:
+ if hasattr(node, "loc"):
+ self.loc = node.loc
+ elif hasattr(node, "base") and node.base != None:
+ loc = {}
+ loc["file"] = os.path.basename(node.base)
+ if hasattr(node, "sourceline"):
+ loc["line"] = node.sourceline
+ self.loc = loc
def __getitem__(self, key):
value = super(XmlCollection, self).__getitem__(key)
@@ -99,8 +113,15 @@ class XmlCollection(list):
class XmlData(dict):
def __init__(self, node=None):
super(XmlData, self).__init__()
- if node:
- self.loc = node.loc
+ if node is not None:
+ if hasattr(node, "loc"):
+ self.loc = node.loc
+ elif hasattr(node, "base") and node.base != None:
+ loc = {}
+ loc["file"] = os.path.basename(node.base)
+ if hasattr(node, "sourceline"):
+ loc["line"] = node.sourceline
+ self.loc = loc
def __getitem__(self, key):
value = super(XmlData, self).__getitem__(key)
10 years, 1 month