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 Sept. 9, 2013, 9:25 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
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 from collections import OrderedDict
24
25 from packager import readMetadata, getDefaultFileName, getBuildVersion, getTempl ate, Files
26 from buildtools.packagerChrome import convertJS, importGeckoLocales, getIgnoredF iles, getPackageFiles, ImageConverter
27
28 def createPlist(params, files):
29 template = getTemplate('Info.plist.tmpl')
30 metadata = params['metadata']
31 catalog = json.loads(files['_locales/en_US/messages.json'])
32
33 def parse_section(section, depth=1):
34 rv = {}
35
36 if not metadata.has_section(section):
37 return rv
38
39 for opt in metadata.options(section):
40 bits = opt.split('_', depth)
41 key = bits.pop(-1).replace('_', ' ').title()
42 d = rv
43
44 for x in bits:
45 d = d.setdefault(x, {})
46
47 val = metadata.get(section, opt)
48
49 try:
50 float(val)
51 except ValueError:
52 type = 'string'
53 else:
54 type = 'real'
55
56 d[key] = '<%s>%s</%s>' % (type, val, type)
57
58 return rv
59
60 def get_optional(*args):
61 try:
62 return metadata.get(*args)
63 except ConfigParser.Error:
64 return None
65
66 allowedDomains = set()
67 allowAllDomains = False
68 allowSecurePages = False
69
70 for perm in re.split(r'\s+', metadata.get('general', 'permissions')):
71 if perm == '<all_urls>':
72 allowAllDomains = True
73 allowSecurePages = True
74 continue
75
76 url = urlparse(perm)
77
78 if url.scheme == 'https':
79 allowSecurePages = True
80 elif url.scheme != 'http':
81 continue
82
83 if '*' in url.hostname:
84 allowAllDomains = True
85 continue
86
87 allowedDomains.add(url.hostname)
88
89 return template.render(
90 version=params['version'],
91 name=catalog['name']['message'],
92 description=catalog['description']['message'],
93 author=get_optional('general', 'author'),
94 website=get_optional('general', 'website'),
95 updateURL=get_optional('general', 'updateURL'),
96 identifier=metadata.get('general', 'identifier'),
97 allowedDomains=allowedDomains,
98 allowAllDomains=allowAllDomains,
99 allowSecurePages=allowSecurePages,
100 contentScripts={
101 'start': metadata.get('contentScripts', 'document_start').split(),
102 'end': metadata.get('contentScripts', 'document_end' ).split(),
103 },
104 menus=parse_section('menus', 2),
105 toolbarItems=parse_section('toolbar_items'),
106 popovers=parse_section('popovers')
107 ).encode('utf-8')
108
109 def createBackgroundPage(params):
110 template = getTemplate('background.html.tmpl')
111 return template.render(
112 backgroundScripts=re.split(r'\s+', params['metadata'].get(
113 'general', 'backgroundScripts'
114 ))
115 ).encode('utf-8')
116
117 def createInfoModule(params):
118 template = getTemplate('safariInfo.js.tmpl')
119 return template.render(params).encode('utf-8');
120
121 def createSignedXarArchive(outFile, files, keyFile, certs):
122 import subprocess
123 import tempfile
124 import shutil
125 import errno
126 import M2Crypto
127
128 # write files to temporary directory and create a xar archive
129 dirname = tempfile.mkdtemp()
130 try:
131 for filename, contents in files.iteritems():
132 path = os.path.join(dirname, filename)
133
134 while True:
135 try:
136 file = open(path, 'wb')
137 break
138 except IOError, e:
139 if e.errno != errno.ENOENT:
140 raise
141 os.makedirs(os.path.dirname(path))
Sebastian Noack 2013/09/10 12:40:43 This uses exactly the same amount of lines of code
142
143 with file:
144 file.write(contents)
145
146 subprocess.check_output(
147 ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(d irname),
148 cwd=dirname
149 )
150 finally:
151 shutil.rmtree(dirname)
152
153 # add placeholder signature and certificates to the xar archive, and get data to sign
154 key = M2Crypto.RSA.load_key(keyFile)
155 digestinfo_filename = tempfile.mktemp()
156 try:
157 subprocess.check_call(
158 [
159 'xar', '--sign', '-f', outFile,
160 '--digestinfo-to-sign', digestinfo_filename,
161 '--sig-size', str(len(key.sign('')))
162 ] + [
163 arg for cert in certs for arg in ('--cert-loc', cert)
164 ]
165 )
166
167 with open(digestinfo_filename, 'rb') as file:
168 digestinfo = file.read()
169 finally:
170 try:
171 os.unlink(digestinfo_filename)
172 except OSError, e:
173 if e.errno != errno.ENOENT:
174 raise
175
176 # sign data and inject signature into xar archive
177 fd, signature_filename = tempfile.mkstemp()
Wladimir Palant 2013/09/10 14:02:12 You are right, my comment was wishful thinking, no
178 try:
179 try:
180 os.write(fd, key.private_encrypt(
181 digestinfo,
182 M2Crypto.RSA.pkcs1_padding
183 ))
184 finally:
185 os.close(fd)
186
187 subprocess.check_call(['xar', '--inject-sig', signature_filename, '-f', outF ile])
188 finally:
189 os.unlink(signature_filename)
190
191 def createBuild(baseDir, type, outFile=None, buildNum=None, releaseBuild=False, keyFile=None, certs=()):
192 metadata = readMetadata(baseDir, type)
193 version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum)
194
195 if not outFile:
196 outFile = getDefaultFileName(baseDir, metadata, version, 'safariextz' if key File else 'zip')
197
198 params = {
199 'type': type,
200 'baseDir': baseDir,
201 'releaseBuild': releaseBuild,
202 'version': version,
203 'devenv': False,
204 'metadata': metadata,
205 }
206
207 files = Files(getPackageFiles(params), getIgnoredFiles(params),
208 process=lambda path, data: data)
209 if metadata.has_section('mapping'):
210 files.readMappedFiles(metadata.items('mapping'))
211 files.read(baseDir)
212
213 if metadata.has_section('convert_js'):
214 convertJS(params, files)
215
216 if metadata.has_section('convert_img'):
217 ImageConverter().convert(params, files)
218
219 if metadata.has_section('import_locales'):
220 importGeckoLocales(params, files)
221
222 files['lib/info.js'] = createInfoModule(params)
223 files['background.html'] = createBackgroundPage(params)
224 files['Info.plist'] = createPlist(params, files)
225
226 dirname = getDefaultFileName('', metadata, version, 'safariextension')
227 for filename in files.keys():
228 files[os.path.join(dirname, filename)] = files.pop(filename)
229
230 if keyFile:
231 createSignedXarArchive(outFile, files, keyFile, certs)
232 else:
233 files.zip(outFile)
OLDNEW

Powered by Google App Engine
This is Rietveld