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: Made first run page always generated, fix absolute URLs for Safari during build, introduced browser… Created Oct. 31, 2013, 10:48 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 | « packagerGecko.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, importGeckoLocales, getIgnoredFiles, getPa ckageFiles, 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_safari']['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 fixAbsoluteUrls(files):
120 for filename, content in files.iteritems():
121 if os.path.splitext(filename)[1].lower() == '.html':
122 prefix = '/'.join(['..'] * filename.count('/') + [''])
123 files[filename] = re.sub(
124 r'(<.*?\b(?:href|src)\s*=\s*(["\']))(\/.*?)(?=\2.*?>)',
125 lambda m: '%s%s%s' % (m.group(1), prefix, m.group(3).lstrip('/')),
Wladimir Palant 2013/10/31 13:58:19 Why look for the entire tag if all you need is the
126 content, re.S | re.I
127 )
128
129 def createSignedXarArchive(outFile, files, keyFile):
130 import subprocess
131 import tempfile
132 import shutil
133 import M2Crypto
134
135 # write files to temporary directory and create a xar archive
136 dirname = tempfile.mkdtemp()
137 try:
138 for filename, contents in files.iteritems():
139 path = os.path.join(dirname, filename)
140
141 try:
142 os.makedirs(os.path.dirname(path))
143 except OSError:
144 pass
145
146 with open(path, 'wb') as file:
147 file.write(contents)
148
149 subprocess.check_output(
150 ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(d irname),
151 cwd=dirname
152 )
153 finally:
154 shutil.rmtree(dirname)
155
156 certificate_filenames = []
157 try:
158 # load key and certificates from the all-in-one key file
159 # and write each certificate in DER format to a seperate
160 # temporary file, that they can be passed to xar
161 bio = M2Crypto.BIO.openfile(keyFile)
162 try:
163 key = M2Crypto.RSA.load_key_bio(bio)
164
165 bio.reset()
166 while True:
167 try:
168 cert = M2Crypto.X509.load_cert_bio(bio)
169 except M2Crypto.X509.X509Error:
170 break
171
172 fd, filename = tempfile.mkstemp()
173 try:
174 certificate_filenames.append(filename)
175 os.write(fd, cert.as_der())
176 finally:
177 os.close(fd)
178 finally:
179 bio.close()
180
181 # add certificates and placeholder signature
182 # to the xar archive, and get data to sign
183 fd, digestinfo_filename = tempfile.mkstemp()
184 os.close(fd)
185 try:
186 subprocess.check_call(
187 [
188 'xar', '--sign', '-f', outFile,
189 '--digestinfo-to-sign', digestinfo_filename,
190 '--sig-size', str(len(key.private_encrypt('', M2Crypto.RSA.pkcs1_paddi ng)))
191 ] + [
192 arg for cert in certificate_filenames for arg in ('--cert-loc', cert)
193 ]
194 )
195
196 with open(digestinfo_filename, 'rb') as file:
197 digestinfo = file.read()
198 finally:
199 os.unlink(digestinfo_filename)
200 finally:
201 for filename in certificate_filenames:
202 os.unlink(filename)
203
204 # sign data and inject signature into xar archive
205 fd, signature_filename = tempfile.mkstemp()
206 try:
207 try:
208 os.write(fd, key.private_encrypt(
209 digestinfo,
210 M2Crypto.RSA.pkcs1_padding
211 ))
212 finally:
213 os.close(fd)
214
215 subprocess.check_call(['xar', '--inject-sig', signature_filename, '-f', outF ile])
216 finally:
217 os.unlink(signature_filename)
218
219 def createBuild(baseDir, type, outFile=None, buildNum=None, releaseBuild=False, keyFile=None):
220 metadata = readMetadata(baseDir, type)
221 version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum)
222
223 if not outFile:
224 outFile = getDefaultFileName(baseDir, metadata, version, 'safariextz' if key File else 'zip')
225
226 params = {
227 'type': type,
228 'baseDir': baseDir,
229 'releaseBuild': releaseBuild,
230 'version': version,
231 'devenv': False,
232 'metadata': metadata,
233 }
234
235 files = Files(getPackageFiles(params), getIgnoredFiles(params),
236 process=lambda path, data: processFile(path, data, params))
237 if metadata.has_section('mapping'):
238 files.readMappedFiles(metadata.items('mapping'))
239 files.read(baseDir)
240
241 if metadata.has_section('convert_js'):
242 convertJS(params, files)
243
244 if metadata.has_section('convert_img'):
245 from imageConversion import convertImages
246 convertImages(params, files)
247
248 if metadata.has_section('preprocess'):
249 files.preprocess(
250 [f for f, _ in metadata.items('preprocess')],
251 {'needsExt': True}
252 )
253
254 if metadata.has_section('import_locales'):
255 importGeckoLocales(params, files)
256
257 files['lib/info.js'] = createInfoModule(params)
258 files['background.html'] = createBackgroundPage(params)
259 files['Info.plist'] = createManifest(params, files)
260
261 fixAbsoluteUrls(files)
262
263 dirname = metadata.get('general', 'basename') + '.safariextension'
264 for filename in files.keys():
265 files[os.path.join(dirname, filename)] = files.pop(filename)
266
267 if keyFile:
268 createSignedXarArchive(outFile, files, keyFile)
269 else:
270 files.zip(outFile)
OLDNEW
« no previous file with comments | « packagerGecko.py ('k') | safariInfo.js.tmpl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld