Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: packagerSafari.py

Issue 11544056: Prepared buildtools for Safari (Closed)
Patch Set: Created Oct. 16, 2013, 9:44 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « packagerChrome.py ('k') | safariInfo.js.tmpl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # coding: utf-8
2
3 # This file is part of the Adblock Plus build tools,
4 # Copyright (C) 2006-2013 Eyeo GmbH
5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation.
9 #
10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
17
18 import os
19 import re
20 import json
21 import ConfigParser
22 from urlparse import urlparse
23
24 from packager import readMetadata, getDefaultFileName, getBuildVersion, getTempl ate, Files
25 from packagerChrome import convertJS, convertFirstRunPage, importGeckoLocales, g etIgnoredFiles, getPackageFiles, defaultLocale
26
27 def processFile(path, data, params):
28 return data
29
30 def createManifest(params, files):
31 template = getTemplate('Info.plist.tmpl', autoEscape=True)
32 metadata = params['metadata']
33 catalog = json.loads(files['_locales/%s/messages.json' % defaultLocale])
34
35 def parse_section(section, depth=1):
36 result = {}
37
38 if not metadata.has_section(section):
39 return result
40
41 for opt in metadata.options(section):
42 bits = opt.split('_', depth)
43 key = bits.pop().replace('_', ' ').title()
44 val = metadata.get(section, opt)
45
46 try:
47 val = int(val)
48 except ValueError:
49 try:
50 val = float(val)
51 except ValueError:
52 pass
53
54 reduce(lambda d, x: d.setdefault(x, {}), bits, result)[key] = val
55
56 return result
57
58 def get_optional(*args):
59 try:
60 return metadata.get(*args)
61 except ConfigParser.Error:
62 return None
63
64 allowedDomains = set()
65 allowAllDomains = False
66 allowSecurePages = False
67
68 for perm in metadata.get('general', 'permissions').split():
69 if perm == '<all_urls>':
70 allowAllDomains = True
71 allowSecurePages = True
72 continue
73
74 url = urlparse(perm)
75
76 if url.scheme == 'https':
77 allowSecurePages = True
78 elif url.scheme != 'http':
79 continue
80
81 if '*' in url.hostname:
82 allowAllDomains = True
83 continue
84
85 allowedDomains.add(url.hostname)
86
87 return template.render(
88 basename=metadata.get('general', 'basename'),
89 version=params['version'],
90 shortVersion=metadata.get('general', 'version'),
91 releaseBuild=params['releaseBuild'],
92 name=catalog['name']['message'],
93 description=catalog['description']['message'],
94 author=get_optional('general', 'author'),
95 homepage=get_optional('general', 'homepage'),
96 updateURL=get_optional('general', 'updateURL'),
97 allowedDomains=allowedDomains,
98 allowAllDomains=allowAllDomains,
99 allowSecurePages=allowSecurePages,
100 startScripts=(get_optional('contentScripts', 'document_start') or '').split( ),
101 endScripts=(get_optional('contentScripts', 'document_end') or '').split(),
102 menus=parse_section('menus', 2),
103 toolbarItems=parse_section('toolbar_items'),
104 popovers=parse_section('popovers')
105 ).encode('utf-8')
106
107 def createBackgroundPage(params):
108 template = getTemplate('background.html.tmpl', autoEscape=True)
109 return template.render(
110 backgroundScripts=params['metadata'].get(
111 'general', 'backgroundScripts'
112 ).split()
113 ).encode('utf-8')
114
115 def createInfoModule(params):
116 template = getTemplate('safariInfo.js.tmpl')
117 return template.render(params).encode('utf-8');
118
119 def createSignedXarArchive(outFile, files, keyFile):
120 import subprocess
121 import tempfile
122 import shutil
123 import M2Crypto
124
125 # write files to temporary directory and create a xar archive
126 dirname = tempfile.mkdtemp()
127 try:
128 for filename, contents in files.iteritems():
129 path = os.path.join(dirname, filename)
130
131 try:
132 os.makedirs(os.path.dirname(path))
133 except OSError:
134 pass
135
136 with open(path, 'wb') as file:
137 file.write(contents)
138
139 subprocess.check_output(
140 ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(d irname),
141 cwd=dirname
142 )
143 finally:
144 shutil.rmtree(dirname)
145
146 certificate_filenames = []
147 try:
148 # load key and certificates from the all-in-one key file
149 # and write each certificate in DER format to a seperate
150 # temporary file, that they can be passed to xar
151 bio = M2Crypto.BIO.openfile(keyFile)
152 try:
153 key = M2Crypto.RSA.load_key_bio(bio)
154
155 bio.reset()
156 while True:
157 try:
158 cert = M2Crypto.X509.load_cert_bio(bio)
159 except M2Crypto.X509.X509Error:
160 break
161
162 fd, filename = tempfile.mkstemp()
163 try:
164 certificate_filenames.append(filename)
165 os.write(fd, cert.as_der())
166 finally:
167 os.close(fd)
168 finally:
169 bio.close()
170
171 # add certificates and placeholder signature
172 # to the xar archive, and get data to sign
173 fd, digestinfo_filename = tempfile.mkstemp()
174 os.close(fd)
175 try:
176 subprocess.check_call(
177 [
178 'xar', '--sign', '-f', outFile,
179 '--digestinfo-to-sign', digestinfo_filename,
180 '--sig-size', str(len(key.private_encrypt('', M2Crypto.RSA.pkcs1_paddi ng)))
181 ] + [
182 arg for cert in certificate_filenames for arg in ('--cert-loc', cert)
183 ]
184 )
185
186 with open(digestinfo_filename, 'rb') as file:
187 digestinfo = file.read()
188 finally:
189 os.unlink(digestinfo_filename)
190 finally:
191 for filename in certificate_filenames:
192 os.unlink(filename)
193
194 # sign data and inject signature into xar archive
195 fd, signature_filename = tempfile.mkstemp()
196 try:
197 try:
198 os.write(fd, key.private_encrypt(
199 digestinfo,
200 M2Crypto.RSA.pkcs1_padding
201 ))
202 finally:
203 os.close(fd)
204
205 subprocess.check_call(['xar', '--inject-sig', signature_filename, '-f', outF ile])
206 finally:
207 os.unlink(signature_filename)
208
209 def createBuild(baseDir, type, outFile=None, buildNum=None, releaseBuild=False, keyFile=None):
210 metadata = readMetadata(baseDir, type)
211 version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum)
212
213 if not outFile:
214 outFile = getDefaultFileName(baseDir, metadata, version, 'safariextz' if key File else 'zip')
215
216 params = {
217 'type': type,
218 'baseDir': baseDir,
219 'releaseBuild': releaseBuild,
220 'version': version,
221 'devenv': False,
222 'metadata': metadata,
223 }
224
225 files = Files(getPackageFiles(params), getIgnoredFiles(params),
226 process=lambda path, data: processFile(path, data, params))
227 if metadata.has_section('mapping'):
228 files.readMappedFiles(metadata.items('mapping'))
229 files.read(baseDir)
230
231 if metadata.has_section('convert_js'):
232 convertJS(params, files)
233
234 if metadata.has_section('convert_img'):
235 from imageConversion import convertImages
236 convertImages(params, files)
237
238 if 'firstRun.html' in files:
239 convertFirstRunPage(params, files)
240
241 if metadata.has_section('import_locales'):
242 importGeckoLocales(params, files)
243
244 files['lib/info.js'] = createInfoModule(params)
245 files['background.html'] = createBackgroundPage(params)
246 files['Info.plist'] = createManifest(params, files)
247
248 dirname = metadata.get('general', 'basename') + '.safariextension'
249 for filename in files.keys():
250 files[os.path.join(dirname, filename)] = files.pop(filename)
251
252 if keyFile:
253 createSignedXarArchive(outFile, files, keyFile)
254 else:
255 files.zip(outFile)
OLDNEW
« no previous file with comments | « packagerChrome.py ('k') | safariInfo.js.tmpl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld