Ensure icon in /tmp is removed on exit.
[AddApp.git] / AddApp / launcher.py
blobe0a7053a702a0ec285f2b0408c507ef2218199dc
1 from zeroinstall.injector import policy
2 import os, shutil
3 import rox
4 from rox import saving
5 from xml.dom import minidom
6 import urllib2
7 import tempfile, shutil
9 addapp_uri = "http://rox.sourceforge.net/2005/interfaces/AddApp"
11 class Policy(policy.Policy):
12 pass
14 class AppLauncher(saving.Saveable):
15 def __init__(self, uri):
16 self.uri = uri
17 self.icon = None
19 self.policy = Policy(uri)
20 self.policy.recalculate()
21 iface = self.policy.get_interface(uri)
22 if not iface.main:
23 rox.alert("Interface '%s' cannot be executed directly; it is just a library "
24 "to be used by other programs (or missing 'main' attribute on the "
25 "root <interface> element)." % iface.name)
27 def save_to_file(self, path):
28 os.mkdir(path)
29 assert "'" not in self.uri
30 apprun = os.fdopen(os.open(os.path.join(path, 'AppRun'), os.O_CREAT | os.O_WRONLY, 0777), 'w')
31 if self.uri == 'http://rox.sourceforge.net/2005/interfaces/AddApp':
32 # Funky special case: AddApp behaves differently when run through AppRun
33 apprun.write("""#!/bin/sh
34 if [ "$*" = "--versions" ]; then
35 exec 0launch -gd '%s' "$@"
36 elif [ "$*" = "" ]; then
37 exec 0launch '%s' --prompt
38 elif [ "$*" = "--help" ]; then
39 exec 0launch '%s' --show-help '%s'
40 else
41 exec 0launch '%s' "$@"
42 fi""" % (self.uri, self.uri, addapp_uri, self.uri, self.uri))
43 else:
44 apprun.write("""#!/bin/sh
45 if [ "$*" = "--versions" ]; then
46 exec 0launch -gd '%s' "$@"
47 elif [ "$*" = "--help" ]; then
48 exec 0launch '%s' --show-help '%s'
49 else
50 exec 0launch '%s' "$@"
51 fi""" % (self.uri, addapp_uri, self.uri, self.uri))
53 apprun.close()
54 if self.icon:
55 shutil.copyfile(self.icon.name, os.path.join(path, '.DirIcon'))
57 iface = self.policy.get_interface(self.uri)
58 if iface.name and iface.summary and \
59 isinstance(iface.name, basestring) and \
60 isinstance(iface.summary, basestring):
61 tooltip = ''.join([iface.name, " -- ", iface.summary,
62 "\n(", self.uri, ")"])
63 elif iface.name and isinstance(iface.name, basestring):
64 tooltip = ''.join([iface.name, " (", self.uri, ")"])
65 else:
66 tooltip = self.uri
68 doc = minidom.parseString("""<?xml version="1.0"?>
69 <AppInfo>
70 <AppMenu>
71 <Item option='--help'>
72 <Label xml:lang="en">Help</Label>
73 </Item>
74 <Item option='--versions'>
75 <Label xml:lang="en">Versions...</Label>
76 </Item>
77 </AppMenu>
78 <Summary xml:lang="en"/>
79 </AppInfo>
80 """)
81 summary, = doc.documentElement.getElementsByTagName('Summary')
82 summary.appendChild(doc.createTextNode(tooltip))
83 info_file = file(os.path.join(path, 'AppInfo.xml'), 'w')
84 doc.writexml(info_file)
85 info_file.close()
87 def get_icon(self):
88 """Returns a GdkPixbuf icon for the app (downloading it first), or None."""
89 from zeroinstall.injector import reader, model, basedir, namespaces
90 cached = basedir.load_first_cache(namespaces.config_site, 'interfaces', model.escape(self.uri))
91 if not cached:
92 print >>sys.stderr, "Internal error: interface '%s' still not cached!" % self.uri
93 return None
94 from xml.dom import minidom
95 doc = minidom.parse(cached)
96 names = doc.documentElement.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'icon')
97 for x in names:
98 type = x.getAttribute('type')
99 if str(type) != 'image/png':
100 print "Skipping unknown icon type '%s'" % type
101 continue
102 icon_uri = x.getAttribute('href')
103 print "Downloading icon from", icon_uri
104 try:
105 icon_data = urllib2.urlopen(icon_uri)
106 except:
107 rox.report_exception()
108 return
109 tmp = tempfile.NamedTemporaryFile()
110 shutil.copyfileobj(icon_data, tmp)
111 icon_data.close()
112 tmp.flush()
114 self.icon = tmp
116 def delete_icon(self):
117 """Remove the temporary icon file, if any"""
118 self.icon = None