1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 |
- #!/usr/bin/env python3
- import sys
- import os
- import errno
- import getopt
- import stat
- import re
- import operator
- from xml.etree import ElementTree, ElementInclude
- import xml.sax
- def info(message, level=1):
- """ @brief Print info to stdout
- @param message string to print
- """
- if VERBOSE >= level:
- sys.stderr.write("*II* %s\n" % message)
- def warning(message):
- """ @brief Print warning to stdout
- @param message string to print
- """
- if ERROR_ON_WARNING:
- error(message)
- if WARNING:
- sys.stderr.write("*WW* %s\n" % message)
- def error(message):
- """ @brief Print error to stdout
- @param message string to print
- """
- print("*EE* %s " % message)
- sys.exit(1)
- def usage(myname):
- print("\nUsage: %s OPTIONS <XML_FILE>\n" % myname)
- print("Read configuration from an XML file and create config files.")
- print("""
- %s reads a data base of configuration parameters from an XML file.
- Subsequently, a number of template files are processed in order to create
- configuration files (targets). See ec-conf User Guide for more information.""" % myname)
- print("""
- Options: -h|--help Print this help screen.
- -p|--platform Set the active platform.
- -l|--list-platforms Lists all platforms, which are defined in the XML file, on stdout.
- -d|--prefix=<PATH> Creates the directory PATH (if non-existing) and writes all target
- files within that directory. Also sets a configuration parameter
- named PLT:ACTIVE:PREFIXDIR for use in the template files.
- -o|--overwrite-parameter <NAME>=<VALUE>
- Allows to set new values to configuration parameters from the
- command line, overwriting the values from the XML file.
- <NAME> must be given in the form
- 'COMPONENT_TYPE:COMPONENT_NAME:PARAMETER_NAME' corresponding to
- the place-holder syntax of ec-conf. See ec-conf user guide for details.
- Multiple parameters can be overwritten by repeating this option.
- -x|--write-xml Writes the content of <XML_FILE> in XML format to stdout.
- This can be used to normalise the XML file and for test purposes.
- -g|--gui Starts the graphical user interface. Turns off -x and -l.
- -v|--verbose Produces verbose output (stderr). To increase verbosity,
- use more than once.
- -w|--no-warning Turns off warnings (however, errors are displayed).
- -e|--error-on-warning Turns warnings into errors (i.e. ec-conf will stop).
- """)
- sys.exit(2)
- class TextNode(object):
- """Represents an XML node that contains only text, i.e. is not named and has no child nodes"""
- def __init__(self):
- self.text = ""
- def add_text(self, content):
- self.text += content
- class NamedNode(object):
- """Represents an XML node with a certain type according to the document
- definition. Base class for Configuration, Translation, Platform, Model,
- and Parameter"""
- def __init__(self, attr=None):
- self.name = None
- self.description = None
- if attr:
- if 'name' in list(attr.keys()):
- self.name = attr['name']
- info('Create named node: ' + self.name +
- ' (' + self.__class__.__name__ + ')', level=2)
- def set(self, key, value):
- self.__dict__.__setitem__(key, value)
- def xml(self, level=0):
- """Provides XML representation of the NamedNode as a string"""
- tabwidth = 4
- xml_string = ' ' * level * tabwidth
- xml_string += '<' + self.__class__.__name__
- if 'name' in self.__dict__ and self.name:
- xml_string += ' name="' + self.name + '"'
- xml_string += '>\n'
- for element in 'description', 'template', 'target', 'properties', 'type', 'value':
- if element in self.__dict__:
- xml_string += ' ' * (level + 1) * tabwidth
- xml_string += '<' + element.capitalize() + '>'
- if self.__dict__[element]:
- xml_string += self.__dict__[element]
- xml_string += '</' + element.capitalize() + '>\n'
- if level <= 1:
- xml_string += '\n'
- for element in 'translation', 'platform', 'model', 'parameter':
- if element in self.__dict__:
- for child_element in self.__dict__[element]:
- xml_string += child_element.xml(level + 1)
- xml_string += ' ' * level * tabwidth
- xml_string += '</' + self.__class__.__name__ + '>\n'
- if level > 0 and level <= 2:
- xml_string += '\n'
- return xml_string
- def plt(self, name=None):
- """Provides short-hand access to the Platform member with name 'name'."""
- if 'platform' in self.__dict__:
- if name:
- for plt in self.platform:
- if plt.name == name:
- return plt
- else:
- return self.platform
- return None
- def mod(self, name=None):
- """Provides short-hand access to the Model member with name 'name'."""
- if 'model' in self.__dict__:
- if name:
- for mod in self.model:
- if mod.name == name:
- return mod
- else:
- return self.model
- return None
- def par(self, name=None):
- """Provides short-hand access to the Parameter member with name 'name'."""
- if 'parameter' in self.__dict__:
- if name:
- for par in self.parameter:
- if par.name == name:
- return par
- else:
- return self.parameter
- return None
- class Translation(NamedNode):
- """Represents a Translation element of the XML document type"""
- def __init__(self, attr):
- super(Translation, self).__init__(attr)
- self.template = None
- self.target = None
- self.properties = ''
- self.is_active = 1
- def set_target(self, target):
- self.target = target
- class Platform(NamedNode):
- """Represents a Platform element of the XML document type"""
- def __init__(self, attr):
- super(Platform, self).__init__(attr)
- self.parameter = []
- self.translation = []
- class Model(NamedNode):
- """Represents a Parameter element of the XML document type"""
- def __init__(self, attr):
- super(Model, self).__init__(attr)
- self.parameter = []
- class Parameter(NamedNode):
- """Represents a Parameter element of the XML document type"""
- def __init__(self, attr):
- super(Parameter, self).__init__(attr)
- self.type = None
- self.value = None
- class Configuration(NamedNode, xml.sax.handler.ContentHandler):
- """Represents a Parameter element (which is the root element) of the XML document type"""
- def __init__(self):
- self.translation = []
- self.platform = []
- self.model = []
- self.xml_file = None
- self.active_platform = None
- self.__stack = []
- self.__types = {'Translation': Translation,
- 'Platform': Platform,
- 'Model': Model,
- 'Parameter': Parameter}
- def xml(self, level=0):
- return '<?xml version="1.0"?>\n\n' \
- + super(Configuration, self).xml(level)
- def startElement(self, tag, attributes):
- info("Processing XML element '" + str(tag) + "'", level=3)
- if self.__stack:
- if tag in self.__types:
- info("Adding NamedNode for element '" + str(tag) + "'", level=3)
- self.__stack.append(self.__types[tag](attributes))
- else:
- info("Adding TextNode for element '" + str(tag) + "'", level=3)
- self.__stack.append(TextNode())
- else:
- self.__stack.append(self)
- def characters(self, content):
- if isinstance(self.__stack[-1], TextNode):
- self.__stack[-1].add_text(content)
- def endElement(self, tag):
- element = self.__stack.pop()
- if self.__stack:
- if isinstance(element, TextNode):
- self.__stack[-1].__dict__[tag.lower()] = element.text
- else:
- self.__stack[-1].__dict__[tag.lower()].append(element)
- def parse(self, file):
- info("Parsing XML file '%s'" % file)
- # A short helper function for xml.etree.ElementInclude.include
- # that parses include files and catches parse errors
- def include_loader(href, parse, encoding=None):
- if parse != "xml":
- error("Only XML includes allowed in xi:include! (see file '%s')" % href)
- try:
- with open(href) as file:
- data = ElementTree.parse(file).getroot()
- except IOError as e:
- error("Can't open include file '%s' for parsing: %s" % (href, e))
- except ElementTree.ParseError as e:
- error("XML parse error in include file '%s': %s" % (href, e))
- return data
- # First parsing stage with xml.etree for include processing
- try:
- tree = ElementTree.parse(file)
- except IOError:
- error("Can't open file '%s' for parsing" % file)
- except ElementTree.ParseError as e:
- error("XML parse error in file '%s': %s" % (file, e))
- # Process XML include files
- tree_root = tree.getroot()
- ElementInclude.include(tree_root, loader=include_loader)
- # Second parsing stage with xml.sax to fill data structures
- # Since errors are catched in the first parsing stage, we assume
- # everything is fine here.
- xml.sax.parseString(ElementTree.tostring(tree_root, encoding="UTF-8"),self)
- info("Finished parsing '%s': Translation: %d Platform: %d Model: %d" % (
- file, len(self.translation), len(self.platform), len(self.model)))
- self.xml_file = file
- def translate(self, translation):
- rpm_ops = {
- 'ADD': operator.add,
- 'SUB': operator.sub,
- 'MUL': operator.mul,
- 'DIV': operator.truediv,
- 'POW': operator.pow,
- 'MOD': operator.mod
- }
- subst_re = re.compile(r"\[\[\[(?P<var>[a-zA-Z0-9_:,]+)\]\]\]")
- var_re = re.compile(r"^(\w{3}):([a-zA-Z0-9_]+):([a-zA-Z0-9_]+)$")
- def parse_var(string):
- # Shortcut for the 'prefixdir' parameter in template file
- if string.lower() == 'plt:active:prefixdir':
- return targetPrefixDir if targetPrefixDir else '[[[' + string + ']]]'
- while True:
- match = var_re.search(string)
- if not match:
- break
- (category, component, parameter) = match.groups()
- if category.lower() == 'plt' and component.lower() == 'active':
- component = self.active_platform
- try:
- string = getattr(self, category.lower())(
- component).par(parameter).value
- except BaseException:
- warning(
- "Unable to process '%s' (Line %d in '%s')" %
- (string, line_number, template))
- return '[[[' + string + ']]]'
- return string
- def parse_rpn(string):
- stack = []
- for token in string.split(','):
- token = parse_var(token)
- if not token:
- info(
- "Substitute expression with empty string (Line %d in '%s')" %
- (line_number, template))
- try:
- result = int(token)
- except ValueError:
- try:
- result = float(token)
- except ValueError:
- if token in list(rpm_ops.keys()):
- try:
- result = rpm_ops[token](
- stack.pop(-2), stack.pop())
- except IndexError:
- warning(
- "Too few arguments to execute '%s' (Line %d in '%s')" %
- (token, line_number, template))
- return "[[[" + string + "]]]"
- except BaseException:
- warning(
- "Unable to execute '%s' (Line %d in '%s')" %
- (token, line_number, template))
- return "[[[" + string + "]]]"
- else:
- result = token
- stack.append(result)
- if len(stack) > 1:
- warning(
- "Too many operands in '%s' (Line %d in '%s')" %
- (string, line_number, template))
- return "[[[" + string + "]]]"
- return result
- template = translation.template
- target = translation.target.strip()
- info("Translate: '%s' --> '%s'" % (template, target))
- try:
- input = open(template, 'r')
- except IOError:
- error("Can't open template file '%s' for reading" % template)
- if target:
- if targetPrefixDir:
- target = os.path.join(targetPrefixDir, target)
- path = os.path.dirname(target)
- try:
- os.makedirs(path)
- info("Created target prefix directory '%s'" % path)
- except OSError as exc:
- if exc.errno == errno.EEXIST and os.path.isdir(path):
- info(
- "Target prefix directory '%s' exists already" %
- (path))
- else:
- error(
- "Could not create target prefix directory '%s'" %
- (path))
- try:
- output = open(target, 'w')
- except IOError:
- error("Can't open target file '%s' for writing" % target)
- if 'executable' in translation.properties.split(','):
- os.chmod(target, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH |
- stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH |
- stat.S_IWUSR)
- else:
- output = sys.stdout
- line_number = 0
- for line in input:
- line_number += 1
- ptr = 0
- buf = ''
- for match in subst_re.finditer(line):
- buf += line[ptr:match.start()]
- var = match.groupdict()['var']
- try:
- buf += str(parse_rpn(var))
- except UnicodeEncodeError as e:
- error('Invalid character in XML file!\n'
- '*EE* Look up the \\uXXXX character code from the following message:\n'
- '*EE* %s' % str(e))
- ptr = match.end()
- buf += line[ptr:]
- output.write(buf)
- input.close()
- if target:
- output.close()
- def translate_all(self):
- for t in self.translation:
- self.translate(t)
- if self.active_platform:
- for t in self.plt(self.active_platform).translation:
- self.translate(t)
- def start_gui(cfg):
- import tkinter
- import tkinter.filedialog
- import tkinter.messagebox
- class VerticalScrolledFrame(tkinter.Frame):
- """A pure Tkinter scrollable frame that actually works!
- * Use the 'interior' attribute to place widgets inside the scrollable frame
- * Construct and pack/place/grid normally
- * This frame only allows vertical scrolling
- http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame
- """
- def __init__(self, parent, *args, **kw):
- tkinter.Frame.__init__(self, parent, *args, **kw)
- # create a canvas object and a vertical scrollbar for scrolling it
- vscrollbar = tkinter.Scrollbar(self, orient=tkinter.VERTICAL)
- vscrollbar.pack(
- fill=tkinter.Y,
- side=tkinter.RIGHT,
- expand=tkinter.FALSE)
- canvas = tkinter.Canvas(self, bd=0, highlightthickness=0,
- yscrollcommand=vscrollbar.set)
- canvas.pack(
- side=tkinter.LEFT,
- fill=tkinter.BOTH,
- expand=tkinter.TRUE)
- vscrollbar.config(command=canvas.yview)
- # reset the view
- canvas.xview_moveto(0)
- canvas.yview_moveto(0)
- # create a frame inside the canvas which will be scrolled with it
- self.interior = interior = tkinter.Frame(canvas)
- interior_id = canvas.create_window(0, 0, window=interior,
- anchor=tkinter.NW)
- # track changes to the canvas and frame width and sync them,
- # also updating the scrollbar
- def _configure_interior(event):
- # update the scrollbars to match the size of the inner frame
- size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
- canvas.config(scrollregion="0 0 %s %s" % size)
- if interior.winfo_reqwidth() != canvas.winfo_width():
- # update the canvas's width to fit the inner frame
- canvas.config(width=interior.winfo_reqwidth())
- interior.bind('<Configure>', _configure_interior)
- def _configure_canvas(event):
- if interior.winfo_reqwidth() != canvas.winfo_width():
- # update the inner frame's width to fill the canvas
- canvas.itemconfigure(
- interior_id, width=canvas.winfo_width())
- canvas.bind('<Configure>', _configure_canvas)
- return
- class GUI(tkinter.Tk):
- def __init__(self, cfg):
- tkinter.Tk.__init__(self)
- self.columnconfigure(1, weight=1)
- self.rowconfigure(0, pad=10)
- self.rowconfigure(2, weight=1)
- self.__cfg = cfg
- self.__var_list = []
- self.__var_dict = {}
- for t in self.__cfg.translation + \
- [t for p in self.__cfg.platform for t in p.translation]:
- v = tkinter.IntVar()
- v.set(1)
- v.trace(
- 'w', lambda n, i, m, t=t: t.set(
- 'is_active', int(
- self.globalgetvar(n))))
- self.__add_var(v, t)
- self.__active_component = tkinter.StringVar()
- self.__status = tkinter.StringVar()
- self.__component_frame = None
- self.__parameter_frame = None
- self.__translation_frame = None
- self.__init_top_panel()
- self.__init_status_panel()
- self.__init_main_panel()
- self.grid_propagate(flag=0)
- self.__set_status(
- "Welcome to EC-CONF's graphical user interface!",
- time=3000)
- def __add_var(self, var, obj=None):
- self.__var_list.append(var)
- if obj:
- self.__var_dict[obj] = len(self.__var_list) - 1
- def __set_status(self, message, time=8000):
- try:
- self.after_cancel(self.__status_after_id)
- except BaseException:
- pass
- self.__default_status_message = 'Basic usage: SELECT XML database' \
- ' and template/target files, CONFIGURE parameters, and CREATE' \
- ' the configuration files.'
- self.__status.set(message)
- self.__status_after_id = self.after(
- time, self.__status.set, self.__default_status_message)
- def __init_top_panel(self):
- w = tkinter.Label(text='The active platform is:')
- w.grid(row=0, column=0)
- if not self.__cfg.active_platform:
- self.__cfg.active_platform = self.__cfg.platform[0].name
- v = tkinter.StringVar()
- v.set(self.__cfg.active_platform)
- v.trace(
- 'w',
- lambda n, i, m: self.__set_status(
- "Active platform changed to '"
- + self.__cfg.active_platform
- + "'"))
- v.trace(
- 'w',
- lambda n, i, m: self.__fill_parameter_frame(
- self.__parameter_frame))
- v.trace(
- 'w',
- lambda n, i, m: self.__fill_component_frame(
- self.__component_frame))
- v.trace(
- 'w',
- lambda n, i, m: self.__fill_translation_frame(
- self.__translation_frame))
- v.trace('w', lambda n, i, m: self.__cfg.set(
- 'active_platform', self.globalgetvar(n)))
- self.__add_var(v)
- w = tkinter.OptionMenu(None, v, *
- [p.name for p in self.__cfg.platform])
- w.grid(row=0, column=1, sticky='W', padx=8)
- w = tkinter.Button(text='Select', width=10, height=2, bg='tan')
- w['command'] = self.__do_select
- w.grid(row=0, column=2, padx=8)
- w = tkinter.Button(text='Configure', width=10, height=2, bg='tan')
- w['command'] = self.__do_configure
- w.grid(row=0, column=3, padx=8)
- w = tkinter.Button(
- text='Create!',
- width=10,
- height=2,
- bg='darkgrey',
- fg='white')
- w['command'] = self.__do_create
- w.grid(row=0, column=4, padx=8)
- def __init_status_panel(self):
- w = tkinter.Label(
- textvariable=self.__status,
- height=2,
- bg='orange')
- w.grid(row=1, column=0, columnspan=5, sticky='EW', pady=5)
- def __init_main_panel(self):
- self.__init_select_panel()
- self.__init_configure_panel()
- self.__select_panel.grid_remove()
- self.__configure_panel.grid_remove()
- self.__active_main_panel = self.__select_panel
- self.__active_main_panel.grid()
- def __init_select_panel(self):
- self.__select_panel = tkinter.Frame()
- self.__select_panel.grid(
- row=2, column=0, columnspan=5, sticky='NEWS')
- self.__select_panel.columnconfigure(0, weight=1)
- self.__select_panel.rowconfigure(2, weight=1)
- f = tkinter.LabelFrame(
- self.__select_panel,
- text='XML database file')
- f.grid(sticky='NEWS')
- f.columnconfigure(1, weight=1)
- w = tkinter.Label(f, text='The current file is: ')
- w.grid(row=0, column=0, sticky='W')
- v = tkinter.StringVar()
- v.set(self.__cfg.xml_file)
- v.trace(
- 'w', lambda n, i, m: self.__cfg.set(
- 'xml_file', self.globalgetvar(n)))
- self.__add_var(v, 'xml_file')
- w = tkinter.Label(f, textvariable=v, bg='darkgrey', fg='white')
- w.grid(row=0, column=1, sticky='W')
- w = tkinter.Button(f, text='Save as', width=8)
- w['command'] = lambda: self.__save_as_xml_file()
- w.grid(row=0, column=2, sticky='E', padx=4, pady=5)
- w = tkinter.Button(f, text='Save', width=8)
- w['command'] = lambda: self.__save_xml_file()
- w.grid(row=0, column=3, sticky='E', padx=4, pady=5)
- tkinter.Frame(self.__select_panel).grid(pady=5)
- self.__translation_frame = tkinter.LabelFrame(
- self.__select_panel, text='Templates and Targets')
- self.__translation_frame.grid(sticky='NEWS')
- self.__translation_frame.columnconfigure(1, weight=1)
- self.__translation_frame.columnconfigure(3, weight=9)
- self.__fill_translation_frame(self.__translation_frame)
- def __init_configure_panel(self):
- self.__configure_panel = tkinter.Frame()
- self.__configure_panel.grid(
- row=2, column=0, columnspan=5, sticky='NEWS')
- self.__configure_panel.rowconfigure(0, weight=1)
- self.__configure_panel.columnconfigure(2, weight=1)
- # Component frame
- self.__component_frame = tkinter.LabelFrame(
- self.__configure_panel, text='Configurable components')
- self.__component_frame.grid(sticky='NEWS')
- self.__fill_component_frame(self.__component_frame)
- # Spacer frame
- f = tkinter.Frame(self.__configure_panel)
- f.grid(row=0, column=1, padx=2)
- # Parameter frame
- f = tkinter.LabelFrame(
- self.__configure_panel,
- text='Configuration parameters')
- f.grid(row=0, column=2, sticky='NEWS')
- f = VerticalScrolledFrame(f)
- f.pack(fill=tkinter.BOTH, expand=tkinter.TRUE)
- self.__parameter_frame = f.interior
- self.__parameter_frame.columnconfigure(2, weight=1)
- self.__fill_parameter_frame(self.__parameter_frame)
- def __fill_translation_frame(self, frame):
- for w in list(frame.children.values()):
- w.destroy()
- v = tkinter.IntVar()
- v.set(1)
- v.trace('w', lambda n,
- i,
- m: [self.__var_list[self.__var_dict[t]].set(self.globalgetvar(n))
- for t in self.__cfg.translation +
- self.__cfg.plt(self.__cfg.active_platform).translation])
- self.__add_var(v)
- w = tkinter.Checkbutton(
- frame, text='Activate/deactivate all', variable=v)
- w.grid(row=0, column=0, sticky='W', pady=5)
- r = 1
- for t in self.__cfg.translation + \
- self.__cfg.plt(self.__cfg.active_platform).translation:
- w = tkinter.Checkbutton(
- frame, text=t.description, variable=self.__var_list[self.__var_dict[t]])
- w.grid(row=r, column=0, sticky='W', pady=5)
- w = tkinter.Label(
- frame,
- text=t.template,
- bg='darkgrey',
- fg='white')
- w.grid(row=r, column=1, sticky='E')
- w = tkinter.Label(frame, text=' --> ')
- w.grid(row=r, column=2)
- v = tkinter.StringVar()
- v.set(t.target)
- v.trace(
- 'w', lambda n, i, m, t=t: t.set_target(
- self.globalgetvar(n)))
- self.__add_var(v)
- w = tkinter.Entry(frame, textvariable=v)
- w.grid(row=r, column=3, sticky='EW')
- r += 1
- def __fill_component_frame(self, frame):
- for w in list(frame.children.values()):
- w.destroy()
- if self.__cfg.active_platform:
- self.__active_component.set(self.__cfg.active_platform)
- w = tkinter.Label(frame, text='Active platform')
- w.pack(anchor='w')
- c = self.__cfg.plt(self.__cfg.active_platform)
- w = tkinter.Radiobutton(
- frame,
- text=c.name,
- variable=self.__active_component,
- value=c.name)
- w['command'] = lambda: self.__fill_parameter_frame(
- self.__parameter_frame)
- w.pack(anchor='w', pady=5)
- if self.__cfg.model:
- if not self.__active_component.get():
- self.set(self.__cfg.model[0].name)
- w = tkinter.Label(frame, text='Configurable models')
- w.pack(anchor='w')
- for c in self.__cfg.model:
- w = tkinter.Radiobutton(
- frame, text=c.name, variable=self.__active_component, value=c.name)
- w['command'] = lambda: self.__fill_parameter_frame(
- self.__parameter_frame)
- w.pack(anchor='w', pady=5)
- def __fill_parameter_frame(self, frame):
- for w in list(frame.children.values()):
- w.destroy()
- for (name, component) in [(c.name, c)
- for c in self.__cfg.platform + self.__cfg.model]:
- if self.__active_component.get() == name:
- break
- r = 0
- for p in component.par():
- w = tkinter.Label(
- frame, text=p.description, anchor="w", width=35)
- w.grid(row=r, column=0, sticky='W')
- w = tkinter.Label(frame, text='[' + str(p.name) + ']')
- w.grid(row=r, column=1, sticky='W', padx=20)
- v = tkinter.StringVar()
- v.set(p.value)
- v.trace(
- 'w', lambda n, i, m, p=p: p.set(
- 'value', self.globalgetvar(n)))
- self.__add_var(v)
- w = tkinter.Entry(frame, textvariable=v)
- w.grid(row=r, column=2, sticky='EW')
- r += 1
- self.__set_status(
- 'Configure parameters for component \'' +
- self.__active_component.get() +
- '\'')
- def __do_select(self):
- self.__active_main_panel.grid_remove()
- self.__active_main_panel = self.__select_panel
- self.__active_main_panel.grid()
- self.__set_status(
- 'Select the XML data base file and active translations in the panel below.')
- def __do_configure(self):
- self.__active_main_panel.grid_remove()
- self.__active_main_panel = self.__configure_panel
- self.__active_main_panel.grid()
- self.__set_status('Configure the configuration parameters for the'
- ' available components in the panel below.')
- def __do_create(self):
- fw = []
- for t in self.__cfg.translation + \
- self.__cfg.plt(self.__cfg.active_platform).translation:
- if t.is_active:
- self.__cfg.translate(t)
- fw.append(t.target)
- if fw:
- msg = 'Active target files written: ' + fw.pop()
- while fw:
- msg += ', ' + fw.pop()
- else:
- msg = 'No targets where written'
- self.__set_status(msg)
- def __save_as_xml_file(self):
- f = tkinter.filedialog.asksaveasfilename(
- title='Select a file name for saving:', filetypes=[
- ('XML files', '*.xml'), ('All files', '*')])
- if f:
- try:
- self.__var_list[self.__var_dict['xml_file']].set(
- os.path.relpath(f))
- except AttributeError:
- self.__var_list[self.__var_dict['xml_file']].set(
- os.path.realpath(f))
- self.__save_xml_file()
- else:
- self.__set_status("Current XML file NOT saved")
- def __save_xml_file(self):
- if os.path.isfile(self.__cfg.xml_file):
- msg = "The file '" + self.__cfg.xml_file + \
- "' exists. Do you want to replace it?"
- if not tkinter.messagebox.askyesno('Save XML file', msg):
- return
- try:
- f = open(self.__cfg.xml_file, 'w')
- except IOError:
- msg = "The file '" + self.__cfg.xml_file + "' could not be opened for writing"
- tkinter.messagebox.showerror('Save XML file', msg)
- self.__set_status("XML database NOT saved")
- return
- f.write(self.__cfg.xml())
- f.close()
- self.__set_status(
- "XML database saved to file '" +
- self.__cfg.xml_file +
- "'")
- root = GUI(cfg)
- root.title('ec-conf GUI')
- min_window_width = min(900, int(0.9 * root.winfo_screenwidth()))
- min_window_height = min(800, int(0.9 * root.winfo_screenheight()))
- root.minsize(min_window_width, min_window_height)
- root.resizable()
- root.mainloop()
- if __name__ == "__main__":
- # Try to get command line options and arguments
- try:
- opts, args = getopt.getopt(sys.argv[1:],
- "hp:gd:o:xlvwe",
- ["help", "platform=", "gui", "prefix=",
- "overwrite-parameter=",
- "write-xml", "list-platforms",
- "verbose", "no-warning", "error-on-warning"])
- except getopt.GetoptError:
- usage(os.path.split(sys.argv[0])[-1])
- # Default values, to be overwritten by command line options
- WARNING = True
- ERROR_ON_WARNING = False
- VERBOSE = 0
- writeXML = False
- listPlatforms = False
- wantGUI = False
- platform = None
- targetPrefixDir = None
- overwriteParameters = []
- # Parse command line options
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(os.path.split(sys.argv[0])[-1])
- elif opt in ('-p', '--platform'):
- platform = arg
- elif opt in ('-g', '--gui'):
- wantGUI = True
- elif opt in ('-d', '--prefix'):
- targetPrefixDir = arg
- elif opt in ('-o', '--overwrite-parameter'):
- overwriteParameters.append(arg)
- elif opt in ('-x', '--write-xml'):
- writeXML = True
- elif opt in ('-l', '--list-platforms'):
- listPlatforms = True
- elif opt in ('-v', '--verbose'):
- VERBOSE += 1
- elif opt in ('-w', '--no-warning'):
- WARNING = False
- elif opt in ('-e', '--error-on-warning'):
- ERROR_ON_WARNING = True
- # The XML file is all that should be left on the command line
- if len(args) != 1:
- usage(os.path.split(sys.argv[0])[-1])
- # Create the Configuration object and fill the data structures by parsing
- # the XML file
- cfg = Configuration()
- cfg.parse(args[0])
- info(args[0])
- info(cfg.parse(args[0]))
- info(platform)
- # If a platform was given on the command line, try to set it
- if platform:
- info(cfg.plt(platform))
- if cfg.plt(platform):
- cfg.active_platform = platform
- else:
- error(
- "Platform '%s' not defined in the configuration file '%s'" %
- (platform, args[0]))
- elif not (wantGUI or listPlatforms):
- warning("No active platform given")
- # Overwrite parameters given explicitely on the command line
- for arg in overwriteParameters:
- # split the name=value pair but make sure additional '=' are preserved
- name = arg.split('=')[0]
- value = '='.join(arg.split('=')[1:])
- # Maybe we want to allow overwriting with empty values?!
- # if so, remove the following if block
- if not value:
- warning("Parameter '%s' in --overwrite-parameter has no value" % name)
- continue
- try:
- (category, component, parameter) = name.split(':')
- except ValueError:
- warning(
- "Malformed parameter name given to --overwrite-parameter: '%s'" % name)
- continue
- if category.lower() == 'plt' and component.lower() == 'active':
- component = cfg.active_platform
- try:
- getattr(cfg, category.lower())(
- component).par(parameter).value = value
- info("Overwriting parameter '%s' with value '%s'" % (name, value))
- except AttributeError:
- warning(
- "Non-existing parameter name given to --overwrite-parameter: '%s'" % name)
- continue
- # Select activity to be done according to the command line options
- # Default is to translate all Translations in the Configuration
- if wantGUI:
- info("Starting GUI")
- start_gui(cfg)
- elif listPlatforms:
- if cfg.plt():
- print('\n'.join([p.name for p in cfg.plt()]))
- else:
- warning("No platforms defined in XML file")
- elif writeXML:
- sys.stdout.write(cfg.xml())
- else:
- cfg.translate_all()
|