Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 import os
6 import xml.dom.minidom
7 import StringIO
9 RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
10 EM_NS = "http://www.mozilla.org/2004/em-rdf#"
12 class RDF(object):
13 def __str__(self):
14 # real files have an .encoding attribute and use it when you
15 # write() unicode into them: they read()/write() unicode and
16 # put encoded bytes in the backend file. StringIO objects
17 # read()/write() unicode and put unicode in the backing store,
18 # so we must encode the output of getvalue() to get a
19 # bytestring. (cStringIO objects are weirder: they effectively
20 # have .encoding hardwired to "ascii" and put only bytes in
21 # the backing store, so we can't use them here).
22 #
23 # The encoding= argument to dom.writexml() merely sets the XML header's
24 # encoding= attribute. It still writes unencoded unicode to the output file,
25 # so we have to encode it for real afterwards.
26 #
27 # Also see: https://bugzilla.mozilla.org/show_bug.cgi?id=567660
29 buf = StringIO.StringIO()
30 self.dom.writexml(buf, encoding="utf-8")
31 return buf.getvalue().encode('utf-8')
33 class RDFUpdate(RDF):
34 def __init__(self):
35 impl = xml.dom.minidom.getDOMImplementation()
36 self.dom = impl.createDocument(RDF_NS, "RDF", None)
37 self.dom.documentElement.setAttribute("xmlns", RDF_NS)
38 self.dom.documentElement.setAttribute("xmlns:em", EM_NS)
40 def _make_node(self, name, value, parent):
41 elem = self.dom.createElement(name)
42 elem.appendChild(self.dom.createTextNode(value))
43 parent.appendChild(elem)
44 return elem
46 def add(self, manifest, update_link):
47 desc = self.dom.createElement("Description")
48 desc.setAttribute(
49 "about",
50 "urn:mozilla:extension:%s" % manifest.get("em:id")
51 )
52 self.dom.documentElement.appendChild(desc)
54 updates = self.dom.createElement("em:updates")
55 desc.appendChild(updates)
57 seq = self.dom.createElement("Seq")
58 updates.appendChild(seq)
60 li = self.dom.createElement("li")
61 seq.appendChild(li)
63 li_desc = self.dom.createElement("Description")
64 li.appendChild(li_desc)
66 self._make_node("em:version", manifest.get("em:version"),
67 li_desc)
69 apps = manifest.dom.documentElement.getElementsByTagName(
70 "em:targetApplication"
71 )
73 for app in apps:
74 target_app = self.dom.createElement("em:targetApplication")
75 li_desc.appendChild(target_app)
77 ta_desc = self.dom.createElement("Description")
78 target_app.appendChild(ta_desc)
80 for name in ["em:id", "em:minVersion", "em:maxVersion"]:
81 elem = app.getElementsByTagName(name)[0]
82 self._make_node(name, elem.firstChild.nodeValue, ta_desc)
84 self._make_node("em:updateLink", update_link, ta_desc)
86 class RDFManifest(RDF):
87 def __init__(self, path):
88 self.dom = xml.dom.minidom.parse(path)
90 def set(self, property, value):
91 elements = self.dom.documentElement.getElementsByTagName(property)
92 if not elements:
93 raise ValueError("Element with value not found: %s" % property)
94 if not elements[0].firstChild:
95 elements[0].appendChild(self.dom.createTextNode(value))
96 else:
97 elements[0].firstChild.nodeValue = value
99 def get(self, property, default=None):
100 elements = self.dom.documentElement.getElementsByTagName(property)
101 if not elements:
102 return default
103 return elements[0].firstChild.nodeValue
105 def remove(self, property):
106 elements = self.dom.documentElement.getElementsByTagName(property)
107 if not elements:
108 return True
109 else:
110 for i in elements:
111 i.parentNode.removeChild(i);
113 return True;
115 def gen_manifest(template_root_dir, target_cfg, jid,
116 update_url=None, bootstrap=True, enable_mobile=False):
117 install_rdf = os.path.join(template_root_dir, "install.rdf")
118 manifest = RDFManifest(install_rdf)
119 dom = manifest.dom
121 manifest.set("em:id", jid)
122 manifest.set("em:version",
123 target_cfg.get('version', '1.0'))
124 manifest.set("em:name",
125 target_cfg.get('title', target_cfg.get('fullName', target_cfg['name'])))
126 manifest.set("em:description",
127 target_cfg.get("description", ""))
128 manifest.set("em:creator",
129 target_cfg.get("author", ""))
130 manifest.set("em:bootstrap", str(bootstrap).lower())
131 # XPIs remain packed by default, but package.json can override that. The
132 # RDF format accepts "true" as True, anything else as False. We expect
133 # booleans in the .json file, not strings.
134 manifest.set("em:unpack", "true" if target_cfg.get("unpack") else "false")
136 for translator in target_cfg.get("translators", [ ]):
137 elem = dom.createElement("em:translator");
138 elem.appendChild(dom.createTextNode(translator))
139 dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem)
141 for contributor in target_cfg.get("contributors", [ ]):
142 elem = dom.createElement("em:contributor");
143 elem.appendChild(dom.createTextNode(contributor))
144 dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem)
146 if update_url:
147 manifest.set("em:updateURL", update_url)
148 else:
149 manifest.remove("em:updateURL")
151 if target_cfg.get("preferences"):
152 manifest.set("em:optionsType", "2")
153 else:
154 manifest.remove("em:optionsType")
156 if enable_mobile:
157 target_app = dom.createElement("em:targetApplication")
158 dom.documentElement.getElementsByTagName("Description")[0].appendChild(target_app)
160 ta_desc = dom.createElement("Description")
161 target_app.appendChild(ta_desc)
163 elem = dom.createElement("em:id")
164 elem.appendChild(dom.createTextNode("{aa3c5121-dab2-40e2-81ca-7ea25febc110}"))
165 ta_desc.appendChild(elem)
167 elem = dom.createElement("em:minVersion")
168 elem.appendChild(dom.createTextNode("26.0"))
169 ta_desc.appendChild(elem)
171 elem = dom.createElement("em:maxVersion")
172 elem.appendChild(dom.createTextNode("30.0a1"))
173 ta_desc.appendChild(elem)
175 if target_cfg.get("homepage"):
176 manifest.set("em:homepageURL", target_cfg.get("homepage"))
177 else:
178 manifest.remove("em:homepageURL")
180 return manifest
182 if __name__ == "__main__":
183 print "Running smoke test."
184 root = os.path.join(os.path.dirname(__file__), '../../app-extension')
185 manifest = gen_manifest(root, {'name': 'test extension'},
186 'fakeid', 'http://foo.com/update.rdf')
187 update = RDFUpdate()
188 update.add(manifest, "https://foo.com/foo.xpi")
189 exercise_str = str(manifest) + str(update)
190 for tagname in ["em:targetApplication", "em:version", "em:id"]:
191 if not len(update.dom.getElementsByTagName(tagname)):
192 raise Exception("tag does not exist: %s" % tagname)
193 if not update.dom.getElementsByTagName(tagname)[0].firstChild:
194 raise Exception("tag has no children: %s" % tagname)
195 print "Success!"