0
|
1 #! /usr/bin/env python
|
|
2
|
|
3 import os
|
|
4 import sys
|
|
5
|
|
6 if __name__ == '__main__':
|
|
7 # This code is run if we're executed directly from the command-line.
|
|
8
|
|
9 myfile = os.path.abspath(__file__)
|
|
10 mydir = os.path.dirname(myfile)
|
|
11 sys.path.insert(0, os.path.join(mydir, 'python-modules'))
|
|
12
|
|
13 args = sys.argv[1:]
|
|
14 if not args:
|
|
15 args = ['help']
|
|
16
|
|
17 # Have paver run this very file as its pavement script.
|
|
18 args = ['-f', myfile] + args
|
|
19
|
|
20 import paver.tasks
|
|
21 paver.tasks.main(args)
|
|
22 sys.exit(0)
|
|
23
|
|
24 # This code is run if we're executed as a pavement script by paver.
|
|
25
|
|
26 import os
|
|
27 import sys
|
|
28 import fnmatch
|
|
29 import distutils.dir_util
|
|
30 import xml.dom.minidom
|
|
31 import zipfile
|
|
32 import shutil
|
|
33 import distutils.dir_util
|
|
34 import time
|
|
35 import threading
|
|
36 import subprocess
|
|
37 import simplejson
|
|
38 from ConfigParser import ConfigParser
|
|
39
|
|
40 from paver.easy import *
|
|
41
|
|
42 # Path to the root of the extension, relative to where this script is
|
|
43 # located.
|
|
44 EXT_SUBDIR = "extension"
|
|
45
|
|
46 # Valid applications that this extension supports. The first one listed
|
|
47 # is the default used if one isn't explicitly provided on the command-line.
|
|
48 VALID_APPS = ['firefox', 'thunderbird']
|
|
49
|
|
50 # When launching a temporary new Firefox profile, use these preferences.
|
|
51 DEFAULT_FIREFOX_PREFS = {
|
|
52 'browser.startup.homepage' : 'about:blank',
|
|
53 'startup.homepage_welcome_url' : 'about:blank',
|
|
54 }
|
|
55
|
|
56 # When launching a temporary new Thunderbird profile, use these preferences.
|
|
57 # Note that these were taken from:
|
|
58 # http://mxr.mozilla.org/comm-central/source/mail/test/mozmill/runtest.py
|
|
59 DEFAULT_THUNDERBIRD_PREFS = {
|
|
60 # say yes to debug output via dump
|
|
61 'browser.dom.window.dump.enabled': True,
|
|
62 # say no to slow script warnings
|
|
63 'dom.max_chrome_script_run_time': 200,
|
|
64 'dom.max_script_run_time': 0,
|
|
65 # disable extension stuffs
|
|
66 'extensions.update.enabled' : False,
|
|
67 'extensions.update.notifyUser' : False,
|
|
68 # do not ask about being the default mail client
|
|
69 'mail.shell.checkDefaultClient': False,
|
|
70 # disable non-gloda indexing daemons
|
|
71 'mail.winsearch.enable': False,
|
|
72 'mail.winsearch.firstRunDone': True,
|
|
73 'mail.spotlight.enable': False,
|
|
74 'mail.spotlight.firstRunDone': True,
|
|
75 # disable address books for undisclosed reasons
|
|
76 'ldap_2.servers.osx.position': 0,
|
|
77 'ldap_2.servers.oe.position': 0,
|
|
78 # disable the first use junk dialog
|
|
79 'mailnews.ui.junk.firstuse': False,
|
|
80 # other unknown voodoo
|
|
81 # -- dummied up local accounts to stop the account wizard
|
|
82 'mail.account.account1.server' : "server1",
|
|
83 'mail.account.account2.identities' : "id1",
|
|
84 'mail.account.account2.server' : "server2",
|
|
85 'mail.accountmanager.accounts' : "account1,account2",
|
|
86 'mail.accountmanager.defaultaccount' : "account2",
|
|
87 'mail.accountmanager.localfoldersserver' : "server1",
|
|
88 'mail.identity.id1.fullName' : "Tinderbox",
|
|
89 'mail.identity.id1.smtpServer' : "smtp1",
|
|
90 'mail.identity.id1.useremail' : "tinderbox@invalid.com",
|
|
91 'mail.identity.id1.valid' : True,
|
|
92 'mail.root.none-rel' : "[ProfD]Mail",
|
|
93 'mail.root.pop3-rel' : "[ProfD]Mail",
|
|
94 'mail.server.server1.directory-rel' : "[ProfD]Mail/Local Folders",
|
|
95 'mail.server.server1.hostname' : "Local Folders",
|
|
96 'mail.server.server1.name' : "Local Folders",
|
|
97 'mail.server.server1.type' : "none",
|
|
98 'mail.server.server1.userName' : "nobody",
|
|
99 'mail.server.server2.check_new_mail' : False,
|
|
100 'mail.server.server2.directory-rel' : "[ProfD]Mail/tinderbox",
|
|
101 'mail.server.server2.download_on_biff' : True,
|
|
102 'mail.server.server2.hostname' : "tinderbox",
|
|
103 'mail.server.server2.login_at_startup' : False,
|
|
104 'mail.server.server2.name' : "tinderbox@invalid.com",
|
|
105 'mail.server.server2.type' : "pop3",
|
|
106 'mail.server.server2.userName' : "tinderbox",
|
|
107 'mail.smtp.defaultserver' : "smtp1",
|
|
108 'mail.smtpserver.smtp1.hostname' : "tinderbox",
|
|
109 'mail.smtpserver.smtp1.username' : "tinderbox",
|
|
110 'mail.smtpservers' : "smtp1",
|
|
111 'mail.startup.enabledMailCheckOnce' : True,
|
|
112 'mailnews.start_page_override.mstone' : "ignore",
|
|
113 }
|
|
114
|
|
115 PROFILE_DIRS = Bunch(
|
|
116 firefox = Bunch(
|
|
117 darwin = "~/Library/Application Support/Firefox/",
|
|
118 windows = "Mozilla\\Firefox",
|
|
119 linux = "~/.mozilla/firefox/"
|
|
120 ),
|
|
121 thunderbird = Bunch(
|
|
122 darwin = "~/Library/Thunderbird/",
|
|
123 windows = "Mozilla\\Thunderbird",
|
|
124 linux = "~/.thunderbird/"
|
|
125 )
|
|
126 )
|
|
127
|
|
128 def clear_dir(dirname):
|
|
129 if os.path.exists(dirname) and os.path.isdir(dirname):
|
|
130 shutil.rmtree(dirname)
|
|
131
|
|
132 def find_profile_dir(app, name):
|
|
133 """
|
|
134 Given the name of an application and its profile, attempts
|
|
135 to find the absolute path to its directory. If it can't be found,
|
|
136 None is returned.
|
|
137 """
|
|
138
|
|
139 base_path = None
|
|
140 if sys.platform == "darwin":
|
|
141 base_path = os.path.expanduser(PROFILE_DIRS[app].darwin)
|
|
142 elif (sys.platform.startswith("win") or
|
|
143 sys.platform == "cygwin"):
|
|
144 # TODO: This only works on 2000/XP/Vista, not 98/Me.
|
|
145 appdata = os.environ["APPDATA"]
|
|
146 base_path = os.path.join(appdata, PROFILE_DIRS[app].windows)
|
|
147 else:
|
|
148 base_path = os.path.expanduser(PROFILE_DIRS[app].linux)
|
|
149 inifile = os.path.join(base_path, "profiles.ini")
|
|
150 config = ConfigParser()
|
|
151 config.read(inifile)
|
|
152 profiles = [section for section in config.sections()
|
|
153 if section.startswith("Profile")]
|
|
154 for profile in profiles:
|
|
155 if config.get(profile, "Name") == name:
|
|
156 # TODO: Look at IsRelative?
|
|
157 path = config.get(profile, "Path")
|
|
158 if not os.path.isabs(path):
|
|
159 path = os.path.join(base_path, path)
|
|
160 return path
|
|
161 return None
|
|
162
|
|
163 def get_install_rdf_dom(path_to_ext_root):
|
|
164 rdf_path = os.path.join(path_to_ext_root, "install.rdf")
|
|
165 rdf = xml.dom.minidom.parse(rdf_path)
|
|
166 return rdf
|
|
167
|
|
168 def get_install_rdf_property(path_to_ext_root, property):
|
|
169 rdf = get_install_rdf_dom(path_to_ext_root)
|
|
170 element = rdf.documentElement.getElementsByTagName(property)[0]
|
|
171 return element.firstChild.nodeValue
|
|
172
|
|
173 def resolve_options(options, ext_subdir = EXT_SUBDIR):
|
|
174 if not options.get('app'):
|
|
175 options.app = VALID_APPS[0]
|
|
176 if not options.get('profile'):
|
|
177 options.profile = 'default'
|
|
178
|
|
179 if options.app not in VALID_APPS:
|
|
180 print "Unrecognized or unsupported application: %s." % options.app
|
|
181 sys.exit(1)
|
|
182
|
|
183 options.my_dir = os.path.dirname(os.path.abspath(options.pavement_file))
|
|
184 options.profile_dir = find_profile_dir(options.app, options.profile)
|
|
185 options.path_to_ext_root = os.path.join(options.my_dir, ext_subdir)
|
|
186
|
|
187 options.ext_id = get_install_rdf_property(options.path_to_ext_root,
|
|
188 "em:id")
|
|
189
|
|
190 options.ext_version = get_install_rdf_property(options.path_to_ext_root,
|
|
191 "em:version")
|
|
192
|
|
193 options.ext_name = get_install_rdf_property(options.path_to_ext_root,
|
|
194 "em:name")
|
|
195
|
|
196 if options.profile_dir:
|
|
197 options.extension_file = os.path.join(options.profile_dir,
|
|
198 "extensions",
|
|
199 options.ext_id)
|
|
200 # If cygwin, change the path to windows format so firefox can
|
|
201 # understand it.
|
|
202 if sys.platform == "cygwin":
|
|
203 # TODO: Will this work if path_to_ext_root has spaces in it?
|
|
204 file = 'cygpath.exe -w ' + options.path_to_ext_root
|
|
205 path = "".join(os.popen(file).readlines())
|
|
206 path = path.replace("\n", " ").rstrip()
|
|
207 options.firefox_path_to_ext_root = path
|
|
208 else:
|
|
209 options.firefox_path_to_ext_root = options.path_to_ext_root
|
|
210
|
|
211 def remove_extension(options):
|
|
212 if not (options.profile_dir and
|
|
213 os.path.exists(options.profile_dir) and
|
|
214 os.path.isdir(options.profile_dir)):
|
|
215 raise BuildFailure("Can't resolve profile directory; aborting.")
|
|
216
|
|
217 files_to_remove = ["compreg.dat", "xpti.dat"]
|
|
218 for filename in files_to_remove:
|
|
219 abspath = os.path.join(options.profile_dir, filename)
|
|
220 if os.path.exists(abspath):
|
|
221 os.remove(abspath)
|
|
222 if os.path.exists(options.extension_file):
|
|
223 if os.path.isdir(options.extension_file):
|
|
224 shutil.rmtree(options.extension_file)
|
|
225 else:
|
|
226 os.remove(options.extension_file)
|
|
227
|
|
228 APP_OPTION = ("app=", "a", "Application to use. Defaults to %s. "
|
|
229 "Valid choices are: %s." % (VALID_APPS[0],
|
|
230 ", ".join(VALID_APPS)))
|
|
231
|
|
232 INSTALL_OPTIONS = [("profile=", "p", "Profile name."),
|
|
233 APP_OPTION]
|
|
234 JSBRIDGE_OPTIONS = [("port=", "p", "Port to use for jsbridge communication."),
|
|
235 ("binary=", "b", "Path to application binary."),
|
|
236 APP_OPTION]
|
|
237
|
|
238 @task
|
|
239 @cmdopts(INSTALL_OPTIONS)
|
|
240 def install(options):
|
|
241 """Install the extension to an application profile."""
|
|
242
|
|
243 resolve_options(options)
|
|
244 remove_extension(options)
|
|
245
|
|
246 extdir = os.path.dirname(options.extension_file)
|
|
247 if not os.path.exists(extdir):
|
|
248 distutils.dir_util.mkpath(extdir)
|
|
249 fileobj = open(options.extension_file, "w")
|
|
250 fileobj.write(options.firefox_path_to_ext_root)
|
|
251 fileobj.close()
|
|
252
|
|
253 copy_libs(options)
|
|
254
|
|
255 print "Extension '%s' installed to %s profile '%s'." % (options.ext_id,
|
|
256 options.app,
|
|
257 options.profile)
|
|
258
|
|
259 @task
|
|
260 @cmdopts(INSTALL_OPTIONS)
|
|
261 def uninstall(options):
|
|
262 """Uninstall the extension from an application profile."""
|
|
263
|
|
264 resolve_options(options)
|
|
265 remove_extension(options)
|
|
266 print "Extension '%s' uninstalled from %s profile '%s'." % (options.ext_id,
|
|
267 options.app,
|
|
268 options.profile)
|
|
269
|
|
270 @task
|
|
271 def xpi(options):
|
|
272 """Build a distributable xpi installer for the extension."""
|
|
273
|
|
274 resolve_options(options)
|
|
275
|
|
276 platforms = os.listdir(os.path.join(options.my_dir, "lib"))
|
|
277
|
|
278 for platform in platforms:
|
|
279 zfname = "%s-%s-%s.xpi" % (options.ext_name.lower(),
|
|
280 options.ext_version,
|
|
281 platform)
|
|
282 copy_libs(options, platform)
|
|
283 zf = zipfile.ZipFile(zfname, "w", zipfile.ZIP_DEFLATED)
|
|
284 for dirpath, dirnames, filenames in os.walk(options.path_to_ext_root):
|
|
285 if platform in dirnames:
|
|
286 # We're in the extension/platform directory, get rid of files for
|
|
287 # other platforms.
|
|
288 dirnames[:] = [platform]
|
|
289 for filename in filenames:
|
|
290 abspath = os.path.join(dirpath, filename)
|
|
291 arcpath = abspath[len(options.path_to_ext_root)+1:]
|
|
292 zf.write(abspath, arcpath)
|
|
293 print "Created %s." % zfname
|
|
294
|
|
295 def start_jsbridge(options):
|
|
296 import mozrunner
|
|
297 import jsbridge
|
|
298
|
|
299 resolve_options(options)
|
|
300
|
|
301 if not options.get('port'):
|
|
302 options.port = '24242'
|
|
303 options.port = int(options.port)
|
|
304 options.binary = options.get('binary')
|
|
305
|
|
306 plugins = [jsbridge.extension_path, options.path_to_ext_root]
|
|
307 if options.app == 'firefox':
|
|
308 profile_class = mozrunner.FirefoxProfile
|
|
309 preferences = DEFAULT_FIREFOX_PREFS
|
|
310 runner_class = mozrunner.FirefoxRunner
|
|
311 elif options.app == 'thunderbird':
|
|
312 profile_class = mozrunner.ThunderbirdProfile
|
|
313 preferences = DEFAULT_THUNDERBIRD_PREFS
|
|
314 runner_class = mozrunner.ThunderbirdRunner
|
|
315
|
|
316 profile = profile_class(plugins=plugins, preferences=preferences)
|
|
317 runner = runner_class(profile=profile,
|
|
318 binary=options.binary,
|
|
319 cmdargs=["-jsbridge", str(options.port)])
|
|
320 runner.start()
|
|
321
|
|
322 back_channel, bridge = jsbridge.wait_and_create_network("127.0.0.1",
|
|
323 options.port)
|
|
324
|
|
325 return Bunch(back_channel = back_channel,
|
|
326 bridge = bridge,
|
|
327 runner = runner)
|
|
328
|
|
329 def start_jetpack(options, listener):
|
|
330 remote = start_jsbridge(options)
|
|
331
|
|
332 import jsbridge
|
|
333
|
|
334 code = (
|
|
335 "((function() { var extension = {}; "
|
|
336 "Components.utils.import('resource://jetpack/modules/init.js', "
|
|
337 "extension); return extension; })())"
|
|
338 )
|
|
339
|
|
340 remote.back_channel.add_global_listener(listener)
|
|
341 extension = jsbridge.JSObject(remote.bridge, code)
|
|
342
|
|
343 INTERVAL = 0.1
|
|
344 MAX_STARTUP_TIME = 5.0
|
|
345
|
|
346 is_done = False
|
|
347 time_elapsed = 0.0
|
|
348
|
|
349 try:
|
|
350 while not is_done:
|
|
351 time.sleep(INTERVAL)
|
|
352 time_elapsed += INTERVAL
|
|
353
|
|
354 if time_elapsed > MAX_STARTUP_TIME:
|
|
355 raise Exception('Maximum startup time exceeded.')
|
|
356
|
|
357 url = 'chrome://jetpack/content/index.html'
|
|
358 window = extension.get(url)
|
|
359 if window is None:
|
|
360 #print "Waiting for index to load."
|
|
361 continue
|
|
362 if hasattr(window, 'frameElement'):
|
|
363 #print "Window is in an iframe."
|
|
364 continue
|
|
365 if window.closed:
|
|
366 #print "Window is closed."
|
|
367 continue
|
|
368 if not hasattr(window, 'JSBridge'):
|
|
369 #print "window.JSBridge does not exist."
|
|
370 continue
|
|
371 if not window.JSBridge.isReady:
|
|
372 #print "Waiting for about:jetpack to be ready."
|
|
373 continue
|
|
374 is_done = True
|
|
375 except:
|
|
376 remote.runner.stop()
|
|
377 raise
|
|
378
|
|
379 remote.window = window
|
|
380 return remote
|
|
381
|
|
382 @task
|
|
383 @cmdopts(JSBRIDGE_OPTIONS)
|
|
384 def run(options):
|
|
385 """Run the application in a temporary new profile with the extension
|
|
386 installed."""
|
|
387
|
|
388 remote = start_jsbridge(options)
|
|
389
|
|
390 try:
|
|
391 print "Now running, press Ctrl-C to stop."
|
|
392 remote.runner.wait()
|
|
393 except KeyboardInterrupt:
|
|
394 print "Received interrupt, stopping."
|
|
395 remote.runner.stop()
|
|
396
|
|
397 @task
|
|
398 @cmdopts(JSBRIDGE_OPTIONS)
|
|
399 def render_docs(options):
|
|
400 """Render the API and tutorial documentation in HTML format,
|
|
401 and output it to the website directory."""
|
|
402
|
|
403 # TODO: Render tutorial docs too (bug 496457).
|
|
404
|
|
405 TEMPLATE = os.path.join("website", "templates", "api.html")
|
|
406 OUTPUT = os.path.join("website", "api.html")
|
|
407
|
|
408 done_event = threading.Event()
|
|
409 result = Bunch()
|
|
410
|
|
411 def listener(event_name, obj):
|
|
412 if event_name == 'jetpack:result':
|
|
413 result.update(obj)
|
|
414 done_event.set()
|
|
415
|
|
416 MAX_RENDER_RUN_TIME = 10.0
|
|
417
|
|
418 remote = start_jetpack(options, listener)
|
|
419
|
|
420 try:
|
|
421 remote.window.JSBridge.renderDocs()
|
|
422 done_event.wait(MAX_RENDER_RUN_TIME)
|
|
423 if not done_event.isSet():
|
|
424 raise Exception('Maximum render run time exceeded.')
|
|
425 finally:
|
|
426 remote.runner.stop()
|
|
427
|
|
428 template = open(TEMPLATE).read();
|
|
429 template = template.replace(
|
|
430 "[[CONTENT]]",
|
|
431 result.apiHtml.encode("ascii", "xmlcharrefreplace")
|
|
432 )
|
|
433 open(OUTPUT, "w").write(template)
|
|
434 print "Wrote API docs to %s using template at %s." % (OUTPUT,
|
|
435 TEMPLATE)
|
|
436
|
|
437 @task
|
|
438 @cmdopts(JSBRIDGE_OPTIONS +
|
|
439 [("filter=", "f",
|
|
440 "Run only test suites containing the given string.")])
|
|
441 def test(options):
|
|
442 """Run unit and functional tests."""
|
|
443
|
|
444 done_event = threading.Event()
|
|
445 result = Bunch()
|
|
446
|
|
447 def listener(event_name, obj):
|
|
448 if event_name == 'jetpack:message':
|
|
449 if obj.get('isWarning', False):
|
|
450 print "[WARNING]: %s" % obj['message']
|
|
451 elif obj.get('isError', False):
|
|
452 print "[ERROR] : %s" % obj['message']
|
|
453 else:
|
|
454 print "[message]: %s" % obj['message']
|
|
455 if obj.get('sourceName'):
|
|
456 print " %s:L%s" % (obj['sourceName'],
|
|
457 obj.get('lineNumber', '?'))
|
|
458 elif event_name == 'jetpack:result':
|
|
459 result.obj = obj
|
|
460 done_event.set()
|
|
461
|
|
462 MAX_TEST_RUN_TIME = 25.0
|
|
463
|
|
464 remote = start_jetpack(options, listener)
|
|
465
|
|
466 try:
|
|
467 remote.window.JSBridge.runTests(options.get("filter"))
|
|
468 done_event.wait(MAX_TEST_RUN_TIME)
|
|
469 if not done_event.isSet():
|
|
470 raise Exception('Maximum test run time exceeded.')
|
|
471 finally:
|
|
472 remote.runner.stop()
|
|
473
|
|
474 print "Tests failed: %d" % result.obj['failed']
|
|
475 print "Tests succeeded: %d" % result.obj['succeeded']
|
|
476
|
|
477 if result.obj['failed'] > 0:
|
|
478 sys.exit(result.obj['failed'])
|
|
479
|
|
480 @task
|
|
481 def clean(options):
|
|
482 """Removes all intermediate and non-essential files."""
|
|
483
|
|
484 resolve_options(options)
|
|
485 clear_dir(os.path.join(options.path_to_ext_root, "lib"))
|
|
486
|
|
487 EXTENSIONS_TO_REMOVE = [".pyc", ".orig", ".rej"]
|
|
488
|
|
489 for dirpath, dirnames, filenames in os.walk(os.getcwd()):
|
|
490 if ".hg" in dirnames:
|
|
491 dirnames.remove(".hg")
|
|
492 for filename in filenames:
|
|
493 fullpath = os.path.join(dirpath, filename)
|
|
494 ext = os.path.splitext(filename)[1]
|
|
495 if ext in EXTENSIONS_TO_REMOVE:
|
|
496 os.remove(fullpath)
|
|
497
|
|
498 def run_program(args, **kwargs):
|
|
499 retval = subprocess.call(args, **kwargs)
|
|
500 if retval:
|
|
501 print "Process failed with exit code %d." % retval
|
|
502 sys.exit(retval)
|
|
503
|
|
504 def copy_libs(options, platform = None):
|
|
505 """Copy the platform-specific dynamic library files from our versioned
|
|
506 repository into the extension's temporary directory."""
|
|
507
|
|
508 if platform is None:
|
|
509 if sys.platform == "darwin":
|
|
510 platform = "Darwin_x86-gcc3"
|
|
511 elif sys.platform.startswith("linux"):
|
|
512 platform = "Linux_x86-gcc3"
|
|
513 else:
|
|
514 # Assume Windows.
|
|
515 platform = "WINNT_x86-msvc"
|
|
516 src_dir = os.path.join(options.my_dir, "lib", platform)
|
|
517 dest_dir = os.path.join(options.path_to_ext_root, "lib")
|
|
518 clear_dir(dest_dir)
|
|
519 shutil.copytree(src_dir, dest_dir)
|
|
520
|
|
521 @task
|
|
522 @cmdopts([("srcdir=", "t", "The root of your mozilla-central checkout"),
|
|
523 ("objdir=", "o", "The root of your objdir")])
|
|
524 def xpcom(options):
|
|
525 """Builds binary XPCOM components for Jetpack."""
|
|
526
|
|
527 for option in ["srcdir", "objdir"]:
|
|
528 if not options.get(option):
|
|
529 raise Exception("Please specify a value for the '%s' option." %
|
|
530 option)
|
|
531
|
|
532 for dirname in ["srcdir", "objdir"]:
|
|
533 options[dirname] = os.path.expanduser(options[dirname])
|
|
534 options[dirname] = os.path.abspath(options[dirname])
|
|
535
|
|
536 resolve_options(options)
|
|
537 options.xpcshell = os.path.join(options.objdir, "dist", "bin",
|
|
538 "xpcshell")
|
|
539
|
|
540 xpcom_info = Bunch()
|
|
541 xpcom_info.components_dir = os.path.join(options.objdir, "dist",
|
|
542 "bin", "components")
|
|
543
|
|
544 autoconf = open(os.path.join(options.objdir, "config", "autoconf.mk"),
|
|
545 "r").readlines()
|
|
546 for line in autoconf:
|
|
547 if line.startswith("OS_TARGET"):
|
|
548 xpcom_info.os = line.split("=")[1].strip()
|
|
549 elif line.startswith("TARGET_XPCOM_ABI"):
|
|
550 xpcom_info.abi = line.split("=")[1].strip()
|
|
551 elif line.startswith("MOZILLA_VERSION"):
|
|
552 xpcom_info.mozilla_version = line.split("=")[1].strip()[:5]
|
|
553 elif (line.startswith("MOZ_DEBUG") and
|
|
554 not line.startswith("MOZ_DEBUG_")):
|
|
555 raw_value = line.split("=")[1].strip()
|
|
556 if not raw_value:
|
|
557 xpcom_info.is_debug = 0
|
|
558 else:
|
|
559 xpcom_info.is_debug = int(raw_value)
|
|
560
|
|
561 platform = "%(os)s_%(abi)s" % xpcom_info
|
|
562 print "Building XPCOM binary components for %s" % platform
|
|
563
|
|
564 comp_src_dir = os.path.join(options.my_dir, "components")
|
|
565 rel_dest_dir = os.path.join("browser", "components", "jetpack")
|
|
566 comp_dest_dir = os.path.join(options.srcdir, rel_dest_dir)
|
|
567 comp_xpi_dir = os.path.join(options.objdir, "dist", "xpi-stage",
|
|
568 "jetpack", "components")
|
|
569 comp_plat_dir1 = os.path.join(options.my_dir, "lib",
|
|
570 platform, xpcom_info.mozilla_version)
|
|
571 comp_plat_dir2 = os.path.join(options.path_to_ext_root, "lib",
|
|
572 xpcom_info.mozilla_version)
|
|
573
|
|
574 clear_dir(comp_dest_dir)
|
|
575 clear_dir(comp_xpi_dir)
|
|
576
|
|
577 shutil.copytree(comp_src_dir, comp_dest_dir)
|
|
578
|
|
579 # Ensure that these paths are unix-like on Windows.
|
|
580 sh_pwd = subprocess.Popen(["sh", "-c", "pwd"],
|
|
581 cwd=options.srcdir,
|
|
582 stdout=subprocess.PIPE)
|
|
583 sh_pwd.wait()
|
|
584 unix_topsrcdir = sh_pwd.stdout.read().strip()
|
|
585 unix_rel_dest_dir = rel_dest_dir.replace("\\", "/")
|
|
586
|
|
587 # We're specifying 'perl' here because we have to for this
|
|
588 # to work on Windows.
|
|
589 run_program(["perl",
|
|
590 os.path.join(options.srcdir, "build", "autoconf",
|
|
591 "make-makefile"),
|
|
592 "-t", unix_topsrcdir,
|
|
593 unix_rel_dest_dir],
|
|
594 cwd=options.objdir)
|
|
595
|
|
596 run_program(["make"],
|
|
597 cwd=os.path.join(options.objdir, rel_dest_dir))
|
|
598
|
|
599 xptfiles = []
|
|
600 libfiles = []
|
|
601 for filename in os.listdir(comp_xpi_dir):
|
|
602 if fnmatch.fnmatch(filename, '*.xpt'):
|
|
603 xptfiles.append(filename)
|
|
604 else:
|
|
605 libfiles.append(filename)
|
|
606
|
|
607 def copy_libs(dest_dir):
|
|
608 clear_dir(dest_dir)
|
|
609 distutils.dir_util.mkpath(dest_dir)
|
|
610 for filename in libfiles:
|
|
611 shutil.copy(os.path.join(comp_xpi_dir, filename),
|
|
612 dest_dir)
|
|
613
|
|
614 if not xpcom_info.is_debug:
|
|
615 copy_libs(comp_plat_dir1)
|
|
616 copy_libs(comp_plat_dir2)
|
|
617
|
|
618 for filename in xptfiles:
|
|
619 shutil.copy(os.path.join(comp_xpi_dir, filename),
|
|
620 os.path.join(options.path_to_ext_root, "components"))
|
|
621
|
|
622 for filename in os.listdir(comp_xpi_dir):
|
|
623 shutil.copy(os.path.join(comp_xpi_dir, filename),
|
|
624 xpcom_info.components_dir)
|
|
625
|
|
626 for filename in ["compreg.dat", "xpti.dat"]:
|
|
627 fullpath = os.path.join(xpcom_info.components_dir, filename)
|
|
628 if os.path.exists(fullpath):
|
|
629 os.unlink(fullpath)
|
|
630
|
|
631 # Now run unit tests via xpcshell.
|
|
632
|
|
633 env = {}
|
|
634 env.update(os.environ)
|
|
635 if sys.platform.startswith("linux"):
|
|
636 env['LD_LIBRARY_PATH'] = os.path.dirname(options.xpcshell)
|
|
637
|
|
638 run_program([options.xpcshell,
|
|
639 os.path.join(options.my_dir, "extension",
|
|
640 "content", "js", "tests",
|
|
641 "test-nsjetpack.js")],
|
|
642 env=env,
|
|
643 cwd=os.path.dirname(options.xpcshell))
|