ubiquity/manage.py

268 строки
8.5 KiB
Python
Executable File

#! /usr/bin/env python
# TODO: We need to re-add the 'build-components' target, so we can build
# the optional xpcom binary components.
import os
import sys
if __name__ == '__main__':
# This code is run if we're executed directly from the command-line.
myfile = os.path.abspath(__file__)
mydir = os.path.dirname(myfile)
sys.path.insert(0, os.path.join(mydir, 'python-modules'))
args = sys.argv[1:]
if not args:
args = ['help']
# Have paver run this very file as its pavement script.
args = ['-f', myfile] + args
import paver.tasks
paver.tasks.main(args)
sys.exit(0)
# This code is run if we're executed as a pavement script by paver.
import os
import sys
import xml.dom.minidom
import zipfile
import shutil
import distutils.dir_util
import time
import threading
from ConfigParser import ConfigParser
from paver.easy import *
# Path to the root of the extension, relative to where this script is
# located.
EXT_SUBDIR = "ubiquity"
def clear_dir(dirname):
if os.path.exists(dirname) and os.path.isdir(dirname):
shutil.rmtree(dirname)
def find_profile_dir(name):
"""
Given the name of a Firefox profile, attempts to find the absolute
path to its directory. If it can't be found, None is returned.
"""
base_path = None
if sys.platform == "darwin":
base_path = os.path.expanduser(
"~/Library/Application Support/Firefox/"
)
elif sys.platform.startswith("win"):
# TODO: This only works on 2000/XP/Vista, not 98/Me.
appdata = os.environ["APPDATA"]
base_path = os.path.join(appdata, "Mozilla\\Firefox")
elif sys.platform == "cygwin":
appdata = os.environ["APPDATA"]
base_path = os.path.join(appdata, "Mozilla\\Firefox")
else:
base_path = os.path.expanduser("~/.mozilla/firefox/")
inifile = os.path.join(base_path, "profiles.ini")
config = ConfigParser()
config.read(inifile)
profiles = [section for section in config.sections()
if section.startswith("Profile")]
for profile in profiles:
if config.get(profile, "Name") == name:
# TODO: Look at IsRelative?
path = config.get(profile, "Path")
if not os.path.isabs(path):
path = os.path.join(base_path, path)
return path
return None
def get_install_rdf_dom(path_to_ext_root):
rdf_path = os.path.join(path_to_ext_root, "install.rdf")
rdf = xml.dom.minidom.parse(rdf_path)
return rdf
def get_install_rdf_property(path_to_ext_root, property):
rdf = get_install_rdf_dom(path_to_ext_root)
element = rdf.documentElement.getElementsByTagName(property)[0]
return element.firstChild.nodeValue
def resolve_options(options, ext_subdir = EXT_SUBDIR):
if not options.get('profile'):
options.profile = 'default'
options.my_dir = os.path.dirname(os.path.abspath(options.pavement_file))
options.profile_dir = find_profile_dir(options.profile)
options.path_to_ext_root = os.path.join(options.my_dir, ext_subdir)
options.ext_id = get_install_rdf_property(options.path_to_ext_root, "id")
options.ext_version = get_install_rdf_property(options.path_to_ext_root,
"version")
options.ext_name = get_install_rdf_property(options.path_to_ext_root,
"name")
if options.profile_dir:
options.extension_file = os.path.join(options.profile_dir,
"extensions",
options.ext_id)
# If cygwin, change the path to windows format so firefox can
# understand it.
if sys.platform == "cygwin":
# TODO: Will this work if path_to_ext_root has spaces in it?
file = 'cygpath.exe -w ' + options.path_to_ext_root
path = "".join(os.popen(file).readlines())
path = path.replace("\n", " ").rstrip()
options.firefox_path_to_ext_root = path
else:
options.firefox_path_to_ext_root = options.path_to_ext_root
def remove_extension(options):
if not (options.profile_dir and
os.path.exists(options.profile_dir) and
os.path.isdir(options.profile_dir)):
raise BuildFailure("Can't resolve profile directory; aborting.")
files_to_remove = ["compreg.dat", "xpti.dat"]
for filename in files_to_remove:
abspath = os.path.join(options.profile_dir, filename)
if os.path.exists(abspath):
os.remove(abspath)
if os.path.exists(options.extension_file):
if os.path.isdir(options.extension_file):
shutil.rmtree(options.extension_file)
else:
os.remove(options.extension_file)
INSTALL_OPTIONS = [("profile=", "p", "Profile name.")]
JSBRIDGE_OPTIONS = [("port=", "p", "Port to use for jsbridge communication."),
("binary=", "b", "Path to Firefox binary.")]
@task
@cmdopts(INSTALL_OPTIONS)
def install(options):
"""Install the extension to a Firefox profile."""
resolve_options(options)
remove_extension(options)
extdir = os.path.dirname(options.extension_file)
if not os.path.exists(extdir):
distutils.dir_util.mkpath(extdir)
fileobj = open(options.extension_file, "w")
fileobj.write(options.firefox_path_to_ext_root)
fileobj.close()
print "Extension '%s' installed to profile '%s'." % (options.ext_id,
options.profile)
@task
@cmdopts(INSTALL_OPTIONS)
def uninstall(options):
"""Uninstall the extension from a Firefox profile."""
resolve_options(options)
remove_extension(options)
print "Extension '%s' uninstalled from profile '%s'." % (options.ext_id,
options.profile)
@task
def xpi(options):
"""Build a distributable xpi installer for the extension."""
resolve_options(options)
zfname = "%s-%s.xpi" % (options.ext_name.lower(), options.ext_version)
zf = zipfile.ZipFile(zfname, "w", zipfile.ZIP_DEFLATED)
for dirpath, dirnames, filenames in os.walk(options.path_to_ext_root):
for filename in filenames:
abspath = os.path.join(dirpath, filename)
arcpath = abspath[len(options.path_to_ext_root)+1:]
zf.write(abspath, arcpath)
print "Created %s." % zfname
def start_jsbridge(options):
import mozrunner
import jsbridge
resolve_options(options)
if not options.get('port'):
options.port = '24242'
options.port = int(options.port)
options.binary = options.get('binary')
plugins = [jsbridge.extension_path, options.path_to_ext_root]
profile = mozrunner.FirefoxProfile(
plugins=plugins,
preferences={'browser.startup.homepage' : 'about:blank',
'startup.homepage_welcome_url' : 'about:blank'}
)
runner = mozrunner.FirefoxRunner(profile=profile,
binary=options.binary,
cmdargs=["-jsbridge", str(options.port)])
runner.start()
back_channel, bridge = jsbridge.wait_and_create_network("127.0.0.1",
options.port)
return Bunch(back_channel = back_channel,
bridge = bridge,
runner = runner)
@task
@cmdopts(JSBRIDGE_OPTIONS)
def run(options):
"""Run Firefox in a temporary new profile with the extension installed."""
remote = start_jsbridge(options)
try:
print "Now running, press Ctrl-C to stop."
remote.runner.wait()
except KeyboardInterrupt:
print "Received interrupt, stopping."
remote.runner.stop()
@task
@cmdopts(JSBRIDGE_OPTIONS)
def test(options):
"""Run test suite."""
remote = start_jsbridge(options)
import jsbridge
MAX_TIMEOUT = 25.0
result = {'is_successful' : False}
is_done = threading.Event()
def listener(event_name, obj):
if event_name == 'ubiquity:success':
result['is_successful'] = obj
is_done.set()
remote.back_channel.add_global_listener(listener)
uri = 'resource://ubiquity/tests/systemtests.js'
tests = jsbridge.JSObject(
remote.bridge,
"Components.utils.import('%s')" % uri
)
tests.start()
is_done.wait(MAX_TIMEOUT)
remote.runner.stop()
if result['is_successful']:
print "Success!"
else:
print "Failure."
if not is_done.isSet():
print "Timeout occurred."
sys.exit(-1)