removed some debugging prints no longer needed
[pyvconv.git] / commands.py
blob1869d96391cef49ff9b6a8182022ba77cc2cd618
1 # Pyvconv - A simple frontend for ffmpeg/mencoder
2 # Copyright (C) 2008, Kristian Rumberg (kristianrumberg@gmail.com)
4 # Permission to use, copy, modify, and/or distribute this software for any
5 # purpose with or without fee is hereby granted, provided that the above
6 # copyright notice and this permission notice appear in all copies.
8 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 import os
17 import libxml2
18 import re
20 class Error(Exception):
21 def __init__(self, value):
22 Exception.__init__(self)
23 self.value = value
24 def __str__(self):
25 return repr(self.value)
27 class Variable:
28 def __init__(self, namestr, defaultstr, exprstr = None):
29 self.namestr = namestr
30 self.defaultstr = defaultstr
31 self.exprstr = exprstr
33 def __str__(self):
34 return self.namestr
36 def has_value(self):
37 return self.defaultstr != None
39 def get_value(self):
40 if self.defaultstr == None:
41 raise Error("Error: Trying to eval variable " + self.namestr + " with no value")
42 return self.defaultstr
44 class OptionalSetting:
45 def __init__(self, namestr, exprstr):
46 self.namestr = namestr
47 self.exprstr = exprstr
49 def get_name(self):
50 return self.namestr
52 def get_value(self, var_list):
53 instr = self.exprstr
54 for var in var_list:
55 if var_list[var].has_value():
56 p = re.compile( "\$\{" + var + "\}")
57 instr = p.sub( var_list[var].get_value(), instr)
58 if instr.find("$") != -1:
59 instr = "" # if not all variables were found, return empty option
60 return instr
62 class Command:
63 def __init__(self, namestr, callstr, extstr, var_list, optset_list):
64 self.namestr = namestr
65 self.callstr = callstr
66 self.extstr = extstr
67 self.var_list = var_list
68 self.optset_list = optset_list
70 def get_name(self):
71 return self.namestr
73 def get_outfile_extension(self):
74 return self.extstr
76 def put_var(self, var):
77 self.var_list[str(var)] = var
79 def get_vars(self):
80 return self.var_list
82 def __str__(self):
83 instr = self.callstr
85 p = re.compile("\$\[(\w+)\]")
86 for o in p.findall(instr):
87 if o not in self.optset_list:
88 raise Error("Error: Optional variable not defined")
89 instr = p.sub(self.optset_list[o].get_value(self.var_list), instr)
91 p = re.compile("\$\{(\w+)\}")
92 for o in p.findall(instr):
93 if o not in self.var_list:
94 raise Error("Error: Variable \"" + o + "\" has not been assigned")
95 val = self.var_list[o].get_value()
96 instr = instr.replace("${" + o + "}", val)
98 if instr.find("$") != -1:
99 raise Error("Error: all variables were not expanded")
100 return instr
102 class CommandList:
103 def __init__(self):
104 self.cmdcall_dict = {}
105 self._read_config()
107 def _read_properties(self, propnode, mand_propnames, opt_propnames = []):
108 propdict = {}
110 for p in propnode:
111 if p.name in mand_propnames:
112 propdict[p.name] = str(p.content)
113 elif p.name != "text" and p.name not in opt_propnames:
114 raise Error("Error parsing XML: only name and call are accepted properties in the element command, found " + str(p.name))
116 if len(mand_propnames) != len(propdict.keys()):
117 raise Error("Error parsing XML: must supply both name and call in element command")
119 for p in propnode:
120 if p.name in opt_propnames:
121 propdict[p.name] = str(p.content)
122 elif p.name != "text" and p.name not in mand_propnames:
123 raise Error("Error parsing XML: only name and call are accepted properties in the element command, found " + str(p.name))
125 return propdict
127 def _get_config_path(self):
128 homeconf = os.path.expanduser("~") + "/.pyvconv/commands.xml"
129 if os.path.isfile("commands.xml"):
130 return "commands.xml"
131 elif os.path.isfile(homeconf):
132 return homeconf
133 else:
134 raise Error("Error: No config found")
136 def _cmd_program_found_in_path(self, programstr):
137 if False == self.program_boolexists_dict.has_key(programstr):
139 if not os.environ.has_key('PATH') or os.environ['PATH']=='':
140 p = os.defpath
141 else:
142 p = os.environ['PATH']
144 self.program_boolexists_dict[programstr] = False # not found yet, so set to false
146 pathlist = p.split (os.pathsep)
147 for path in pathlist:
148 f = os.path.join(path, programstr)
149 if os.access(f, os.X_OK):
150 self.program_boolexists_dict[programstr] = True
152 return self.program_boolexists_dict[programstr]
154 def _read_config(self):
155 doc = libxml2.parseFile(self._get_config_path())
156 cmd_xmllist = doc.xpathEval( '//command')
158 self.program_boolexists_dict = {}
160 # read all commands from XML description
161 for cmdnode in cmd_xmllist:
162 if cmdnode.type == "element" and cmdnode.name == "command":
164 var_list = {}
165 optset_list = {}
167 if cmdnode.children:
168 for varsetnode in cmdnode.children:
169 if varsetnode.type == "element" and varsetnode.name == "variable":
170 props = self._read_properties(varsetnode.properties, ["name", "expr"], ["default"])
171 defprop = None
172 if "default" in props:
173 defprop = props["default"]
174 var_list[props["name"]] = Variable(props["name"], defprop, props["expr"])
176 elif varsetnode.type == "element" and varsetnode.name == "optionalsetting":
177 props = self._read_properties(varsetnode.properties, ["name", "expr"])
178 optset_list[props["name"]] = OptionalSetting(props["name"], props["expr"])
180 elif varsetnode.name != "text":
181 raise Error("Error parsing XML: only variable and optionalsetting elements allowed in command")
183 props = self._read_properties(cmdnode.properties, ["name", "call", "ext"])
185 if self._cmd_program_found_in_path( props["call"].split()[0] ):
186 self.cmdcall_dict[props["name"]] = Command(props["name"], props["call"], props["ext"], var_list, optset_list)
188 else:
189 raise Error("Error parsing XML: only command elements are supported")
191 def __iter__(self):
192 return self.cmdcall_dict.values().__iter__()
194 def __len__(self):
195 return len(self.cmdcall_dict)
197 def __getitem__(self, name):
198 return self.cmdcall_dict[name]