1
2
3 '''
4
5 cli.py
6 ======
7
8 Command-line tool for creating FOAF and homepages for Gentoo Linux Developers
9
10 Author: Rob Cakebread <pythonhead@gentoo.org>
11
12 License : GPL-2
13
14 '''
15
16 __docformat__ = 'epytext'
17 __revision__ = '$Revision: $'[11:-1].strip()
18
19
20 import sha
21 import sys
22 import logging
23 import optparse
24 from cStringIO import StringIO
25
26 from lxml import etree
27 from rdflib.Graph import ConjunctiveGraph as CGraph
28 from rdflib import Namespace, Literal, BNode, RDF, URIRef
29
30 from ternate.utils import COLOR
31 from ternate.__init__ import __version__ as VERSION
32
33 FOAF = Namespace('http://xmlns.com/foaf/0.1/')
34 RDFS = Namespace('http://www.w3.org/2000/01/rdf-schema#')
35 DOAP = Namespace('http://usefulinc.com/ns/doap#')
36 GENTOO = Namespace('http://www.gentoo.org/ns/gentoo#')
37 HERD = Namespace('http://www.gentoo.org/ns/herd#')
38
40 '''Serialize FOAF'''
41 graph = CGraph()
42
43
44 graph.bind('foaf', FOAF)
45 graph.bind('rdfs', RDFS)
46 graph.bind('doap', DOAP)
47 graph.bind('herd', HERD)
48 graph.bind('gentoo', GENTOO)
49
50 person = add_foaf_node(graph, FOAF, ldap)
51
52
53 for friend in friends:
54 knows = add_foaf_node(graph, FOAF, friend)
55
56 graph.add((knows, RDFS['seeAlso'], URIRef(friend.get_foaf_url())))
57 graph.add((person, FOAF['knows'], knows))
58
59 return graph.serialize(format="pretty-xml")
60
62 '''
63 Create a BNode for a Person
64
65 TODO: Create mbox_sha1sum checksum from devname@gentoo.org
66 Is there a birthday on Gentoo's LDAP?
67 '''
68 nick = ldap['uid']
69 mbox = sha.new()
70 mbox.update('mailto:%s' % ldap['mail'])
71
72 node = URIRef("me")
73
74 graph.add((node, RDF.type, FOAF['Person'] ))
75 graph.add((node, FOAF['nick'], Literal(nick)))
76 graph.add((node, FOAF['name'], Literal(ldap['cn'])))
77 graph.add((node, GENTOO['gentooJoin'], Literal(ldap['gentooJoin'])))
78 graph.add((node, FOAF['homepage'], URIRef('http://dev.gentoo.org/~%s' % nick)))
79 graph.add((node, FOAF['mbox_sha1sum'], Literal(mbox.hexdigest())))
80
81
82 return node
83
85 '''
86 Parses the output of perl_ldap and creates a dictionary with the info
87 we want to use in FOAF
88
89 '''
90 fields = ['uid', 'cn', 'gentooLocation', 'gentooRoles', 'lat', 'lon',
91 'gentooJoin', 'mail', 'gpgkey', 'gentooStatus']
92
93 ldap = open(ldap_file).readlines()
94 ldap_dict = {}
95
96 for line in ldap:
97 if ':' in line:
98 key, value = line.split(':')
99 key = key.strip()
100 if key in fields:
101 ldap_dict[key] = value.strip()
102 return ldap_dict
103
105 '''
106 Get a dictionary of developer LDAP metadata and return a FOAF rendering
107 '''
108 ldap = get_ldap_info(ldap_file)
109 return create_foaf_file(ldap)
110
112 '''
113 Run an XSLT transform of foaf.rdf with developer.xsl stylesheet and get
114 nice Gentoo GuideXML output
115 '''
116 transform = etree.XSLT(etree.fromstring(FOAF_XSL))
117 doc = etree.parse(open(foaf_path, 'r'))
118 result_tree = transform(doc)
119 out = StringIO()
120 out.write("")
121 result_tree.write(out)
122 return out.getvalue()
123
124
126
127 '''`Ternate` class'''
128
130 '''Initialize attributes, set logger'''
131 self.options = None
132 self.log = logging.getLogger('ternate')
133 self.log.addHandler(logging.StreamHandler())
134
136 '''Set log level according to command-line options'''
137 if self.options.verbose:
138 self.log.setLevel(logging.INFO)
139 elif self.options.quiet:
140 self.log.setLevel(logging.ERROR)
141
142
143 else:
144 self.log.setLevel(logging.WARN)
145
147 '''
148 Run ternate command specified on command-line
149
150 @rtype: int
151 @returns: 0 success or 1 failure
152
153 '''
154 opt_parser = self.setup_opt_parser()
155 (self.options, remaining_args) = opt_parser.parse_args()
156 if remaining_args:
157 opt_parser.print_help()
158 return 1
159 self.set_log_level()
160
161 if self.options.ternate_version:
162 return ternate_version()
163
164 if self.options.no_color:
165 for this in COLOR:
166 COLOR[this] = '\x1b[0m'
167 if self.options.foaf:
168 print ldap_to_foaf(self.options.foaf)
169 return
170
171 elif self.options.guidexml:
172 print foaf_to_guidexml(self.options.guidexml)
173 return
174 else:
175 opt_parser.print_help()
176 return 1
177
179 '''
180 Setup the optparser
181
182 @rtype: opt_parser.OptionParser
183 @return: Option parser
184
185 '''
186 usage = 'usage: %prog [options]'
187 opt_parser = optparse.OptionParser(usage=usage)
188
189 opt_parser.add_option('--version', action='store_true',
190 dest='ternate_version', default=False,
191 help='Show ternate version and exit.')
192
193 opt_parser.add_option('-p', '--http-proxy', action='store',
194 dest='proxy', default=False,
195 help='Specify http proxy URL if you use one.')
196
197 opt_parser.add_option('-l', '--ldap', action='store',
198 dest='ldap', default=False,
199 metavar='username',
200 help='Fetch LDAP info for <username>')
201
202 opt_parser.add_option('-f', '--foaf', action='store',
203 dest='foaf', default=False,
204 metavar='LDAP file',
205 help='Create FOAF from LDAP info')
206
207 opt_parser.add_option('-g', '--guidexml', action='store',
208 dest='guidexml', default=False,
209 metavar='FOAF file',
210 help='Create GuideXML from LDAP info')
211
212 opt_parser.add_option('-C', '--no-color', action='store_true',
213 dest='no_color', default=False,
214 help="Don't use color in output")
215
216 opt_parser.add_option('-q', '--quiet', action='store_true',
217 dest='quiet', default=False, help="Show less output")
218
219 opt_parser.add_option('-v', '--verbose', action='store_true',
220 dest='verbose', default=False, help="Show more output")
221
222 return opt_parser
223
224
226 '''Print ternate version'''
227 print VERSION
228
229
231 '''Let's do it.'''
232 my_ternate = Ternate()
233 return my_ternate.run()
234
235
236 if __name__ == '__main__':
237 sys.exit(main())
238
239
240 FOAF_XSL = '''<?xml version="1.0"?>
241 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doap="http://usefulinc.com/ns/doap#" xmlns:herd="http://www.gentoo.org/ns/herd#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.0" xml:lang="en" xmlns:air="http://www.megginson.com/exp/ns/airports#" xmlns:wn="http://xmlns.com/wordnet/1.6/" xmlns:contact="http://www.w3.org/2000/10/swap/pim/contact#" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
242 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
243 <xsl:key name="indi" match="foaf:Person" use="@rdf:about"/>
244 <xsl:template match="/">
245 <guide link="/developer.xml">
246 <title>
247 <xsl:value-of select="/rdf:RDF/foaf:Person[@rdf:about='me']/foaf:name"/>
248 </title>
249 <author title="Author">
250 <xsl:element name="mail">
251 <xsl:attribute name="link">
252 <xsl:value-of select="/rdf:RDF/foaf:Person[@rdf:about='me']/foaf:nick"/>
253 </xsl:attribute>
254 </xsl:element>
255 </author>
256 <abstract>
257 This is the developer homepage of <xsl:value-of select="/rdf:RDF/foaf:Person[@rdf:about='me']/foaf:nick"/>
258 </abstract>
259 <!-- The content of this document is licensed under the CC-BY-SA license -->
260 <!-- See http://creativecommons.org/licenses/by-sa/2.5 -->
261 <license/>
262 <version>0.1</version>
263 <date>2008-06-27</date>
264 <chapter>
265 <title>Developer Info</title>
266 <section>
267 <title>Vitals</title>
268 <body>
269 <xsl:for-each select="rdf:RDF/foaf:Person[@rdf:about='me']">
270 <xsl:element name="a">
271 <xsl:attribute name="name">
272 <xsl:value-of select="@rdf:about='me'"/>
273 </xsl:attribute>
274 </xsl:element>
275 <dl>
276 <!-- We're in trouble if they add another nick since we want to do stuff with the Gentoo developer nick. So we should make a 'holdsAccount' and use the username from it -->
277 <dt>Nick: </dt>
278 <dd>
279 <xsl:value-of select="foaf:nick"/>
280 </dd>
281 <xsl:if test="foaf:gender">
282 <dt>Gender: </dt>
283 <dd>
284 <xsl:value-of select="foaf:gender"/>
285 </dd>
286 </xsl:if>
287 <dt>Mailbox sha1sum : </dt>
288 <xsl:for-each select="foaf:mbox_sha1sum">
289 <dd>
290 <xsl:value-of select="."/>
291 </dd>
292 </xsl:for-each>
293 <dt>Homepage : </dt>
294 <xsl:for-each select="foaf:homepage">
295 <dd>
296 <xsl:element name="uri">
297 <xsl:value-of select="@rdf:resource"/>
298 </xsl:element>
299 </dd>
300 </xsl:for-each>
301 <xsl:if test="foaf:weblog">
302 <dt>Blog : </dt>
303 <xsl:for-each select="foaf:weblog">
304 <dd>
305 <xsl:element name="uri">
306 <xsl:value-of select="@rdf:resource"/>
307 </xsl:element>
308 </dd>
309 </xsl:for-each>
310 </xsl:if>
311 <xsl:if test="foaf:based_near">
312 <dt>Location : </dt>
313 <xsl:for-each select="foaf:based_near/geo:Point">
314 <dd>
315 <xsl:text>Lattitude </xsl:text><xsl:value-of select="geo:lat"/>
316 </dd>
317 <dd>
318 <xsl:text>Longitude </xsl:text><xsl:value-of select="geo:long"/>
319 </dd>
320
321 </xsl:for-each>
322 </xsl:if>
323
324 <xsl:if test="foaf:openid">
325 <dt>OpenID : </dt>
326 <xsl:for-each select="foaf:openid">
327 <dd>
328 <xsl:element name="uri">
329 <xsl:value-of select="@rdf:resource"/>
330 </xsl:element>
331 </dd>
332 </xsl:for-each>
333 </xsl:if>
334 <xsl:if test="foaf:currentProject/herd:Project">
335 <dt>Herds : </dt>
336 <dd>
337 <xsl:for-each select="foaf:currentProject/herd:Project">
338 <xsl:apply-templates select="."/>
339 </xsl:for-each>
340 </dd>
341 </xsl:if>
342
343 <xsl:if test="foaf:currentProject/doap:Project">
344 <dt>Other OSS Projects : </dt>
345 <xsl:for-each select="foaf:currentProject/doap:Project">
346 <dd>
347 <xsl:element name="uri">
348 <xsl:attribute name="link"><xsl:value-of select="doap:homepage/@rdf:resource"/></xsl:attribute>
349 <xsl:apply-templates select="."/>
350 </xsl:element>
351 </dd>
352 </xsl:for-each>
353 </xsl:if>
354 <dt>Stats : </dt>
355 <dd>
356 <xsl:element name="uri">
357 <xsl:attribute name="link">
358 http://cia.navi.cx/stats/author/<xsl:value-of select="/rdf:RDF/foaf:Person/foaf:nick"/>
359 </xsl:attribute>
360 Commits
361 </xsl:element>
362 </dd>
363
364 <dd>
365 <xsl:element name="uri">
366 <xsl:attribute name="link">
367 <xsl:text>http://bugs.gentoo.org/buglist.cgi?bug_status=NEW;bug_status=ASSIGNED;bug_status=REOPENED;email1=</xsl:text><xsl:value-of select="/rdf:RDF/foaf:Person/foaf:nick"/><xsl:text>%40gentoo.org;emailtype1=exact;emailassigned_to1=1;emailreporter1=1</xsl:text></xsl:attribute>
368 <xsl:text>Bugs</xsl:text>
369 </xsl:element>
370 </dd>
371
372 <xsl:if test="foaf:JabberID">
373 <dt>Jabber Id : </dt>
374 <xsl:for-each select="foaf:jabberID">
375 <dd>
376 <xsl:value-of select="."/>
377 </dd>
378 </xsl:for-each>
379 </xsl:if>
380
381 <xsl:if test="foaf:holdsAccount">
382 <dt>Misc Accounts : </dt>
383 <xsl:for-each select="foaf:holdsAccount/foaf:OnlineAccount">
384 <dd>
385 <xsl:choose>
386 <xsl:when test="@rdf:about">
387 <xsl:element name="uri">
388 <xsl:attribute name="link"><xsl:value-of select="@rdf:about"/></xsl:attribute>
389 <xsl:value-of select="foaf:accountName"/>
390 <xsl:text> - </xsl:text>
391 <xsl:value-of select="foaf:accountServiceHomepage/@rdf:resource"/>
392 </xsl:element>
393 </xsl:when>
394 <xsl:otherwise>
395 <xsl:value-of select="foaf:accountName"/>
396 <xsl:text> - </xsl:text>
397 <xsl:element name="uri">
398 <xsl:attribute name="link"><xsl:value-of select="foaf:accountProfilePage/@rdf:resource"/></xsl:attribute>
399 <xsl:value-of select="foaf:accountProfilePage/@rdf:resource"/>
400 </xsl:element>
401 </xsl:otherwise>
402 </xsl:choose>
403 </dd>
404 </xsl:for-each>
405
406 </xsl:if>
407 <xsl:for-each select="foaf:depiction">
408 <dt>Photos : </dt>
409 <dd>
410 <xsl:element name="img">
411 <xsl:attribute name="src">
412 <xsl:value-of select="@rdf:resource"/>
413 </xsl:attribute>
414 <xsl:value-of select="@rdf:resource"/>
415 </xsl:element>
416 </dd>
417 </xsl:for-each>
418 </dl>
419 </xsl:for-each>
420 </body>
421 </section>
422 </chapter>
423 </guide>
424 </xsl:template>
425 </xsl:stylesheet>
426 '''
427