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