class Trigger(object): """Match/action triggers for a server. All objects in this class are created by Triggers objects. """ def __init__(self, parent, name): # Parent is the Triggers object that created this one. # name is a unique name for this trigger. self.parent = parent self.name = name self.matches = OrderedDict() self.actions = OrderedDict() def __hash__(self): """For sets. """ return hash(self.name) def __eq__(self, other): """Makes comparison for equality work reasonably. Action and match lists must match; parents need not. """ return ( self.name == other.name and self.matches == other.matches and self.actions == other.actions ) def __ne__(self, other): """Makes comparison for equality work reasonably. """ return not self.__eq__(other) def addMatch(self, matchSpec, matchName=""): """Add one match to this trigger. matchSpec should be a ParmLine where the event and parameter values are regexps. matchName can name the match arbitrarily. """ if not matchName: matchName = "(match%03d)" % (len(self.matches)+1) match = Struct() match.name = matchName match.value = matchSpec # This allows replacements by exact name match. self.matches[matchName] = match def addAction(self, actionSpec, actionName=""): """Add one action to this trigger. actionSpec should be an action to perform. actionName can name the action arbitrarily. """ if not actionName: actionName = "(action%03d)" % (len(self.actions)+1) action = Struct() action.name = actionName action.value = actionSpec # This allows replacements by exact name match. self.actions[actionName] = action def apply(self, parmline): """Apply actions if and only if there is a match. """ for match in self.matches.values(): if not self._isMatch(match, parmline): continue uinfo = "" if parmline.parms.get("userid"): uinfo = " (userid %s)" % (parmline.parms.userid) # Use errorFromEvent instead of outputFromEvent so it's not # silent if the server is marked silent. self.parent.server.errorFromEvent("%s triggers %s %s%s" % ( parmline.event, self.name, match.name or match.value, uinfo )) for action in self.actions.values(): actionData = Struct() actionData.parmline = parmline actionData.match = match actionData.action = action self._doAction(actionData) return True return False def _isMatch(self, match, eventline): """Return True on a match. match is a name,value struct where value is a ParmLine where the event and parameter values are regexps. eventline is an actual event line as the name implies. Matching is forced to be case-insensitive. Matches also implicitly start with ^ and end with $, so they must match the entire event or parameter value. Special cases of match.value: nodecode: True if eventline contains nulls or illegal UTF-8 sequences. line match=...: A regular expression match against the whole line. """ m = match.value if m.event.lower() == "nodecode": # Check for lines that will confuse TeamTalk 4.3.0.1891 and older. if chr(0) in eventline.initLine: return True try: eventline.initLine.decode("utf-8") except UnicodeDecodeError: return True return False # Whole-line matches. # Format: line match=<re>. if m.event.lower() == "line" and m.parms.get("match"): regexp = m.parms["match"] if re.match('^'+regexp+'$', eventline.initLine, re.IGNORECASE): return True return False # Normal RE event match and parms. if not re.match('^'+m.event+'$', eventline.event, re.IGNORECASE): return False # matchKey and matchRE are keys and regexps to match against # event parameter values. for matchKey in m.parms: matchRE = m.parms[matchKey] if matchKey == "address": # This one is special/magical: # It tries to match against any ".*addr" eventline key, # and it uses special logic, not regexp logic, to match. # First collect the address keys, e.g., ipaddr/udpaddr. addrkeys = filter(lambda k: k.endswith("addr"), eventline.parms.keys()) # Then check each for a match. matched = False for ak in addrkeys: addr = eventline.parms[ak] if self._matchAddress(matchRE, addr): matched = True break if not matched: return False # Not a "magical" address match. elif not eventline.parms.has_key(matchKey): return False elif not re.match('^'+matchRE+'$', eventline.parms[matchKey], re.IGNORECASE): return False return True def _matchAddress(self, matchval, addr): """Indicate if the given address matches matchval. Matchval should be a full address or the first part of one. Addr should be an event parameter value. Helper for isMatch(). """ # Remove any extra brackets/port, often found on UDP address values. if "[" in addr and "]" in addr: addr = re.findall(r'^\[(.*?)]', addr)[0] # Allow IPV4 and IPV6 addresses with the same content to match. if not matchval.startswith(":"): addr = re.sub(r'^(?i)::ffff:', '', addr) # Remove any trailing port from an IPV4 address. addr = re.sub(r':\d+$', '', addr) # If this is a partial address, ad a dott to avoid partial number matches. if len(matchval.split(".")) < 4: matchval += "." # And finally do a left-side simple match. return addr.startswith(matchval) def _doAction(self, actionData): """Perform one action. actionData properties: eventline: The ParmLine for the event that fired the trigger. match: The name,value struct for the match that matched this event. match.value is the ParmLine that matched this event. action: The name,value struct for the action to perform. action.value is the actual command to perform. match.name and action.name may be null. Substitutions: A string in an action like %(userid) becomes something like userid="123" in the actually sent command. If the action begins with "send," it is not sent through the command processor but sent directly to this server, after any substitutions. If the command begins with "say," the rest of the line is spoken if possible. """ a = actionData.action.value parmline = actionData.parmline # Include any parameters from the matched line. # We do this manually rather than with % so we can control # what happens when the author asks for something that doesn't exist. # We throw an error in such a case. ms = lambda m: self._doSubs(m, parmline.parms) a = re.sub(r'%\((\S+?)\)', ms, a) sendFunc = None if a.lower().startswith("send "): sendFunc = self.parent.server.send elif a.lower().startswith("sendwithwait "): sendFunc = self.parent.server.sendWithWait if sendFunc: # Remove the "send[WithWait]" part, then send it. a = a.split(None, 1)[1] sendFunc(ParmLine(a)) return if a.lower().startswith("say "): # Remove the "say" part, then say it. a = a.split(None, 1)[1] mycmd_say(a) return # Make the action apply to the right server. a = "server %s %s" % (self.parent.server.shortname, a) # Run the command as if typed by the user. self.parent.runCommand(a) def _doSubs(self, m, parms): """Do substitutions like for %(userid) in actions. """ k = m.groups()[0] excludeParmName = False if k.startswith("!"): excludeParmName = True k = k[1:] val = parms[k] if not excludeParmName: val = '%s="%s"' % (k, val) return val
class comboBox(QComboBox,widgetState): def __init__(self,widget,label=None, displayLabel=True, items=None, editable=False, orientation='horizontal',callback = None,**kwargs): kwargs.setdefault('includeInReports', True) kwargs.setdefault('sizePolicy', QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) widgetState.__init__(self,widget,label,**kwargs) QComboBox.__init__(self,self.controlArea) if displayLabel: self.hb = widgetBox(self.controlArea,orientation=orientation) lb = widgetLabel(self.hb, label) self.hb.layout().addWidget(self) self.hasLabel = True self.hb.layout().setAlignment(lb,Qt.AlignRight) lb.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) else: self.controlArea.layout().addWidget(self) self.hasLabel = False self.label = label self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) self.items = OrderedDict() self.setEditable(editable) if items: self.addItems(items) if callback: QObject.connect(self, SIGNAL('activated(int)'), callback) def getSettings(self): """Standard getSettings""" r = {'items':self.items, 'current':self.currentIndex()} return r def loadSettings(self,data): """Standard loadSettings""" # print _('in comboBox load') # print data self.update(data.get('items', [])) if data.get('current', None) != None: self.setCurrentIndex(data['current']) def currentId(self): """Returns the current ID""" try: return self.items.keys()[self.currentIndex()] except: return None def currentItem(self): """Returns the current key value pair""" return {self.items.keys()[self.currentIndex()]:self.items.values()[self.currentIndex()]} def setCurrentId(self,id): """Sets the current ID, the ID's value will apear in the comboBox""" try: self.setCurrentIndex(self.items.keys().index(id)) except: pass def addItems(self,items): """Adds items to the comboBox, new items will appear after old ones""" if type(items) in [dict,OrderedDict]: for k,v in items.items(): self.addItem(k,v) elif type(items) in [list]: if len(items) > 0 and type(items[0]) is tuple: for k,v in items: self.addItem(k,v) else: for v in items: self.addItem(v,v) # redRLog.log(redRLog.REDRCORE,redRLog.DEBUG,_('In listBox should not use list')) else: raise Exception(_('In comboBox, addItems takes a list, dict or OrderedDict')) def update(self, items): """Clears the comboBox and adds new items, sets the current ID to the previously selected ID if found in the items""" current = self.currentId() self.clear() self.addItems(items) self.setCurrentId(current) def clear(self): """Removes all items from the comboBox""" QComboBox.clear(self) self.items = OrderedDict() def addItem(self,id,item): """Adds a single item""" QComboBox.addItem(self,item) self.items[id] = item def getReportText(self, fileDir): """Standard getReportText""" r = {self.widgetName:{'includeInReports': self.includeInReports, 'text': self.currentText()}} #return '%s set to %s' % (self.label, self.currentText()) return r
class Triggers(object): """Match/action triggers for a server. """ def __init__(self, commandFunc): self.runCommand = commandFunc self.triggers = OrderedDict() self.thr = None self._q = [] def __hash__(self): """For sets. """ return hash(self.triggers) def __eq__(self, other): """Makes comparison for equality work reasonably. """ return self.triggers == other.triggers def __ne__(self, other): """Makes comparison for equality work reasonably. """ return not self.__eq__(other) def get(self, name): """Get and/or make the trigger object for the given name. """ if not self.triggers.get(name): self.triggers[name] = Trigger(self, name) return self.triggers[name] def addMatch(self, triggerName, matchSpec, matchName=""): """Add one match to a trigger. triggerName should uniquely identify a set of matches and associated actions, to separate them from any other match/action sets. matchSpec should be a ParmLine where the event and parameter values are regexps. matchName can name the match arbitrarily. """ trigger = self.get(triggerName) trigger.addMatch(matchSpec, matchName) def addAction(self, triggerName, actionSpec, actionName=""): """Add one action to a trigger. triggerName should uniquely identify a set of matches and associated actions, to separate them from any other match/action sets. actionSpec should be an action to perform. actionName can name the action arbitrarily. """ trigger = self.get(triggerName) trigger.addAction(actionSpec, actionName) def apply(self, parmline): """Apply actions where there is a match. As many match/action sets as match will have their actions applied. """ # config file triggers first. [trigger.apply(parmline) for trigger in self.triggers.values()] # Then custom code triggers if any. trigger_cc.apply(self.server, parmline, self.runCommand) @classmethod def loadCustomCode(cls): """Load custom trigger code if it exists. """ reload(trigger_cc) def queue(self, parmline): """Queues a trigger check instead of applying it immediately. """ self._q.append(parmline) if not self.thr: thr = threading.Thread(target=self._queueWatch) thr.daemon = True thr.start() def _queueWatch(self): """Watch the queue for things to do. Runs in its own thread as started by queue(). """ while True: if not self._q: sleep(0.5) continue parmline = self._q.pop(0) self.apply(parmline)
class Project(tmt.EclipseProject): def __init__(self, *args, **kwargs): tmt.EclipseProject.__init__(self, *args, **kwargs) tmt.WinstoneServer = self self.main = "net.gnehzr.tnoodle.server.TNoodleServer" self.argv = ['--nobrowser', '--consoleLevel=INFO'] # Winstone does all of these things =(. self.ignoredWarnings += ['unchecked'] self.ignoredWarnings += ['deprecation'] self.ignoredWarnings += ['serial'] self.ignoredWarnings += ['dep-ann'] self.ignoredWarnings += ['rawtypes'] # It is important that when we iterate through the plugins # in topological sorted order. This way if B uses A, B can clobber # A's settings. self.plugins = OrderedDict() def configure(self): tmt.EclipseProject.configure(self) self.nonJavaResourceDeps |= tmt.glob(self.srcResource, '.*$', relativeTo=self.srcResource) for f in xmlFileTypes: self.nonJavaResourceDeps -= tmt.glob(self.srcResource, "%s$" % f, relativeTo=self.srcResource) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.properties$', relativeTo=self.src) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.xsd$', relativeTo=self.src) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.dtd$', relativeTo=self.src) def addPlugin(self, project, needsDb=False): project.main = self.main project.argv = self.argv self.plugins[project.name] = project project.needsDb = needsDb notDotfile = lambda dirname: not dirname.startswith(".") def wrapCompile(ogCompile): def newCompile(self): if ogCompile(self): assert self.webContent for dirpath, dirnames, filenames in os.walk( self.webContent): dirnames[:] = filter( notDotfile, dirnames ) # Note that we're modifying dirnames in place if "WEB-INF" in dirnames: dirnames.remove("WEB-INF") for filename in filter(notDotfile, filenames): path = os.path.normpath( os.path.join(dirpath, filename)) pathRelToWebContent = relpath( path, self.webContent) name = join(tmt.WinstoneServer.binResource, "webapps", "ROOT", pathRelToWebContent) linkParent = os.path.dirname(name) if not os.path.exists(linkParent): os.makedirs(linkParent) else: assert os.path.isdir(linkParent) tmt.createSymlinkIfNotExistsOrStale( relpath(path, linkParent), name) tmt.WinstoneServer.mungeXmlFiles(topLevelWebProject=self) return newCompile project.__class__.compile = wrapCompile(project.__class__.compile) def webContentDist(self): # We just compiled ourself, which caused a recompile # of winstone server, so there's no need to recompile it. # In fact, recompiling it would be bad, as it would nuke # our carefully constructed tnoodle_resources. tmt.WinstoneServer.dist(noRemake=True) tmt.WinstoneServer.distJarFile() shutil.copy(tmt.WinstoneServer.distJarFile(), self.distJarFile()) project.__class__.webContentDist = webContentDist def getWebappDir(self): webappsDir = join(self.binResource, "webapps") webappDir = join(webappsDir, "ROOT") return webappDir def compile(self): if tmt.EclipseProject.compile(self): if tmt.TmtProject.projects[tmt.args.project] == self: # No wrapped compile to call this for us self.mungeXmlFiles(topLevelWebProject=self) webappDir = self.getWebappDir() webappWebInfDir = join(webappDir, "WEB-INF") libDir = join(webappWebInfDir, 'lib') if not os.path.exists(libDir): os.makedirs(libDir) classesDir = join(webappWebInfDir, 'classes') if not os.path.exists(classesDir): os.makedirs(classesDir) def mungeXmlFiles(self, topLevelWebProject): for f in xmlFileTypes: deps = topLevelWebProject.getRecursiveDependenciesTopoSorted() webappDir = self.getWebappDir() webappWebInfDir = join(webappDir, "WEB-INF") if not os.path.isdir(webappWebInfDir): os.makedirs(webappWebInfDir) srcWebInfDir = join(self.srcResource, "webapps", "ROOT", "WEB-INF") xmlRoot = ET.parse(join(srcWebInfDir, f)).getroot() if self.needsDb(): h2ConsoleServlet = """<?xml version="1.0" encoding="UTF-8"?> <junk> <!-- H2 web console --> <servlet> <servlet-name>H2Console</servlet-name> <servlet-class>org.h2.server.web.WebServlet</servlet-class> <init-param> <param-name>properties</param-name> <param-value>null</param-value> </init-param> <!-- <init-param> <param-name>webAllowOthers</param-name> <param-value></param-value> </init-param> <init-param> <param-name>trace</param-name> <param-value></param-value> </init-param> --> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>InitializeH2Console</servlet-name> <servlet-class>net.gnehzr.tnoodle.server.InitializeH2Console</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>H2Console</servlet-name> <url-pattern>/h2/*</url-pattern> </servlet-mapping> </junk> """ root = ET.fromstring(h2ConsoleServlet) for child in reversed(root): xmlRoot.insert(0, child) for project in deps: if project in self.plugins.values(): assert project.webContent pluginXmlFile = join(project.webContent, "WEB-INF", f) if not os.path.exists(pluginXmlFile): continue tree = ET.parse(pluginXmlFile) root = tree.getroot() for child in reversed(root): xmlRoot.insert(0, child) xmlFile = join(webappWebInfDir, f) xmlFileOut = open(xmlFile, 'w') ET.register_namespace("", "http://java.sun.com/xml/ns/javaee") xmlFileOut.write(ET.tostring(xmlRoot)) xmlFileOut.close() def needsDb(self): if getattr(tmt.args, "project", None) is None: # None may not yet be a key in tmt.TmtProject.projects, # we just hack around this by unconditionally returning True here. return True webProject = tmt.TmtProject.projects[tmt.args.project] if webProject == self: return True deps = webProject.getRecursiveDependenciesTopoSorted( exclude=set([self])) for project in deps: if project in self.plugins.values(): if project.needsDb: return True return False def getJars(self, includeCompileTimeOnlyDependencies=False): jars = tmt.EclipseProject.getJars(self, includeCompileTimeOnlyDependencies= includeCompileTimeOnlyDependencies) if self.needsDb(): jars.append(tmt.TmtProject.projects['h2-1.3.169.jar']) return jars def tweakJarFile(self, jar): # We don't necessarily want all the plugins in self.plugins to load here, # we only want the ones that the project we're currently building somehow # depends on. webProject = tmt.TmtProject.projects[tmt.args.project] # Out jar file already contains everything needed to start up winstone. # All the contents of tnoodle_resources are there too (including webroot). # The problem is that even after compiling, webroot/WEB-INF/lib/ and # webroot/WEB-INF/classes/ are still unpopulated, so simply jarring it up # isn't good enough. Here we populate classes/ and lib/. To do so, we need # all of the things that webProject depends on, EXCEPT for winstone (ourself). deps = webProject.getRecursiveDependenciesTopoSorted( exclude=set([self])) webInf = join("tnoodle_resources", "webapps", "ROOT", "WEB-INF") libDir = join(webInf, "lib") classesDir = join(webInf, "classes") for project in deps: assert project is not self if hasattr(project, "jarFile"): arcPath = join(libDir, basename(project.jarFile)) jar.write(project.jarFile, arcPath) elif isinstance(project, tmt.EclipseProject): for dirpath, dirnames, filenames in os.walk(project.bin, followlinks=True): for name in filenames: if dirpath.startswith( join(project.bin, "tnoodle_resources")): destDir = "" else: destDir = classesDir path = join(dirpath, name) prefixLen = len(project.bin) if project.bin.endswith("/"): prefixLen += 1 arcPath = join(destDir, path[prefixLen + 1:]) jar.write(path, arcPath)
class Project(tmt.EclipseProject): def __init__(self, *args, **kwargs): tmt.EclipseProject.__init__(self, *args, **kwargs) tmt.WinstoneServer = self self.main = "net.gnehzr.tnoodle.server.TNoodleServer" self.argv = [ '--nobrowser', '--consoleLevel=INFO' ] # Winstone does all of these things =(. self.ignoredWarnings += [ 'unchecked' ] self.ignoredWarnings += [ 'deprecation' ] self.ignoredWarnings += [ 'serial' ] self.ignoredWarnings += [ 'dep-ann' ] self.ignoredWarnings += [ 'rawtypes' ] # It is important that when we iterate through the plugins # in topological sorted order. This way if B uses A, B can clobber # A's settings. self.plugins = OrderedDict() def configure(self): tmt.EclipseProject.configure(self) self.nonJavaResourceDeps |= tmt.glob(self.srcResource, '.*$', relativeTo=self.srcResource) for f in xmlFileTypes: self.nonJavaResourceDeps -= tmt.glob(self.srcResource, "%s$" % f, relativeTo=self.srcResource) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.properties$', relativeTo=self.src) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.xsd$', relativeTo=self.src) self.nonJavaSrcDeps |= tmt.glob(self.src, '.*\\.dtd$', relativeTo=self.src) def addPlugin(self, project, needsDb=False): project.main = self.main project.argv = self.argv self.plugins[project.name] = project project.needsDb = needsDb notDotfile = lambda dirname: not dirname.startswith(".") def wrapCompile(ogCompile): def newCompile(self): if ogCompile(self): assert self.webContent for dirpath, dirnames, filenames in os.walk(self.webContent): dirnames[:] = filter(notDotfile, dirnames) # Note that we're modifying dirnames in place if "WEB-INF" in dirnames: dirnames.remove("WEB-INF") for filename in filter(notDotfile, filenames): path = os.path.normpath(os.path.join(dirpath, filename)) pathRelToWebContent = relpath(path, self.webContent) name = join(tmt.WinstoneServer.binResource, "webapps", "ROOT", pathRelToWebContent) linkParent = os.path.dirname(name) if not os.path.exists(linkParent): os.makedirs(linkParent) else: assert os.path.isdir(linkParent) tmt.createSymlinkIfNotExistsOrStale(relpath(path, linkParent), name) tmt.WinstoneServer.mungeXmlFiles(topLevelWebProject=self) return newCompile project.__class__.compile = wrapCompile(project.__class__.compile) def webContentDist(self): # We just compiled ourself, which caused a recompile # of winstone server, so there's no need to recompile it. # In fact, recompiling it would be bad, as it would nuke # our carefully constructed tnoodle_resources. tmt.WinstoneServer.dist(noRemake=True, implementationTitle=self.fullName) tmt.WinstoneServer.distJarFile() shutil.copy(tmt.WinstoneServer.distJarFile(), self.distJarFile()) project.__class__.webContentDist = webContentDist def getWebappDir(self): webappsDir = join(self.binResource, "webapps") webappDir = join(webappsDir, "ROOT") return webappDir def compile(self): if tmt.EclipseProject.compile(self): if tmt.TmtProject.projects[tmt.args.project] == self: # No wrapped compile to call this for us self.mungeXmlFiles(topLevelWebProject=self) webappDir = self.getWebappDir() webappWebInfDir = join(webappDir, "WEB-INF") libDir = join(webappWebInfDir, 'lib') if not os.path.exists(libDir): os.makedirs(libDir) classesDir = join(webappWebInfDir, 'classes') if not os.path.exists(classesDir): os.makedirs(classesDir) def mungeXmlFiles(self, topLevelWebProject): for f in xmlFileTypes: deps = topLevelWebProject.getRecursiveDependenciesTopoSorted() webappDir = self.getWebappDir() webappWebInfDir = join(webappDir, "WEB-INF") if not os.path.isdir(webappWebInfDir): os.makedirs(webappWebInfDir) srcWebInfDir = join(self.srcResource, "webapps", "ROOT", "WEB-INF") xmlRoot = ET.parse(join(srcWebInfDir, f)).getroot() if self.needsDb(): h2ConsoleServlet = """<?xml version="1.0" encoding="UTF-8"?> <junk> <!-- H2 web console --> <servlet> <servlet-name>H2Console</servlet-name> <servlet-class>org.h2.server.web.WebServlet</servlet-class> <init-param> <param-name>properties</param-name> <param-value>null</param-value> </init-param> <!-- <init-param> <param-name>webAllowOthers</param-name> <param-value></param-value> </init-param> <init-param> <param-name>trace</param-name> <param-value></param-value> </init-param> --> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>InitializeH2Console</servlet-name> <servlet-class>net.gnehzr.tnoodle.server.InitializeH2Console</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>H2Console</servlet-name> <url-pattern>/h2/*</url-pattern> </servlet-mapping> </junk> """ root = ET.fromstring(h2ConsoleServlet) for child in reversed(root): xmlRoot.insert(0, child) for project in deps: if project in self.plugins.values(): assert project.webContent pluginXmlFile = join(project.webContent, "WEB-INF", f) if not os.path.exists(pluginXmlFile): continue tree = ET.parse(pluginXmlFile) root = tree.getroot() for child in reversed(root): xmlRoot.insert(0, child) xmlFile = join(webappWebInfDir, f) xmlFileOut = open(xmlFile, 'w') ET.register_namespace("", "http://java.sun.com/xml/ns/javaee") xmlFileOut.write(ET.tostring(xmlRoot)) xmlFileOut.close() def needsDb(self): if getattr(tmt.args, "project", None) is None: # None may not yet be a key in tmt.TmtProject.projects, # we just hack around this by unconditionally returning True here. return True webProject = tmt.TmtProject.projects[tmt.args.project] if webProject == self: return True deps = webProject.getRecursiveDependenciesTopoSorted(exclude=set([self])) for project in deps: if project in self.plugins.values(): if project.needsDb: return True return False def getJars(self, includeCompileTimeOnlyDependencies=False): jars = tmt.EclipseProject.getJars(self, includeCompileTimeOnlyDependencies=includeCompileTimeOnlyDependencies) if self.needsDb(): jars.append(tmt.TmtProject.projects['h2-1.3.169.jar']) return jars def tweakJarFile(self, jar): # We don't necessarily want all the plugins in self.plugins to load here, # we only want the ones that the project we're currently building somehow # depends on. webProject = tmt.TmtProject.projects[tmt.args.project] # Out jar file already contains everything needed to start up winstone. # All the contents of tnoodle_resources are there too (including webroot). # The problem is that even after compiling, webroot/WEB-INF/lib/ and # webroot/WEB-INF/classes/ are still unpopulated, so simply jarring it up # isn't good enough. Here we populate classes/ and lib/. To do so, we need # all of the things that webProject depends on, EXCEPT for winstone (ourself). deps = webProject.getRecursiveDependenciesTopoSorted(exclude=set([self])) webInf = join("tnoodle_resources", "webapps", "ROOT", "WEB-INF") libDir = join(webInf, "lib") classesDir = join(webInf, "classes") for project in deps: assert project is not self if hasattr(project, "jarFile"): arcPath = join(libDir, basename(project.jarFile)) jar.write(project.jarFile, arcPath) elif isinstance(project, tmt.EclipseProject): for dirpath, dirnames, filenames in os.walk(project.bin, followlinks=True): for name in filenames: if dirpath.startswith(join(project.bin, "tnoodle_resources")): destDir = "" else: destDir = classesDir path = join(dirpath, name) prefixLen = len(project.bin) if project.bin.endswith("/"): prefixLen += 1 arcPath = join(destDir, path[prefixLen+1:]) jar.write(path, arcPath)
class comboBox(QComboBox, widgetState): def __init__(self, widget, label=None, displayLabel=True, includeInReports=True, items=None, editable=False, orientation='horizontal', callback=None): widgetState.__init__(self, widget, label, includeInReports) QComboBox.__init__(self, self.controlArea) if displayLabel: self.hb = widgetBox(self.controlArea, orientation=orientation) widgetLabel(self.hb, label) self.hb.layout().addWidget(self) self.hasLabel = True else: self.controlArea.layout().addWidget(self) self.hasLabel = False self.label = label self.items = OrderedDict() self.setEditable(editable) if items: self.addItems(items) if callback: QObject.connect(self, SIGNAL('activated(int)'), callback) def getSettings(self): r = {'items': self.items, 'current': self.currentIndex()} return r def loadSettings(self, data): # print _('in comboBox load') # print data self.addItems(data['items']) self.setCurrentIndex(data['current']) def currentId(self): try: return self.items.keys()[self.currentIndex()] except: return None def currentItem(self): return { self.items.keys()[self.currentIndex()]: self.items.values()[self.currentIndex()] } def setCurrentId(self, id): try: self.setCurrentIndex(self.items.keys().index(id)) except: pass def addItems(self, items): if type(items) in [dict, OrderedDict]: for k, v in items.items(): self.addItem(k, v) elif type(items) in [list]: if len(items) > 0 and type(items[0]) is tuple: for k, v in items: self.addItem(k, v) else: for v in items: self.addItem(v, v) # redRLog.log(redRLog.REDRCORE,redRLog.DEBUG,_('In listBox should not use list')) else: raise Exception( _('In comboBox, addItems takes a list, dict or OrderedDict')) def update(self, items): current = self.currentId() self.clear() self.addItems(items) self.setCurrentId(current) def clear(self): QComboBox.clear(self) self.items = OrderedDict() def addItem(self, id, item): QComboBox.addItem(self, item) self.items[id] = item def getReportText(self, fileDir): r = { self.widgetName: { 'includeInReports': self.includeInReports, 'text': self.currentText() } } #return '%s set to %s' % (self.label, self.currentText()) return r
class listBox(QListWidget,widgetState): def __init__(self, widget, value=None, label=None, displayLabel=True, orientation='vertical', selectionMode=QAbstractItemView.SingleSelection, enableDragDrop = 0, dragDropCallback = None, dataValidityCallback = None, sizeHint = None, callback=None, items = None, *args, **kwargs): kwargs.setdefault('includeInReports', True) kwargs.setdefault('sizePolicy', QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) widgetState.__init__(self,widget,label,**kwargs) QListWidget.__init__(self, *args) self.label = label self.widget = self.controlArea if displayLabel: self.hb = groupBox(self.controlArea,label=label,orientation=orientation) else: self.hb = widgetBox(self.controlArea,orientation=orientation) self.hb.layout().addWidget(self) self.ogValue = value self.ogLabels = label self.enableDragDrop = enableDragDrop self.dragDopCallback = dragDropCallback self.dataValidityCallback = dataValidityCallback self.defaultSizeHint = QSize(150,100) self.setSelectionMode(selectionMode) if enableDragDrop: self.setDragEnabled(1) self.setAcceptDrops(1) self.setDropIndicatorShown(1) #self.setDragDropMode(QAbstractItemView.DragDrop) self.dragStartPosition = 0 self.listItems = OrderedDict() if items: self.addItems(items) if callback: QObject.connect(self, SIGNAL('itemClicked(QListWidgetItem*)'), callback) def getItems(self): """Returns an OrderedDict of the items (key, value) in the listBox, this can be treated as a dict also.""" return self.listItems def addItem(self,id,item): QListWidget.addItem(self,item) self.listItems[id] = item def addItems(self,items): progressBar = startProgressBar('Setting List Items', '', len(items)) progress = 0 if type(items) in [dict,OrderedDict]: for k,v in items.items(): self.addItem(k,v) progress += 1 progressBar.setValue(progress) elif type(items) in [list]: progressBar = startProgressBar('Setting List Items', '', len(items)) if len(items) > 0 and type(items[0]) is tuple: for k,v in items: self.addItem(k,v) progress += 1 progressBar.setValue(progress) else: for v in items: self.addItem(v,v) progress += 1 progressBar.setValue(progress) # redRLog.log(redRLog.REDRCORE,redRLog.DEBUG,_('In listBox should not use list')) else: progressBar.hide() raise Exception(_('In listBox, addItems takes a list, dict or OrderedDict')) progressBar.hide() def setSelectedIds(self,ids): """Sets a list of ids (ids) to be selected.""" if ids == None: return progressBar = startProgressBar('Setting Selected Items', '', len(ids)) progress = 0 for x in ids: try: self.item(self.listItems.keys().index(x)).setSelected(True) except: pass progress += 1 progressBar.setValue(progress) def update(self, items): """Clears the list, adds new items, and sets any selected items in the old list to being selected in the new list (if they exist of course).""" current = self.selectedIds() self.clear() self.addItems(items) self.setSelectedIds(current) def clear(self): """Clears the list""" QListWidget.clear(self) self.listItems = OrderedDict() def invertSelection(self): for i in range(self.count()): if self.isItemSelected(self.item(i)): self.item(i).setSelected(False) else: self.item(i).setSelected(True) def selectionCount(self): return len(self.selectedIndexes()) def currentSelection(self): """Returns a list of selected values (the text in the list)""" return self.selectedItems().values() def selectedItems(self): """Returns a dict of selected items.""" items = {} for x in self.selectedIndexes(): items[self.listItems.keys()[x.row()]] = self.listItems.values()[x.row()] return items def selectedIds(self): """Returns a list of selected ids""" ids = [] for x in self.selectedIndexes(): ids.append(self.listItems.keys()[x.row()]) return ids #def setSelectedIds(self, ids): #if ids == None: return #for i in range(self.count()): #if self.listItems.keys()[i] in ids: #self.item(i).setSelect(True) def sizeHint(self): return self.defaultSizeHint def startDrag(self, supportedActions): if not self.enableDragDrop: return drag = QDrag(self) mime = QMimeData() if not self.ogValue: selectedItems = [i for i in range(self.count()) if self.item(i).isSelected()] else: selectedItems = getdeepattr(self.widget, self.ogValue, default = []) mime.setText(unicode(selectedItems)) mime.source = self drag.setMimeData(mime) drag.start(Qt.MoveAction) def dragEnterEvent(self, ev): if not self.enableDragDrop: return if self.dataValidityCallback: return self.dataValidityCallback(ev) if ev.mimeData().hasText(): ev.accept() else: ev.ignore() def dragMoveEvent(self, ev): if not self.enableDragDrop: return if self.dataValidityCallback: return self.dataValidityCallback(ev) if ev.mimeData().hasText(): ev.setDropAction(Qt.MoveAction) ev.accept() else: ev.ignore() def dropEvent(self, ev): if not self.enableDragDrop: return if ev.mimeData().hasText(): item = self.itemAt(ev.pos()) if item: index = self.indexFromItem(item).row() else: index = self.count() source = ev.mimeData().source selectedItemIndices = eval(unicode(ev.mimeData().text())) if self.ogLabels != None and self.ogValue != None: allSourceItems = getdeepattr(source.widget, source.ogLabels, default = []) selectedItems = [allSourceItems[i] for i in selectedItemIndices] allDestItems = getdeepattr(self.widget, self.ogLabels, default = []) if source != self: setattr(source.widget, source.ogLabels, [item for item in allSourceItems if item not in selectedItems]) # TODO: optimize this code. use the fact that the selectedItemIndices is a sorted list setattr(self.widget, self.ogLabels, allDestItems[:index] + selectedItems + allDestItems[index:]) setattr(source.widget, source.ogValue, []) # clear selection in the source widget else: items = [item for item in allSourceItems if item not in selectedItems] if index < len(allDestItems): while index > 0 and index in getdeepattr(self.widget, self.ogValue, default = []): # if we are dropping items on a selected item, we have to select some previous unselected item as the drop target index -= 1 destItem = allDestItems[index] index = items.index(destItem) else: index = max(0, index - len(selectedItems)) setattr(self.widget, self.ogLabels, items[:index] + selectedItems + items[index:]) setattr(self.widget, self.ogValue, range(index, index+len(selectedItems))) else: # if we don't have variables ogValue and ogLabel if source != self: self.insertItems(source.selectedItems()) for index in selectedItemIndices[::-1]: source.takeItem(index) else: if index < self.count(): while index > 0 and self.item(index).isSelected(): # if we are dropping items on a selected item, we have to select some previous unselected item as the drop target index -= 1 items = [source.item(i) for i in selectedItemIndices] for ind in selectedItemIndices[::-1]: source.takeItem(ind) if ind <= index: index-= 1 for item in items[::-1]: self.insertItem(index, item) self.clearSelection() for i in range(index, index+len(items)): self.item(i).setSelected(1) if self.dragDopCallback: # call the callback self.dragDopCallback() ev.setDropAction(Qt.MoveAction) ev.accept() ## whatever all of this does we need to execute the function to update the items self.updateRedRItems() else: ev.ignore() def updateRedRItems(self): """Updates the items in the list to a new order.""" ## we go through all of the items and remake the items OrderedDict newDict = OrderedDict() for r in range(self.count()): t = unicode(self.item(r).text()) # get the text of the item if t not in self.listItems.values(): newDict[t] = t else: for i, ov in self.listItems.items(): if ov == t: newDict[i] = ov self.listItems = newDict def getSettings(self): #print 'saving list box' r = {'items':self.listItems, 'selected':self.selectedIds()} #print r return r def loadSettings(self,data): self.clear() self.addItems(data.get('items', [])) self.setSelectedIds(data.get('selected', None)) def getReportText(self, fileDir): items = self.getItems() selected = self.currentSelection() new = [] for x in items: if x in selected: new.append([_('Selected'), x]) else: new.append([_('Not Selected'),x]) #print new text = redRReports.createTable(new,columnNames=[_('Selection'),_('Option')]) # if text != '': # text += '\nSelected text has * in front' r = {self.widgetName:{'includeInReports': self.includeInReports, 'text': text}} return r
class listBox(QListWidget, widgetState): def __init__(self, widget, value=None, label=None, displayLabel=True, includeInReports=True, orientation='vertical', selectionMode=QAbstractItemView.SingleSelection, enableDragDrop=0, dragDropCallback=None, dataValidityCallback=None, sizeHint=None, callback=None, toolTip=None, items=None, *args): widgetState.__init__(self, widget, label, includeInReports) QListWidget.__init__(self, *args) self.label = label self.widget = self.controlArea if displayLabel: self.hb = groupBox(self.controlArea, label=label, orientation=orientation) else: self.hb = widgetBox(self.controlArea, orientation=orientation) self.hb.layout().addWidget(self) self.ogValue = value self.ogLabels = label self.enableDragDrop = enableDragDrop self.dragDopCallback = dragDropCallback self.dataValidityCallback = dataValidityCallback if not sizeHint: self.defaultSizeHint = QSize(150, 100) else: self.defaultSizeHint = sizeHint self.setSelectionMode(selectionMode) if enableDragDrop: self.setDragEnabled(1) self.setAcceptDrops(1) self.setDropIndicatorShown(1) #self.setDragDropMode(QAbstractItemView.DragDrop) self.dragStartPosition = 0 if toolTip: self.setToolTip(toolTip) self.listItems = OrderedDict() if items: self.addItems(items) if callback: QObject.connect(self, SIGNAL('itemClicked(QListWidgetItem*)'), callback) def getItems(self): return self.listItems def addItem(self, id, item): QListWidget.addItem(self, item) self.listItems[id] = item def addItems(self, items): if type(items) in [dict, OrderedDict]: for k, v in items.items(): self.addItem(k, v) elif type(items) in [list]: if len(items) > 0 and type(items[0]) is tuple: for k, v in items: self.addItem(k, v) else: for v in items: self.addItem(v, v) # redRLog.log(redRLog.REDRCORE,redRLog.DEBUG,_('In listBox should not use list')) else: raise Exception( _('In listBox, addItems takes a list, dict or OrderedDict')) def setSelectedIds(self, ids): for x in ids: try: self.item(self.listItems.keys().index(x)).setSelected(True) except: pass def update(self, items): current = self.selectedIds() self.clear() self.addItems(items) self.setSelectedIds(current) def clear(self): QListWidget.clear(self) self.items = OrderedDict() def invertSelection(self): for i in range(self.count()): if self.isItemSelected(self.item(i)): self.item(i).setSelected(False) else: self.item(i).setSelected(True) def selectionCount(self): return len(self.selectedIndexes()) def currentSelection(self): return self.selectedItems().values() def selectedItems(self): items = {} for x in self.selectedIndexes(): items[self.listItems.keys()[x.row()]] = self.listItems.values()[ x.row()] return items def selectedIds(self): ids = [] for x in self.selectedIndexes(): ids.append(self.listItems.keys()[x.row()]) return ids def sizeHint(self): return self.defaultSizeHint def startDrag(self, supportedActions): if not self.enableDragDrop: return drag = QDrag(self) mime = QMimeData() if not self.ogValue: selectedItems = [ i for i in range(self.count()) if self.item(i).isSelected() ] else: selectedItems = getdeepattr(self.widget, self.ogValue, default=[]) mime.setText(unicode(selectedItems)) mime.source = self drag.setMimeData(mime) drag.start(Qt.MoveAction) def dragEnterEvent(self, ev): if not self.enableDragDrop: return if self.dataValidityCallback: return self.dataValidityCallback(ev) if ev.mimeData().hasText(): ev.accept() else: ev.ignore() def dragMoveEvent(self, ev): if not self.enableDragDrop: return if self.dataValidityCallback: return self.dataValidityCallback(ev) if ev.mimeData().hasText(): ev.setDropAction(Qt.MoveAction) ev.accept() else: ev.ignore() def dropEvent(self, ev): if not self.enableDragDrop: return if ev.mimeData().hasText(): item = self.itemAt(ev.pos()) if item: index = self.indexFromItem(item).row() else: index = self.count() source = ev.mimeData().source selectedItemIndices = eval(unicode(ev.mimeData().text())) if self.ogLabels != None and self.ogValue != None: allSourceItems = getdeepattr(source.widget, source.ogLabels, default=[]) selectedItems = [ allSourceItems[i] for i in selectedItemIndices ] allDestItems = getdeepattr(self.widget, self.ogLabels, default=[]) if source != self: setattr( source.widget, source.ogLabels, [ item for item in allSourceItems if item not in selectedItems ] ) # TODO: optimize this code. use the fact that the selectedItemIndices is a sorted list setattr( self.widget, self.ogLabels, allDestItems[:index] + selectedItems + allDestItems[index:]) setattr(source.widget, source.ogValue, []) # clear selection in the source widget else: items = [ item for item in allSourceItems if item not in selectedItems ] if index < len(allDestItems): while index > 0 and index in getdeepattr( self.widget, self.ogValue, default=[] ): # if we are dropping items on a selected item, we have to select some previous unselected item as the drop target index -= 1 destItem = allDestItems[index] index = items.index(destItem) else: index = max(0, index - len(selectedItems)) setattr(self.widget, self.ogLabels, items[:index] + selectedItems + items[index:]) setattr(self.widget, self.ogValue, range(index, index + len(selectedItems))) else: # if we don't have variables ogValue and ogLabel if source != self: self.insertItems(source.selectedItems()) for index in selectedItemIndices[::-1]: source.takeItem(index) else: if index < self.count(): while index > 0 and self.item(index).isSelected( ): # if we are dropping items on a selected item, we have to select some previous unselected item as the drop target index -= 1 items = [source.item(i) for i in selectedItemIndices] for ind in selectedItemIndices[::-1]: source.takeItem(ind) if ind <= index: index -= 1 for item in items[::-1]: self.insertItem(index, item) self.clearSelection() for i in range(index, index + len(items)): self.item(i).setSelected(1) if self.dragDopCallback: # call the callback self.dragDopCallback() ev.setDropAction(Qt.MoveAction) ev.accept() ## whatever all of this does we need to execute the function to update the items self.updateRedRItems() else: ev.ignore() def updateRedRItems(self): ## we go through all of the items and remake the items OrderedDict newDict = OrderedDict() for r in range(self.count()): t = unicode(self.itemAt(r).text()) # get the text of the item if t not in self.listItems.values(): newDict[t] = t else: for i, ov in self.listItems.items(): if ov == t: newDict[i] = ov self.listItems = newDict def getSettings(self): print 'saving list box' r = {'items': self.items, 'selected': self.selectedIds()} print r return r def loadSettings(self, data): print _('loading list box') print data self.clear() self.addItems(data['items']) self.setSelectedIds(data['selected']) def getReportText(self, fileDir): items = self.getItems() selected = self.currentSelection() new = [] for x in items: if x in selected: new.append([_('Selected'), x]) else: new.append([_('Not Selected'), x]) #print new text = redRReports.createTable( new, columnNames=[_('Selection'), _('Option')]) # if text != '': # text += '\nSelected text has * in front' r = { self.widgetName: { 'includeInReports': self.includeInReports, 'text': text } } return r