Fix bug #4260: translate fails with go tag in final position
[maxima.git] / admin / sfquery.py
blob84813fa85e67c5e79a192101570534fddf4e2d0e
1 #!/usr/bin/env python
3 # sfquery.py : python library/program to query Sourceforge bug database
4 # XML files.
6 # See the comments below the license for usage examples.
8 # Copyright (C) 2003 James F. Amundson
9 # <amundson at users dot sourceforge dot net>
11 # This library is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU Library General Public
13 # License as published by the Free Software Foundation; either
14 # version 2 of the License, or (at your option) any later version.
16 # This library is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 # Library General Public License for more details.
21 # You should have received a copy of the GNU Library General Public
22 # License along with this library; if not, write to the
23 # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 # Examples:
28 # Find all the bugs submitted by amundson and print summaries:
30 # ./sfquery.py bugs-10-02-2003.xml\
31 # "artifact.get('submitted_by') == 'amundson'"\
32 # "artifact.print_summary()"
34 # Find all the *open* bugs submitted by amundson and print summaries:
36 # ./sfquery.py bugs-10-02-2003.xml\
37 # "artifact.get('submitted_by')=='amundson' and artifact.get('status')=='Open'"\
38 # "artifact.print_summary()"
40 # Find a specific bug and print the full record:
42 # ./sfquery.py bugs-10-02-2003.xml\
43 # "artifact.get('artifact_id') == '596204'"\
44 # "artifact.print_all()"
45 # Find all bugs containing plot and print who submitted them and their status:
47 # ./sfquery.py bugs-10-02-2003.xml\
48 # "contains(artifact,'plot')"\
49 # "sys.stdout.write('%s\n' % artifact.get('submitted_by'));sys.stdout.write('%s\n\n' % artifact.get('status'))"
52 import sys
53 from xml.sax import make_parser, handler, saxutils
54 from time import asctime, gmtime
55 import string
56 import re
58 def contains(thing,pattern,ignore_case=1):
59 if type(thing) == str or type(thing) == unicode:
60 if ignore_case:
61 result = re.search(pattern,thing,re.IGNORECASE)
62 else:
63 result = re.search(pattern,thing)
64 if result:
65 return 1
66 else:
67 return 0
68 elif hasattr(thing,"contains"):
69 return thing.contains(pattern,ignore_case)
70 else:
71 print "Warning: contains can not check",thing,"of type",type(thing)
72 return 0
74 class Fielded:
75 def __init__(self):
76 self.fields = {}
77 def add(self,name,content):
78 if self.fields.has_key(name):
79 self.fields[name] += content
80 else:
81 self.fields[name] = content
82 def get(self,name):
83 if self.fields.has_key(name):
84 uni = self.fields[name]
85 return uni.encode('iso-8859-1')
86 else:
87 return None
88 def contains(self,pattern,ignore_case=1):
89 for key in self.fields.keys():
90 if contains(self.fields[key],pattern,ignore_case):
91 return 1
92 return 0
93 def print_field(self,name):
94 if self.fields.has_key(name):
95 print name, ":",
96 if string.find(name,"date") > -1:
97 print asctime(gmtime(int(self.fields[name])))
98 elif name == "details":
99 print
100 print "-------------------------------------------------"
101 print self.fields[name].encode('iso-8859-1')
102 print "-------------------------------------------------"
103 else:
104 print self.fields[name]
105 def print_all(self,prefix=None):
106 for key in self.fields.keys():
107 if prefix:
108 print prefix,
109 self.print_field(key)
111 class History(Fielded):
112 def __init__(self):
113 self.fields = {}
114 self.messages = []
115 def contains(self,pattern,ignore_case=1):
116 for message in self.messages:
117 if contains(message,pattern,ignore_case):
118 return 1
119 return Fielded.contains(self,pattern,ignore_case)
120 def print_all(self,name,prefix=None):
121 Fielded.print_all(self,prefix)
122 if prefix:
123 print_prefix=prefix
124 else:
125 print_prefix=""
126 sub_prefix = print_prefix + " "
127 print print_prefix,"----------- messages -----------"
128 for message in self.messages:
129 message.print_all(sub_prefix)
130 print print_prefix,"--------------------------------"
132 class Artifact(Fielded):
133 def __init__(self):
134 self.fields = {}
135 self.messages = []
136 self.histories = []
137 def print_summary(self):
138 print self.get("artifact_id"),":",
139 print self.get("summary")
140 def contains(self,pattern,ignore_case=1):
141 for message in self.messages:
142 if contains(message,pattern,ignore_case):
143 return 1
144 for history in self.histories:
145 if contains(history,pattern,ignore_case):
146 return 1
147 return Fielded.contains(self,pattern,ignore_case)
148 def print_all(self,prefix=None):
149 if prefix:
150 print_prefix=prefix
151 else:
152 print_prefix=""
153 print print_prefix,"==================== artifact ===================="
154 Fielded.print_all(self,prefix)
155 sub_prefix = print_prefix + " "
156 print print_prefix,"----------- histories -----------"
157 for history in self.histories:
158 history.print_all(sub_prefix)
159 print print_prefix,"----------- messages -----------"
160 for message in self.messages:
161 message.print_all(sub_prefix)
162 print print_prefix,"--------------------------------"
163 print print_prefix,"================================================="
165 class Artifacts(Fielded):
166 def __init__(self):
167 self.fields={}
168 self.artifacts=[]
170 class ArtifactGrabber(handler.ContentHandler):
171 def __init__(self,warn=1):
172 self.current = []
173 self.artifacts = None
174 self.in_named_field = 0
175 self.warn = warn
177 def startElement(self, name, attrs):
178 if name == "artifacts":
179 self.current.append(Artifacts())
180 elif name == "artifact":
181 self.current.append(Artifact())
182 elif name == "history":
183 self.current.append(History())
184 elif name == "message":
185 self.current.append(Fielded())
186 elif name == "field":
187 if len(self.current) > 0:
188 if attrs.has_key("name"):
189 self.in_named_field = 1
190 self.field_name = attrs["name"]
191 else:
192 if self.warn:
193 print "Warning: ignoring element", name
195 def endElement(self, name):
196 if name == "artifacts":
197 self.artifacts = self.current.pop()
198 elif name == "artifact":
199 this = self.current.pop()
200 parent = self.current[len(self.current)-1]
201 parent.artifacts.append(this)
202 elif name == "message":
203 this = self.current.pop()
204 parent = self.current[len(self.current)-1]
205 parent.messages.append(this)
206 elif name == "history":
207 this = self.current.pop()
208 parent = self.current[len(self.current)-1]
209 parent.histories.append(this)
210 elif name == "field":
211 self.in_named_field = 0
213 def characters(self, content):
214 if self.in_named_field:
215 self.current[len(self.current)-1].add(self.field_name,content)
217 def endDocument(self):
218 global global_artifacts
219 global_artifacts = self.artifacts.artifacts
221 def get_artifacts(filename):
222 parser = make_parser()
223 parser.setContentHandler(ArtifactGrabber(warn=0))
224 parser.parse(filename)
225 return global_artifacts
227 def simple_query(artifacts,query,action):
228 print "Total number of artifacts =", len(artifacts)
229 matches = 0
230 for artifact in artifacts:
231 if eval(query):
232 matches += 1
233 for cmd in string.split(action,';'):
234 eval(cmd)
235 print "Found", matches,"matches."
237 if __name__ == "__main__":
238 if len(sys.argv) != 4:
239 print """Usage:
240 sfquery.py <filename> <query> <action>
241 <filename> is an XML dump of a SourceForge bug database.
242 <query> is a python command evaluating to 1 or 0.
243 <action> is a python command or commands to perform on each matched
244 object. Multiple command should be separated by the ';'
245 character.
247 sys.exit(1)
248 else:
249 artifacts = get_artifacts(sys.argv[1])
250 simple_query(artifacts,sys.argv[2],sys.argv[3])