Bug 676078 Remove unused mozmill code from mozilla-central r=ctalbert
--HG-- rename : testing/mozmill/simplejson-2.1.1/CHANGES.txt => other-licenses/simplejson-2.1.1/CHANGES.txt rename : testing/mozmill/simplejson-2.1.1/LICENSE.txt => other-licenses/simplejson-2.1.1/LICENSE.txt rename : testing/mozmill/simplejson-2.1.1/PKG-INFO => other-licenses/simplejson-2.1.1/PKG-INFO rename : testing/mozmill/simplejson-2.1.1/conf.py => other-licenses/simplejson-2.1.1/conf.py rename : testing/mozmill/simplejson-2.1.1/docs/_sources/index.txt => other-licenses/simplejson-2.1.1/docs/_sources/index.txt rename : testing/mozmill/simplejson-2.1.1/docs/_static/contents.png => other-licenses/simplejson-2.1.1/docs/_static/contents.png rename : testing/mozmill/simplejson-2.1.1/docs/_static/default.css => other-licenses/simplejson-2.1.1/docs/_static/default.css rename : testing/mozmill/simplejson-2.1.1/docs/_static/doctools.js => other-licenses/simplejson-2.1.1/docs/_static/doctools.js rename : testing/mozmill/simplejson-2.1.1/docs/_static/file.png => other-licenses/simplejson-2.1.1/docs/_static/file.png rename : testing/mozmill/simplejson-2.1.1/docs/_static/interface.js => other-licenses/simplejson-2.1.1/docs/_static/interface.js rename : testing/mozmill/simplejson-2.1.1/docs/_static/jquery.js => other-licenses/simplejson-2.1.1/docs/_static/jquery.js rename : testing/mozmill/simplejson-2.1.1/docs/_static/minus.png => other-licenses/simplejson-2.1.1/docs/_static/minus.png rename : testing/mozmill/simplejson-2.1.1/docs/_static/navigation.png => other-licenses/simplejson-2.1.1/docs/_static/navigation.png rename : testing/mozmill/simplejson-2.1.1/docs/_static/plus.png => other-licenses/simplejson-2.1.1/docs/_static/plus.png rename : testing/mozmill/simplejson-2.1.1/docs/_static/pygments.css => other-licenses/simplejson-2.1.1/docs/_static/pygments.css rename : testing/mozmill/simplejson-2.1.1/docs/_static/rightsidebar.css => other-licenses/simplejson-2.1.1/docs/_static/rightsidebar.css rename : testing/mozmill/simplejson-2.1.1/docs/_static/searchtools.js => other-licenses/simplejson-2.1.1/docs/_static/searchtools.js rename : testing/mozmill/simplejson-2.1.1/docs/_static/sphinxdoc.css => other-licenses/simplejson-2.1.1/docs/_static/sphinxdoc.css rename : testing/mozmill/simplejson-2.1.1/docs/_static/stickysidebar.css => other-licenses/simplejson-2.1.1/docs/_static/stickysidebar.css rename : testing/mozmill/simplejson-2.1.1/docs/_static/traditional.css => other-licenses/simplejson-2.1.1/docs/_static/traditional.css rename : testing/mozmill/simplejson-2.1.1/docs/genindex.html => other-licenses/simplejson-2.1.1/docs/genindex.html rename : testing/mozmill/simplejson-2.1.1/docs/index.html => other-licenses/simplejson-2.1.1/docs/index.html rename : testing/mozmill/simplejson-2.1.1/docs/objects.inv => other-licenses/simplejson-2.1.1/docs/objects.inv rename : testing/mozmill/simplejson-2.1.1/docs/search.html => other-licenses/simplejson-2.1.1/docs/search.html rename : testing/mozmill/simplejson-2.1.1/docs/searchindex.js => other-licenses/simplejson-2.1.1/docs/searchindex.js rename : testing/mozmill/simplejson-2.1.1/docs/searchindex.json => other-licenses/simplejson-2.1.1/docs/searchindex.json rename : testing/mozmill/simplejson-2.1.1/ez_setup.py => other-licenses/simplejson-2.1.1/ez_setup.py rename : testing/mozmill/simplejson-2.1.1/index.rst => other-licenses/simplejson-2.1.1/index.rst rename : testing/mozmill/simplejson-2.1.1/scripts/make_docs.py => other-licenses/simplejson-2.1.1/scripts/make_docs.py rename : testing/mozmill/simplejson-2.1.1/setup.cfg => other-licenses/simplejson-2.1.1/setup.cfg rename : testing/mozmill/simplejson-2.1.1/setup.py => other-licenses/simplejson-2.1.1/setup.py rename : testing/mozmill/simplejson-2.1.1/simplejson/__init__.py => other-licenses/simplejson-2.1.1/simplejson/__init__.py rename : testing/mozmill/simplejson-2.1.1/simplejson/_speedups.c => other-licenses/simplejson-2.1.1/simplejson/_speedups.c rename : testing/mozmill/simplejson-2.1.1/simplejson/decoder.py => other-licenses/simplejson-2.1.1/simplejson/decoder.py rename : testing/mozmill/simplejson-2.1.1/simplejson/encoder.py => other-licenses/simplejson-2.1.1/simplejson/encoder.py rename : testing/mozmill/simplejson-2.1.1/simplejson/ordered_dict.py => other-licenses/simplejson-2.1.1/simplejson/ordered_dict.py rename : testing/mozmill/simplejson-2.1.1/simplejson/scanner.py => other-licenses/simplejson-2.1.1/simplejson/scanner.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/__init__.py => other-licenses/simplejson-2.1.1/simplejson/tests/__init__.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_check_circular.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_check_circular.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_decimal.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_decimal.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_decode.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_decode.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_default.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_default.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_dump.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_dump.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_encode_basestring_ascii.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_encode_basestring_ascii.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_encode_for_html.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_encode_for_html.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_fail.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_fail.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_float.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_float.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_indent.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_indent.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_pass1.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_pass1.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_pass2.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_pass2.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_pass3.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_pass3.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_recursion.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_recursion.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_scanstring.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_scanstring.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_separators.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_separators.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_speedups.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_speedups.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tests/test_unicode.py => other-licenses/simplejson-2.1.1/simplejson/tests/test_unicode.py rename : testing/mozmill/simplejson-2.1.1/simplejson/tool.py => other-licenses/simplejson-2.1.1/simplejson/tool.py rename : testing/mozmill/virtualenv/MANIFEST.in => other-licenses/virtualenv/MANIFEST.in rename : testing/mozmill/virtualenv/PKG-INFO => other-licenses/virtualenv/PKG-INFO rename : testing/mozmill/virtualenv/docs/_build/_sources/index.txt => other-licenses/virtualenv/docs/_build/_sources/index.txt rename : testing/mozmill/virtualenv/docs/_build/_sources/license.txt => other-licenses/virtualenv/docs/_build/_sources/license.txt rename : testing/mozmill/virtualenv/docs/_build/_sources/news.txt => other-licenses/virtualenv/docs/_build/_sources/news.txt rename : testing/mozmill/virtualenv/docs/index.txt => other-licenses/virtualenv/docs/index.txt rename : testing/mozmill/virtualenv/docs/license.txt => other-licenses/virtualenv/docs/license.txt rename : testing/mozmill/virtualenv/docs/news.txt => other-licenses/virtualenv/docs/news.txt rename : testing/mozmill/virtualenv/scripts/virtualenv => other-licenses/virtualenv/scripts/virtualenv rename : testing/mozmill/virtualenv/setup.cfg => other-licenses/virtualenv/setup.cfg rename : testing/mozmill/virtualenv/setup.py => other-licenses/virtualenv/setup.py rename : testing/mozmill/virtualenv/virtualenv.py => other-licenses/virtualenv/virtualenv.py rename : testing/mozmill/virtualenv/virtualenv_support/__init__.py => other-licenses/virtualenv/virtualenv_support/__init__.py rename : testing/mozmill/virtualenv/virtualenv_support/distribute-0.6.8.tar.gz => other-licenses/virtualenv/virtualenv_support/distribute-0.6.8.tar.gz rename : testing/mozmill/virtualenv/virtualenv_support/pip-0.7.1.tar.gz => other-licenses/virtualenv/virtualenv_support/pip-0.7.1.tar.gz rename : testing/mozmill/virtualenv/virtualenv_support/setuptools-0.6c11-py2.4.egg => other-licenses/virtualenv/virtualenv_support/setuptools-0.6c11-py2.4.egg rename : testing/mozmill/virtualenv/virtualenv_support/setuptools-0.6c11-py2.5.egg => other-licenses/virtualenv/virtualenv_support/setuptools-0.6c11-py2.5.egg rename : testing/mozmill/virtualenv/virtualenv_support/setuptools-0.6c11-py2.6.egg => other-licenses/virtualenv/virtualenv_support/setuptools-0.6c11-py2.6.egg
До Ширина: | Высота: | Размер: 202 B После Ширина: | Высота: | Размер: 202 B |
До Ширина: | Высота: | Размер: 392 B После Ширина: | Высота: | Размер: 392 B |
До Ширина: | Высота: | Размер: 199 B После Ширина: | Высота: | Размер: 199 B |
До Ширина: | Высота: | Размер: 218 B После Ширина: | Высота: | Размер: 218 B |
До Ширина: | Высота: | Размер: 199 B После Ширина: | Высота: | Размер: 199 B |
|
@ -39,7 +39,7 @@ DEPTH = ../..
|
|||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
mozmilldir = @top_srcdir@/testing/mozmill
|
||||
otherlicenses = @top_srcdir@/other-licenses
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
|
@ -47,14 +47,14 @@ MODULE = testing_firebug
|
|||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Firebug requires several of the same packages as Mozmill.
|
||||
# Rather than check them into m-c twice, just grab them from
|
||||
# the Mozmill directory.
|
||||
TEST_MOZMILL_PACKAGES = \
|
||||
# Firebug requires several 3rd party packages.
|
||||
# Grab them from the other-licenses directory:
|
||||
# http://mxr.mozilla.org/mozilla-central/source/other-licenses/
|
||||
TEST_OTHER_PACKAGES = \
|
||||
simplejson-2.1.1 \
|
||||
$(NULL)
|
||||
|
||||
TEST_MOZMILL_EXTRAS = \
|
||||
TEST_OTHER_EXTRAS = \
|
||||
virtualenv \
|
||||
$(NULL)
|
||||
|
||||
|
@ -79,9 +79,9 @@ TEST_HARNESS_FILES = \
|
|||
stage-package: PKG_STAGE = $(DIST)/test-package-stage
|
||||
stage-package:
|
||||
$(NSINSTALL) -D $(PKG_STAGE)/firebug
|
||||
@echo $(TEST_MOZMILL_PACKAGES) $(TEST_HARNESS_PACKAGES) > $(PKG_STAGE)/firebug/PACKAGES
|
||||
@echo $(TEST_OTHER_PACKAGES) $(TEST_HARNESS_PACKAGES) > $(PKG_STAGE)/firebug/PACKAGES
|
||||
@(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_PACKAGES)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_FILES)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_EXTRAS)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(mozmilldir) && tar $(TAR_CREATE_FLAGS) - $(TEST_MOZMILL_EXTRAS)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(mozmilldir) && tar $(TAR_CREATE_FLAGS) - $(TEST_MOZMILL_PACKAGES)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(otherlicenses) && tar $(TAR_CREATE_FLAGS) - $(TEST_OTHER_EXTRAS)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
@(cd $(otherlicenses) && tar $(TAR_CREATE_FLAGS) - $(TEST_OTHER_PACKAGES)) | (cd $(PKG_STAGE)/firebug && tar -xf -)
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla.org.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Jeff Hammel <jhammel@mozilla.com> (Original author)
|
||||
# Clint Talbert <ctalbert@mozilla.com> (Original author)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = testing_mozmill
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
# Harness packages from the srcdir;
|
||||
# python packages to be installed IN INSTALLATION ORDER.
|
||||
# Packages later in the list can depend only on packages earlier in the list.
|
||||
# Since jsbridge depends on simplejson and mozrunner, these
|
||||
# must be installed before jsbridge is installed. Likewise,
|
||||
# mozmill depends on jsbridge. If the dependencies are not
|
||||
# found installed, pip will download them from the internet
|
||||
# which is normally not desirable,
|
||||
TEST_HARNESS_PACKAGES = \
|
||||
simplejson-2.1.1 \
|
||||
mozrunner \
|
||||
jsbridge \
|
||||
mozmill \
|
||||
$(NULL)
|
||||
|
||||
MOZMILL_EXTRAS := \
|
||||
virtualenv \
|
||||
README.txt \
|
||||
installmozmill.py \
|
||||
$(NULL)
|
||||
|
||||
TEST_FILES := \
|
||||
$(TEST_HARNESS_PACKAGES) \
|
||||
$(MOZMILL_EXTRAS) \
|
||||
tests \
|
||||
$(NULL)
|
||||
|
||||
# assumes you are in objdir
|
||||
mozmill-dir:
|
||||
$(NSINSTALL) -D $(PKG_STAGE)/mozmill
|
||||
echo $(TEST_HARNESS_PACKAGES) > $(PKG_STAGE)/mozmill/PACKAGES
|
||||
|
||||
install: mozmill-dir
|
||||
(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_FILES)) | (cd $(PKG_STAGE)/mozmill && tar -xf -)
|
||||
|
||||
# on WINNT, copy the tests; otherwise, assume you can symlink them
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
install-develop: install
|
||||
else
|
||||
install-develop: mozmill-dir
|
||||
$(INSTALL) $(foreach f, $(TEST_HARNESS_PACKAGES), "$(srcdir)/$f") $(PKG_STAGE)/mozmill/
|
||||
(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(MOZMILL_EXTRAS)) | (cd $(PKG_STAGE)/mozmill && tar -xf -)
|
||||
$(INSTALL) $(topsrcdir)/testing/mozmill/tests $(PKG_STAGE)/mozmill
|
||||
endif
|
||||
|
||||
# Rules for staging the necessary harness bits for a test package
|
||||
stage-package: install
|
||||
|
||||
PKG_STAGE = $(DIST)/test-package-stage
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
Simple mozmill test harness
|
||||
|
||||
See https://developer.mozilla.org/en/Mozmill
|
||||
|
||||
The tests are from http://hg.mozilla.org/qa/mozmill-tests
|
|
@ -1,162 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla.org.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Jeff Hammel <jhammel@mozilla.com> (Original author)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
"""
|
||||
install mozmill and its dependencies
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
from subprocess import call
|
||||
|
||||
### utility functions for cross-platform
|
||||
|
||||
def is_windows():
|
||||
return sys.platform.startswith('win')
|
||||
|
||||
def esc(path):
|
||||
"""quote and escape a path for cross-platform use"""
|
||||
return '"%s"' % repr(path)[1:-1]
|
||||
|
||||
def scripts_path(virtual_env):
|
||||
"""path to scripts directory"""
|
||||
if is_windows():
|
||||
return os.path.join(virtual_env, 'Scripts')
|
||||
return os.path.join(virtual_env, 'bin')
|
||||
|
||||
def python_script_path(virtual_env, script_name):
|
||||
"""path to a python script in a virtualenv"""
|
||||
scripts_dir = scripts_path(virtual_env)
|
||||
if is_windows():
|
||||
script_name = script_name + '-script.py'
|
||||
return os.path.join(scripts_dir, script_name)
|
||||
|
||||
def entry_point_path(virtual_env, entry_point):
|
||||
path = os.path.join(scripts_path(virtual_env), entry_point)
|
||||
if is_windows():
|
||||
path += '.exe'
|
||||
return path
|
||||
|
||||
### command-line entry point
|
||||
|
||||
def main(args=None):
|
||||
"""command line front-end function"""
|
||||
|
||||
# parse command line arguments
|
||||
args = args or sys.argv[1:]
|
||||
usage = "Usage: %prog [options] [destination]"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('--develop', dest='develop',
|
||||
action='store_true', default=False,
|
||||
help='setup in development mode')
|
||||
options, args = parser.parse_args(args)
|
||||
|
||||
# Print the python version
|
||||
print 'Python: %s' % sys.version
|
||||
|
||||
# The data is kept in the same directory as the script
|
||||
source=os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
# directory to install to
|
||||
if not len(args):
|
||||
destination = source
|
||||
elif len(args) == 1:
|
||||
destination = os.path.abspath(args[0])
|
||||
else:
|
||||
parser.print_usage()
|
||||
parser.exit(1)
|
||||
|
||||
os.chdir(source)
|
||||
|
||||
# check for existence of necessary files
|
||||
if not os.path.exists('virtualenv'):
|
||||
print "File not found: virtualenv"
|
||||
sys.exit(1)
|
||||
PACKAGES_FILE = 'PACKAGES'
|
||||
if not os.path.exists(PACKAGES_FILE) and destination != source:
|
||||
PACKAGES_FILE = os.path.join(destination, PACKAGES_FILE)
|
||||
if not os.path.exists(PACKAGES_FILE):
|
||||
print "File not found: PACKAGES"
|
||||
|
||||
# packages to install in dependency order
|
||||
PACKAGES=file(PACKAGES_FILE).read().split()
|
||||
assert PACKAGES
|
||||
|
||||
# create the virtualenv and install packages
|
||||
env = os.environ.copy()
|
||||
env.pop('PYTHONHOME', None)
|
||||
returncode = call([sys.executable, os.path.join('virtualenv', 'virtualenv.py'), destination], env=env)
|
||||
if returncode:
|
||||
print 'Failure to install virtualenv'
|
||||
sys.exit(returncode)
|
||||
if options.develop:
|
||||
python = entry_point_path(destination, 'python')
|
||||
for package in PACKAGES:
|
||||
oldcwd = os.getcwd()
|
||||
os.chdir(package)
|
||||
returncode = call([python, 'setup.py', 'develop'])
|
||||
os.chdir(oldcwd)
|
||||
if returncode:
|
||||
break
|
||||
else:
|
||||
pip = entry_point_path(destination, 'pip')
|
||||
returncode = call([pip, 'install'] + PACKAGES, env=env)
|
||||
|
||||
if returncode:
|
||||
print 'Failure to install packages'
|
||||
sys.exit(returncode)
|
||||
|
||||
# create a front end runner that is path-independent
|
||||
template = """#!/bin/bash
|
||||
unset PYTHONHOME
|
||||
%(PYTHON)s %(MOZMILL)s $@
|
||||
"""
|
||||
variables = {'PYTHON': esc(entry_point_path(destination, 'python')) }
|
||||
for script in 'mozmill', 'mozmill-restart':
|
||||
path = os.path.join(destination, script + '.sh')
|
||||
f = file(path, 'w')
|
||||
variables['MOZMILL'] = esc(python_script_path(destination, script))
|
||||
print >> f, template % variables
|
||||
f.close()
|
||||
if not is_windows():
|
||||
os.chmod(path, 0755)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,2 +0,0 @@
|
|||
recursive-include jsbridge/extension *
|
||||
recursive-include jsbridge/xpi *
|
|
@ -1,177 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Corporation Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mikeal Rogers.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008 -2009
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
# Henrik Skupin <hskupin@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import socket
|
||||
import os
|
||||
import copy
|
||||
import asyncore
|
||||
|
||||
from time import sleep
|
||||
from network import Bridge, BackChannel, create_network
|
||||
from jsobjects import JSObject
|
||||
|
||||
import mozrunner
|
||||
|
||||
settings_env = 'JSBRIDGE_SETTINGS_FILE'
|
||||
|
||||
parent = os.path.abspath(os.path.dirname(__file__))
|
||||
extension_path = os.path.join(parent, 'extension')
|
||||
|
||||
window_string = "Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('')"
|
||||
|
||||
wait_to_create_timeout = 60
|
||||
|
||||
def wait_and_create_network(host, port, timeout=wait_to_create_timeout):
|
||||
ttl = 0
|
||||
while ttl < timeout:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((host, port))
|
||||
s.close()
|
||||
break
|
||||
except socket.error:
|
||||
pass
|
||||
sleep(.25)
|
||||
ttl += .25
|
||||
if ttl == timeout:
|
||||
raise Exception("Sorry, cannot connect to jsbridge extension, port %s" % port)
|
||||
|
||||
back_channel, bridge = create_network(host, port)
|
||||
sleep(.5)
|
||||
|
||||
while back_channel.registered is False:
|
||||
back_channel.close()
|
||||
bridge.close()
|
||||
asyncore.socket_map = {}
|
||||
sleep(1)
|
||||
back_channel, bridge = create_network(host, port)
|
||||
|
||||
return back_channel, bridge
|
||||
|
||||
class CLI(mozrunner.CLI):
|
||||
"""Command line interface."""
|
||||
|
||||
module = "jsbridge"
|
||||
|
||||
parser_options = copy.copy(mozrunner.CLI.parser_options)
|
||||
parser_options[('-D', '--debug',)] = dict(dest="debug",
|
||||
action="store_true",
|
||||
help="Debug mode",
|
||||
metavar="JSBRIDGE_DEBUG",
|
||||
default=False )
|
||||
parser_options[('-s', '--shell',)] = dict(dest="shell",
|
||||
action="store_true",
|
||||
help="Start a Python shell",
|
||||
metavar="JSBRIDGE_SHELL",
|
||||
default=False )
|
||||
parser_options[('-u', '--usecode',)] = dict(dest="usecode", action="store_true",
|
||||
help="Use code module instead of iPython",
|
||||
default=False)
|
||||
parser_options[('-P', '--port')] = dict(dest="port", default="24242",
|
||||
help="TCP port to run jsbridge on.")
|
||||
|
||||
def get_profile(self, *args, **kwargs):
|
||||
if self.options.debug:
|
||||
kwargs.setdefault('preferences', {}).update({
|
||||
'extensions.checkCompatibility':False,
|
||||
'devtools.errorconsole.enabled':True
|
||||
})
|
||||
profile = mozrunner.CLI.get_profile(self, *args, **kwargs)
|
||||
profile.install_addon(extension_path)
|
||||
return profile
|
||||
|
||||
def get_runner(self, *args, **kwargs):
|
||||
runner = super(CLI, self).get_runner(*args, **kwargs)
|
||||
if self.options.debug:
|
||||
runner.cmdargs.append('-jsconsole')
|
||||
runner.cmdargs += ['-jsbridge', self.options.port]
|
||||
return runner
|
||||
|
||||
def run(self):
|
||||
runner = self.create_runner()
|
||||
runner.start()
|
||||
self.start_jsbridge_network()
|
||||
if self.options.shell:
|
||||
self.start_shell(runner)
|
||||
else:
|
||||
try:
|
||||
runner.wait()
|
||||
except KeyboardInterrupt:
|
||||
runner.stop()
|
||||
|
||||
runner.profile.cleanup()
|
||||
|
||||
def start_shell(self, runner):
|
||||
try:
|
||||
import IPython
|
||||
except:
|
||||
IPython = None
|
||||
jsobj = JSObject(self.bridge, window_string)
|
||||
|
||||
if IPython is None or self.options.usecode:
|
||||
import code
|
||||
code.interact(local={"jsobj":jsobj,
|
||||
"getBrowserWindow":lambda : getBrowserWindow(self.bridge),
|
||||
"back_channel":self.back_channel,
|
||||
})
|
||||
else:
|
||||
from IPython.Shell import IPShellEmbed
|
||||
ipshell = IPShellEmbed([])
|
||||
ipshell(local_ns={"jsobj":jsobj,
|
||||
"getBrowserWindow":lambda : getBrowserWindow(self.bridge),
|
||||
"back_channel":self.back_channel,
|
||||
})
|
||||
runner.stop()
|
||||
|
||||
def start_jsbridge_network(self, timeout=10):
|
||||
port = int(self.options.port)
|
||||
host = '127.0.0.1'
|
||||
self.back_channel, self.bridge = wait_and_create_network(host, port, timeout)
|
||||
|
||||
def cli():
|
||||
CLI().run()
|
||||
|
||||
def getBrowserWindow(bridge):
|
||||
return JSObject(bridge, "Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('')")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
resource jsbridge resource/
|
||||
|
||||
content jsbridge chrome/content/
|
||||
|
||||
overlay chrome://browser/content/browser.xul chrome://jsbridge/content/overlay.xul
|
||||
overlay chrome://messenger/content/mailWindowOverlay.xul chrome://jsbridge/content/overlay.xul
|
||||
|
||||
overlay chrome://calendar/content/calendar.xul chrome://jsbridge/content/overlay.xul
|
||||
|
||||
overlay windowtype:Songbird:Main chrome://jsbridge/content/overlay.xul
|
||||
|
||||
component {2872d428-14f6-11de-ac86-001f5bd9235c} components/cmdarg.js
|
||||
contract @mozilla.org/commandlinehandler/general-startup;1?type=jsbridge {2872d428-14f6-11de-ac86-001f5bd9235c}
|
||||
category command-line-handler jsbridge @mozilla.org/commandlinehandler/general-startup;1?type=jsbridge
|
|
@ -1,40 +0,0 @@
|
|||
// ***** BEGIN LICENSE BLOCK *****
|
||||
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
//
|
||||
// The contents of this file are subject to the Mozilla Public License Version
|
||||
// 1.1 (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS" basis,
|
||||
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
// for the specific language governing rights and limitations under the
|
||||
// License.
|
||||
//
|
||||
// The Original Code is Mozilla Corporation Code.
|
||||
//
|
||||
// The Initial Developer of the Original Code is
|
||||
// Mikeal Rogers.
|
||||
// Portions created by the Initial Developer are Copyright (C) 2008
|
||||
// the Initial Developer. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
// Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
// in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
// of those above. If you wish to allow use of your version of this file only
|
||||
// under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
// use your version of this file under the terms of the MPL, indicate your
|
||||
// decision by deleting the provisions above and replace them with the notice
|
||||
// and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
// the provisions above, a recipient may use your version of this file under
|
||||
// the terms of any one of the MPL, the GPL or the LGPL.
|
||||
//
|
||||
// ***** END LICENSE BLOCK *****
|
||||
|
||||
var jsbridgeInit = {}; Components.utils.import('resource://jsbridge/modules/init.js',jsbridgeInit);
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<overlay id="jsbridge-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="overlay.js"/>
|
||||
</overlay>
|
|
@ -1,124 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const nsIAppShellService = Components.interfaces.nsIAppShellService;
|
||||
const nsISupports = Components.interfaces.nsISupports;
|
||||
const nsICategoryManager = Components.interfaces.nsICategoryManager;
|
||||
const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
|
||||
const nsICommandLine = Components.interfaces.nsICommandLine;
|
||||
const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler;
|
||||
const nsIFactory = Components.interfaces.nsIFactory;
|
||||
const nsIModule = Components.interfaces.nsIModule;
|
||||
const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher;
|
||||
|
||||
// CHANGEME: to the chrome URI of your extension or application
|
||||
const CHROME_URI = "chrome://jsbridge/content/";
|
||||
|
||||
// CHANGEME: change the contract id, CID, and category to be unique
|
||||
// to your application.
|
||||
const clh_contractID = "@mozilla.org/commandlinehandler/general-startup;1?type=jsbridge";
|
||||
|
||||
// use uuidgen to generate a unique ID
|
||||
const clh_CID = Components.ID("{2872d428-14f6-11de-ac86-001f5bd9235c}");
|
||||
|
||||
// category names are sorted alphabetically. Typical command-line handlers use a
|
||||
// category that begins with the letter "m".
|
||||
const clh_category = "jsbridge";
|
||||
|
||||
var aConsoleService = Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Components.interfaces.nsIConsoleService);
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opens a chrome window.
|
||||
* @param aChromeURISpec a string specifying the URI of the window to open.
|
||||
* @param aArgument an argument to pass to the window (may be null)
|
||||
*/
|
||||
function openWindow(aChromeURISpec, aArgument)
|
||||
{
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.openWindow(null, aChromeURISpec, "_blank",
|
||||
"chrome,menubar,toolbar,status,resizable,dialog=no",
|
||||
aArgument);
|
||||
}
|
||||
|
||||
/**
|
||||
* The XPCOM component that implements nsICommandLineHandler.
|
||||
* It also implements nsIFactory to serve as its own singleton factory.
|
||||
*/
|
||||
function jsbridgeHandler() {
|
||||
}
|
||||
jsbridgeHandler.prototype = {
|
||||
classID: clh_CID,
|
||||
contractID: clh_contractID,
|
||||
classDescription: "jsbridgeHandler",
|
||||
_xpcom_categories: [{category: "command-line-handler", entry: clh_category}],
|
||||
|
||||
/* nsISupports */
|
||||
QueryInterface : function clh_QI(iid)
|
||||
{
|
||||
if (iid.equals(nsICommandLineHandler) ||
|
||||
iid.equals(nsIFactory) ||
|
||||
iid.equals(nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
/* nsICommandLineHandler */
|
||||
|
||||
handle : function clh_handle(cmdLine)
|
||||
{
|
||||
try {
|
||||
var port = cmdLine.handleFlagWithParam("jsbridge", false);
|
||||
if (port) {
|
||||
var server = {};
|
||||
Components.utils.import('resource://jsbridge/modules/server.js', server);
|
||||
server.startServer(parseInt(port));
|
||||
} else {
|
||||
var server = {};
|
||||
Components.utils.import('resource://jsbridge/modules/server.js', server);
|
||||
server.startServer(24242);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Components.utils.reportError("incorrect parameter passed to -jsbridge on the command line.");
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// CHANGEME: change the help info as appropriate, but
|
||||
// follow the guidelines in nsICommandLineHandler.idl
|
||||
// specifically, flag descriptions should start at
|
||||
// character 24, and lines should be wrapped at
|
||||
// 72 characters with embedded newlines,
|
||||
// and finally, the string should end with a newline
|
||||
helpInfo : " -jsbridge Port to run jsbridge on.\n",
|
||||
|
||||
/* nsIFactory */
|
||||
|
||||
createInstance : function clh_CI(outer, iid)
|
||||
{
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
lockFactory : function clh_lock(lock)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
|
||||
* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.1 (Firefox 3.5).
|
||||
*/
|
||||
if (XPCOMUtils.generateNSGetFactory)
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([jsbridgeHandler]);
|
||||
else
|
||||
const NSGetModule = XPCOMUtils.generateNSGetModule([jsbridgeHandler]);
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>jsbridge@mozilla.com</em:id>
|
||||
<em:name>jsbridge</em:name>
|
||||
<em:version>2.4.1rc2</em:version>
|
||||
<em:creator>Mikeal Rogers</em:creator>
|
||||
<em:description>Python to JavaScript bridge</em:description>
|
||||
<em:targetApplication>
|
||||
<!-- Firefox -->
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>3.5</em:minVersion>
|
||||
<em:maxVersion>4.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:targetApplication>
|
||||
<!-- Thunderbird -->
|
||||
<Description>
|
||||
<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
|
||||
<em:minVersion>3.0a1pre</em:minVersion>
|
||||
<em:maxVersion>4.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:targetApplication>
|
||||
<!-- Sunbird -->
|
||||
<Description>
|
||||
<em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id>
|
||||
<em:minVersion>1.0b1pre</em:minVersion>
|
||||
<em:maxVersion>1.0pre</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:targetApplication>
|
||||
<!-- Songbird -->
|
||||
<Description>
|
||||
<em:id>songbird@songbirdnest.com</em:id>
|
||||
<em:minVersion>0.3pre</em:minVersion>
|
||||
<em:maxVersion>2.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>1.9.1</em:minVersion>
|
||||
<em:maxVersion>2.0*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
|
||||
|
||||
</RDF>
|
|
@ -1,13 +0,0 @@
|
|||
var EXPORTED_SYMBOLS = ["backchannels", "fireEvent", "addBackChannel"];
|
||||
|
||||
var backchannels = [];
|
||||
|
||||
var fireEvent = function (name, obj) {
|
||||
for each(backchannel in backchannels) {
|
||||
backchannel.session.encodeOut({'eventType':name, 'result':obj});
|
||||
}
|
||||
}
|
||||
|
||||
var addBackChannel = function (backchannel) {
|
||||
backchannels.push(backchannel);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// ***** BEGIN LICENSE BLOCK *****
|
||||
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
//
|
||||
// The contents of this file are subject to the Mozilla Public License Version
|
||||
// 1.1 (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS" basis,
|
||||
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
// for the specific language governing rights and limitations under the
|
||||
// License.
|
||||
//
|
||||
// The Original Code is Mozilla Corporation Code.
|
||||
//
|
||||
// The Initial Developer of the Original Code is
|
||||
// Mikeal Rogers.
|
||||
// Portions created by the Initial Developer are Copyright (C) 2008
|
||||
// the Initial Developer. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
// Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
// in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
// of those above. If you wish to allow use of your version of this file only
|
||||
// under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
// use your version of this file under the terms of the MPL, indicate your
|
||||
// decision by deleting the provisions above and replace them with the notice
|
||||
// and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
// the provisions above, a recipient may use your version of this file under
|
||||
// the terms of any one of the MPL, the GPL or the LGPL.
|
||||
//
|
||||
// ***** END LICENSE BLOCK *****
|
||||
|
||||
var EXPORTED_SYMBOLS = ["server"];
|
||||
|
||||
var server = {}; Components.utils.import('resource://jsbridge/modules/server.js', server);
|
|
@ -1,471 +0,0 @@
|
|||
/*
|
||||
http://www.JSON.org/json2.js
|
||||
2008-05-25
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
This file creates a global JSON object containing two methods: stringify
|
||||
and parse.
|
||||
|
||||
JSON.stringify(value, replacer, space)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
replacer an optional parameter that determines how object
|
||||
values are stringified for objects without a toJSON
|
||||
method. It can be a function or an array.
|
||||
|
||||
space an optional parameter that specifies the indentation
|
||||
of nested structures. If it is omitted, the text will
|
||||
be packed without extra whitespace. If it is a number,
|
||||
it will specify the number of spaces to indent at each
|
||||
level. If it is a string (such as '\t' or ' '),
|
||||
it contains the characters used to indent at each level.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
|
||||
When an object value is found, if the object contains a toJSON
|
||||
method, its toJSON method will be called and the result will be
|
||||
stringified. A toJSON method does not serialize: it returns the
|
||||
value represented by the name/value pair that should be serialized,
|
||||
or undefined if nothing should be serialized. The toJSON method
|
||||
will be passed the key associated with the value, and this will be
|
||||
bound to the object holding the key.
|
||||
|
||||
For example, this would serialize Dates as ISO strings.
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
You can provide an optional replacer method. It will be passed the
|
||||
key and value of each member, with this bound to the containing
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
If the replacer parameter is an array, then it will be used to
|
||||
select the members to be serialized. It filters the results such
|
||||
that only members with keys listed in the replacer array are
|
||||
stringified.
|
||||
|
||||
Values that do not have JSON representations, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped; in arrays they will be replaced with null. You can use
|
||||
a replacer function to replace those with JSON values.
|
||||
JSON.stringify(undefined) returns undefined.
|
||||
|
||||
The optional space parameter produces a stringification of the
|
||||
value that is filled with line breaks and indentation to make it
|
||||
easier to read.
|
||||
|
||||
If the space parameter is a non-empty string, then that string will
|
||||
be used for indentation. If the space parameter is a number, then
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||
|
||||
text = JSON.stringify([new Date()], function (key, value) {
|
||||
return this[key] instanceof Date ?
|
||||
'Date(' + this[key] + ')' : value;
|
||||
});
|
||||
// text is '["Date(---current time---)"]'
|
||||
|
||||
|
||||
JSON.parse(text, reviver)
|
||||
This method parses a JSON text to produce an object or array.
|
||||
It can throw a SyntaxError exception.
|
||||
|
||||
The optional reviver parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values,
|
||||
and its return value is used instead of the original value.
|
||||
If it returns what it received, then the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||
var d;
|
||||
if (typeof value === 'string' &&
|
||||
value.slice(0, 5) === 'Date(' &&
|
||||
value.slice(-1) === ')') {
|
||||
d = new Date(value.slice(5, -1));
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
|
||||
This is a reference implementation. You are free to copy, modify, or
|
||||
redistribute.
|
||||
|
||||
This code should be minified before deployment.
|
||||
See http://javascript.crockford.com/jsmin.html
|
||||
|
||||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||
NOT CONTROL.
|
||||
*/
|
||||
|
||||
/*jslint evil: true */
|
||||
|
||||
/*global JSON */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", call,
|
||||
charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes,
|
||||
getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length,
|
||||
parse, propertyIsEnumerable, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ["JSON"];
|
||||
|
||||
if (!this.JSON) {
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// object in a closure to avoid creating global variables.
|
||||
|
||||
JSON = function () {
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
escapeable.lastIndex = 0;
|
||||
return escapeable.test(string) ?
|
||||
'"' + string.replace(escapeable, function (a) {
|
||||
var c = meta[a];
|
||||
if (typeof c === 'string') {
|
||||
return c;
|
||||
}
|
||||
return '\\u' + ('0000' +
|
||||
(+(a.charCodeAt(0))).toString(16)).slice(-4);
|
||||
}) + '"' :
|
||||
'"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// If the object has a dontEnum length property, we'll treat it as an array.
|
||||
|
||||
if (typeof value.length === 'number' &&
|
||||
!(value.propertyIsEnumerable('length'))) {
|
||||
|
||||
// The object is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// Join all of the elements together, separated with commas, and wrap them in
|
||||
// brackets.
|
||||
|
||||
v = partial.length === 0 ? '[]' :
|
||||
gap ? '[\n' + gap +
|
||||
partial.join(',\n' + gap) + '\n' +
|
||||
mind + ']' :
|
||||
'[' + partial.join(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
k = rep[i];
|
||||
if (typeof k === 'string') {
|
||||
v = str(k, value, rep);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value, rep);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with commas,
|
||||
// and wrap them in braces.
|
||||
|
||||
v = partial.length === 0 ? '{}' :
|
||||
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||
mind + '}' : '{' + partial.join(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the JSON object containing the stringify and parse methods.
|
||||
|
||||
return {
|
||||
stringify: function (value, replacer, space) {
|
||||
|
||||
// The stringify method takes a value and an optional replacer, and an optional
|
||||
// space parameter, and returns a JSON text. The replacer can be a function
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
},
|
||||
|
||||
|
||||
parse: function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' + ('0000' +
|
||||
(+(a.charCodeAt(0))).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/.
|
||||
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the third stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a reviver function for possible transformation.
|
||||
|
||||
return typeof reviver === 'function' ?
|
||||
walk({'': j}, '') : j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
}
|
||||
};
|
||||
}();
|
||||
}
|
|
@ -1,302 +0,0 @@
|
|||
// ***** BEGIN LICENSE BLOCK *****
|
||||
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
//
|
||||
// The contents of this file are subject to the Mozilla Public License Version
|
||||
// 1.1 (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS" basis,
|
||||
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
// for the specific language governing rights and limitations under the
|
||||
// License.
|
||||
//
|
||||
// The Original Code is Mozilla Corporation Code.
|
||||
//
|
||||
// The Initial Developer of the Original Code is
|
||||
// based on the MozRepl project.
|
||||
// Portions created by the Initial Developer are Copyright (C) 2008
|
||||
// the Initial Developer. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
// Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
// Massimiliano Mirra <bard@hyperstruct.net>
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
// in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
// of those above. If you wish to allow use of your version of this file only
|
||||
// under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
// use your version of this file under the terms of the MPL, indicate your
|
||||
// decision by deleting the provisions above and replace them with the notice
|
||||
// and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
// the provisions above, a recipient may use your version of this file under
|
||||
// the terms of any one of the MPL, the GPL or the LGPL.
|
||||
//
|
||||
// ***** END LICENSE BLOCK *****
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Server", "server", "AsyncRead", "Session", "sessions", "globalRegistry", "startServer"];
|
||||
|
||||
var events = {}; Components.utils.import("resource://jsbridge/modules/events.js", events);
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
|
||||
.getService(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
var hwindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
|
||||
.getService(Components.interfaces.nsIAppShellService)
|
||||
.hiddenDOMWindow;
|
||||
|
||||
var uuidgen = Components.classes["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Components.interfaces.nsIUUIDGenerator);
|
||||
|
||||
function AsyncRead (session) {
|
||||
this.session = session;
|
||||
}
|
||||
AsyncRead.prototype.onStartRequest = function (request, context) {};
|
||||
AsyncRead.prototype.onStopRequest = function (request, context, status) {
|
||||
this.session.onQuit();
|
||||
}
|
||||
AsyncRead.prototype.onDataAvailable = function (request, context, inputStream, offset, count) {
|
||||
var str = {};
|
||||
this.session.instream.readString(count, str);
|
||||
this.session.receive(str.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
globalRegistry = {};
|
||||
|
||||
function Bridge (session) {
|
||||
this.session = session;
|
||||
this.registry = globalRegistry;
|
||||
}
|
||||
Bridge.prototype._register = function (_type) {
|
||||
this.bridgeType = _type;
|
||||
if (_type == "backchannel") {
|
||||
events.addBackChannel(this);
|
||||
}
|
||||
}
|
||||
Bridge.prototype.register = function (uuid, _type) {
|
||||
try {
|
||||
this._register(_type);
|
||||
var passed = true;
|
||||
} catch(e) {
|
||||
if (typeof(e) == "string") {
|
||||
var exception = e;
|
||||
} else {
|
||||
var exception = {'name':e.name, 'message':e.message};
|
||||
}
|
||||
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
||||
}
|
||||
if (passed != undefined) {
|
||||
this.session.encodeOut({"result":true, 'eventType':'register', 'uuid':uuid});
|
||||
}
|
||||
|
||||
}
|
||||
Bridge.prototype._describe = function (obj) {
|
||||
var response = {};
|
||||
if (obj == null) {
|
||||
var type = "null";
|
||||
} else {
|
||||
var type = typeof(obj);
|
||||
}
|
||||
if (type == "object") {
|
||||
if (obj.length != undefined) {
|
||||
var type = "array";
|
||||
}
|
||||
response.attributes = [];
|
||||
for (i in obj) {
|
||||
response.attributes = response.attributes.concat(i);
|
||||
}
|
||||
}
|
||||
else if (type != "function"){
|
||||
response.data = obj;
|
||||
}
|
||||
response.type = type;
|
||||
return response;
|
||||
}
|
||||
Bridge.prototype.describe = function (uuid, obj) {
|
||||
var response = this._describe(obj);
|
||||
response.uuid = uuid;
|
||||
response.result = true;
|
||||
this.session.encodeOut(response);
|
||||
}
|
||||
Bridge.prototype._set = function (obj) {
|
||||
var uuid = uuidgen.generateUUID().toString();
|
||||
this.registry[uuid] = obj;
|
||||
return uuid;
|
||||
}
|
||||
Bridge.prototype.set = function (uuid, obj) {
|
||||
var ruuid = this._set(obj);
|
||||
this.session.encodeOut({'result':true, 'data':'bridge.registry["'+ruuid+'"]', 'uuid':uuid});
|
||||
}
|
||||
Bridge.prototype._setAttribute = function (obj, name, value) {
|
||||
obj[name] = value;
|
||||
return value;
|
||||
}
|
||||
Bridge.prototype.setAttribute = function (uuid, obj, name, value) {
|
||||
// log(uuid, String(obj), name, String(value))
|
||||
try {
|
||||
var result = this._setAttribute(obj, name, value);
|
||||
} catch(e) {
|
||||
if (typeof(e) == "string") {
|
||||
var exception = e;
|
||||
} else {
|
||||
var exception = {'name':e.name, 'message':e.message};
|
||||
}
|
||||
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
||||
}
|
||||
if (result != undefined) {
|
||||
this.set(uuid, obj[name]);
|
||||
}
|
||||
}
|
||||
Bridge.prototype._execFunction = function (func, args) {
|
||||
return func.apply(this.session.sandbox, args);
|
||||
}
|
||||
Bridge.prototype.execFunction = function (uuid, func, args) {
|
||||
try {
|
||||
var data = this._execFunction(func, args);
|
||||
var result = true;
|
||||
} catch(e) {
|
||||
if (typeof(e) == "string") {
|
||||
var exception = e;
|
||||
} else {
|
||||
var exception = {'name':e.name, 'message':e.message};
|
||||
}
|
||||
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
||||
var result = true;
|
||||
}
|
||||
if (data != undefined) {
|
||||
this.set(uuid, data);
|
||||
} else if ( result == true) {
|
||||
this.session.encodeOut({'result':true, 'data':null, 'uuid':uuid});
|
||||
} else {
|
||||
throw 'Something very bad happened.'
|
||||
}
|
||||
}
|
||||
|
||||
backstage = this;
|
||||
|
||||
function Session (transport) {
|
||||
this.transpart = transport;
|
||||
this.sandbox = Components.utils.Sandbox(backstage);
|
||||
this.sandbox.bridge = new Bridge(this);
|
||||
this.sandbox.openPreferences = hwindow.openPreferences;
|
||||
try {
|
||||
this.outputstream = transport.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
|
||||
this.outstream = Cc['@mozilla.org/intl/converter-output-stream;1']
|
||||
.createInstance(Ci.nsIConverterOutputStream);
|
||||
this.outstream.init(this.outputstream, 'UTF-8', 1024,
|
||||
Ci.nsIConverterOutputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
this.stream = transport.openInputStream(0, 0, 0);
|
||||
this.instream = Cc['@mozilla.org/intl/converter-input-stream;1']
|
||||
.createInstance(Ci.nsIConverterInputStream);
|
||||
this.instream.init(this.stream, 'UTF-8', 1024,
|
||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
} catch(e) {
|
||||
log('jsbridge: Error: ' + e);
|
||||
}
|
||||
// log('jsbridge: Accepted connection.');
|
||||
|
||||
this.pump = Cc['@mozilla.org/network/input-stream-pump;1']
|
||||
.createInstance(Ci.nsIInputStreamPump);
|
||||
this.pump.init(this.stream, -1, -1, 0, 0, false);
|
||||
this.pump.asyncRead(new AsyncRead(this), null);
|
||||
}
|
||||
Session.prototype.onOutput = function(string) {
|
||||
// log('jsbridge write: '+string)
|
||||
if (typeof(string) != "string") {
|
||||
throw "This is not a string"
|
||||
}
|
||||
try {
|
||||
this.outstream.writeString(string);
|
||||
this.outstream.flush();
|
||||
} catch (e) {
|
||||
throw "Why is this failing "+string
|
||||
}
|
||||
// this.outstream.write(string, string.length);
|
||||
};
|
||||
Session.prototype.onQuit = function() {
|
||||
this.instream.close();
|
||||
this.outstream.close();
|
||||
sessions.remove(session);
|
||||
};
|
||||
Session.prototype.encodeOut = function (obj) {
|
||||
try {
|
||||
this.onOutput(JSON.stringify(obj));
|
||||
} catch(e) {
|
||||
if (typeof(e) == "string") {
|
||||
var exception = e;
|
||||
} else {
|
||||
var exception = {'name':e.name, 'message':e.message};
|
||||
}
|
||||
this.onOutput(JSON.stringify({'result':false, 'exception':exception}));
|
||||
}
|
||||
|
||||
}
|
||||
Session.prototype.receive = function(data) {
|
||||
// log('jsbrige receive: '+data);
|
||||
Components.utils.evalInSandbox(data, this.sandbox);
|
||||
}
|
||||
|
||||
var sessions = {
|
||||
_list: [],
|
||||
add: function(session) {
|
||||
this._list.push(session);
|
||||
},
|
||||
remove: function(session) {
|
||||
var index = this._list.indexOf(session);
|
||||
if(index != -1)
|
||||
this._list.splice(index, 1);
|
||||
},
|
||||
get: function(index) {
|
||||
return this._list[index];
|
||||
},
|
||||
quit: function() {
|
||||
this._list.forEach(
|
||||
function(session) { session.quit; });
|
||||
this._list.splice(0, this._list.length);
|
||||
}
|
||||
};
|
||||
|
||||
function Server (port) {
|
||||
this.port = port;
|
||||
}
|
||||
Server.prototype.start = function () {
|
||||
try {
|
||||
this.serv = Cc['@mozilla.org/network/server-socket;1']
|
||||
.createInstance(Ci.nsIServerSocket);
|
||||
this.serv.init(this.port, true, -1);
|
||||
this.serv.asyncListen(this);
|
||||
// log('jsbridge: Listening...');
|
||||
} catch(e) {
|
||||
log('jsbridge: Exception: ' + e);
|
||||
}
|
||||
}
|
||||
Server.prototype.stop = function () {
|
||||
log('jsbridge: Closing...');
|
||||
this.serv.close();
|
||||
this.sessions.quit();
|
||||
this.serv = undefined;
|
||||
}
|
||||
Server.prototype.onStopListening = function (serv, status) {
|
||||
// Stub function
|
||||
}
|
||||
Server.prototype.onSocketAccepted = function (serv, transport) {
|
||||
session = new Session(transport)
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
function log(msg) {
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
function startServer(port) {
|
||||
var server = new Server(port)
|
||||
server.start()
|
||||
}
|
||||
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Corporation Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mikeal Rogers.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
def init_jsobject(cls, bridge, name, value, description=None):
|
||||
"""Initialize a js object that is a subclassed base type; int, str, unicode, float."""
|
||||
obj = cls(value)
|
||||
obj._bridge_ = bridge
|
||||
obj._name_ = name
|
||||
obj._description_ = description
|
||||
return obj
|
||||
|
||||
def create_jsobject(bridge, fullname, value=None, obj_type=None, override_set=False):
|
||||
"""Create a single JSObject for named object on other side of the bridge.
|
||||
|
||||
Handles various initization cases for different JSObjects."""
|
||||
description = bridge.describe(fullname)
|
||||
obj_type = description['type']
|
||||
value = description.get('data', None)
|
||||
|
||||
if value is True or value is False:
|
||||
return value
|
||||
|
||||
if js_type_cases.has_key(obj_type):
|
||||
cls, needs_init = js_type_cases[obj_type]
|
||||
# Objects that requires initialization are base types that have "values".
|
||||
if needs_init:
|
||||
obj = init_jsobject(cls, bridge, fullname, value, description=description)
|
||||
else:
|
||||
obj = cls(bridge, fullname, description=description, override_set=override_set)
|
||||
return obj
|
||||
else:
|
||||
# Something very bad happened, we don't have a representation for the given type.
|
||||
raise TypeError("Don't have a JSObject for javascript type "+obj_type)
|
||||
|
||||
class JSObject(object):
|
||||
"""Base javascript object representation."""
|
||||
_loaded_ = False
|
||||
|
||||
def __init__(self, bridge, name, override_set=False, description=None, *args, **kwargs):
|
||||
self._bridge_ = bridge
|
||||
if not override_set:
|
||||
name = bridge.set(name)['data']
|
||||
self._name_ = name
|
||||
self._description_ = description
|
||||
|
||||
def __jsget__(self, name):
|
||||
"""Abstraction for final step in get events; __getitem__ and __getattr__.
|
||||
"""
|
||||
result = create_jsobject(self._bridge_, name, override_set=True)
|
||||
return result
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Get the object from jsbridge.
|
||||
|
||||
Handles lazy loading of all attributes of self."""
|
||||
# A little hack so that ipython returns all the names.
|
||||
if name == '_getAttributeNames':
|
||||
return lambda : self._bridge_.describe(self._name_)['attributes']
|
||||
|
||||
attributes = self._bridge_.describe(self._name_)['attributes']
|
||||
if name in attributes:
|
||||
return self.__jsget__(self._name_+'["'+name+'"]')
|
||||
else:
|
||||
raise AttributeError(name+" is undefined.")
|
||||
|
||||
__getitem__ = __getattr__
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
"""Set the given JSObject as an attribute of this JSObject and make proper javascript
|
||||
assignment on the other side of the bridge."""
|
||||
if name.startswith('_') and name.endswith('_'):
|
||||
return object.__setattr__(self, name, value)
|
||||
|
||||
response = self._bridge_.setAttribute(self._name_, name, value)
|
||||
object.__setattr__(self, name, create_jsobject(self._bridge_, response['data'], override_set=True))
|
||||
|
||||
__setitem__ = __setattr__
|
||||
|
||||
class JSFunction(JSObject):
|
||||
"""Javascript function represenation.
|
||||
|
||||
Returns a JSObject instance for the serialized js type with
|
||||
name set to the full javascript call for this function.
|
||||
"""
|
||||
|
||||
def __init__(self, bridge, name, override_set=False, description=None, *args, **kwargs):
|
||||
self._bridge_ = bridge
|
||||
self._name_ = name
|
||||
self._description_ = description
|
||||
|
||||
def __call__(self, *args):
|
||||
response = self._bridge_.execFunction(self._name_, args)
|
||||
if response['data'] is not None:
|
||||
return create_jsobject(self._bridge_, response['data'], override_set=True)
|
||||
|
||||
|
||||
class JSString(JSObject, unicode):
|
||||
"Javascript string representation."
|
||||
__init__ = unicode.__init__
|
||||
|
||||
class JSInt(JSObject, int):
|
||||
"""Javascript number representation for Python int."""
|
||||
__init__ = int.__init__
|
||||
|
||||
class JSFloat(JSObject, float):
|
||||
"""Javascript number representation for Python float."""
|
||||
__init__ = float.__init__
|
||||
|
||||
class JSUndefined(JSObject):
|
||||
"""Javascript undefined representation."""
|
||||
__str__ = lambda self : "undefined"
|
||||
|
||||
def __cmp__(self, other):
|
||||
if isinstance(other, JSUndefined):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
__nonzero__ = lambda self: False
|
||||
|
||||
js_type_cases = {'function' :(JSFunction, False,),
|
||||
'object' :(JSObject, False,),
|
||||
'array' :(JSObject, False,),
|
||||
'string' :(JSString, True,),
|
||||
'number' :(JSFloat, True,),
|
||||
'undefined':(JSUndefined, False,),
|
||||
'null' :(JSObject, False,),
|
||||
}
|
||||
py_type_cases = {unicode :JSString,
|
||||
str :JSString,
|
||||
int :JSInt,
|
||||
float :JSFloat,
|
||||
}
|
|
@ -1,306 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Corporation Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mikeal Rogers.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import asyncore
|
||||
import socket
|
||||
import select
|
||||
import logging
|
||||
import uuid
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
|
||||
try:
|
||||
import json as simplejson
|
||||
from json.encoder import encode_basestring_ascii, encode_basestring
|
||||
except ImportError:
|
||||
import simplejson
|
||||
from simplejson.encoder import encode_basestring_ascii, encode_basestring
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class JavaScriptException(Exception): pass
|
||||
|
||||
class Telnet(asyncore.dispatcher):
|
||||
def __init__(self, host, port):
|
||||
self.host, self.port = host, port
|
||||
asyncore.dispatcher.__init__(self)
|
||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.connect((host, port))
|
||||
self.buffer = ''
|
||||
self.logger = logger
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def handle_close(self):
|
||||
"""override method of asyncore.dispatcher"""
|
||||
self.close()
|
||||
|
||||
def handle_expt(self): self.close() # connection failed, shutdown
|
||||
|
||||
def writable(self):
|
||||
return (len(self.buffer) > 0)
|
||||
|
||||
def handle_write(self):
|
||||
sent = self.send(self.buffer)
|
||||
self.buffer = self.buffer[sent:]
|
||||
|
||||
def read_all(self):
|
||||
import socket
|
||||
data = ''
|
||||
while 1:
|
||||
try:
|
||||
data += self.recv(4096)
|
||||
except socket.error:
|
||||
return data
|
||||
|
||||
def handle_read(self):
|
||||
self.data = self.read_all()
|
||||
self.process_read(self.data)
|
||||
|
||||
read_callback = lambda self, data: None
|
||||
|
||||
decoder = simplejson.JSONDecoder()
|
||||
|
||||
class JSObjectEncoder(simplejson.JSONEncoder):
|
||||
"""Encoder that supports jsobject references by name."""
|
||||
|
||||
def encode(self, o):
|
||||
import jsobjects
|
||||
if isinstance(o, jsobjects.JSObject):
|
||||
return o._name_
|
||||
else:
|
||||
return simplejson.JSONEncoder.encode(self, o)
|
||||
|
||||
def _iterencode(self, o, markers=None):
|
||||
import jsobjects
|
||||
if isinstance(o, jsobjects.JSObject):
|
||||
yield o._name_
|
||||
elif isinstance(o, basestring):
|
||||
if self.ensure_ascii:
|
||||
encoder = encode_basestring_ascii
|
||||
else:
|
||||
encoder = encode_basestring
|
||||
_encoding = self.encoding
|
||||
if (_encoding is not None and isinstance(o, str)
|
||||
and not (_encoding == 'utf-8')):
|
||||
o = o.decode(_encoding)
|
||||
yield encoder(o)
|
||||
elif o is None:
|
||||
yield 'null'
|
||||
elif o is True:
|
||||
yield 'true'
|
||||
elif o is False:
|
||||
yield 'false'
|
||||
elif isinstance(o, (int, long)):
|
||||
yield str(o)
|
||||
elif isinstance(o, float):
|
||||
yield getattr(simplejson.encoder, 'floatstr', simplejson.encoder._floatstr)(o, self.allow_nan)
|
||||
elif isinstance(o, (list, tuple)):
|
||||
for chunk in self._iterencode_list(o, markers):
|
||||
yield chunk
|
||||
elif isinstance(o, dict):
|
||||
for chunk in self._iterencode_dict(o, markers):
|
||||
yield chunk
|
||||
else:
|
||||
if markers is not None:
|
||||
markerid = id(o)
|
||||
if markerid in markers:
|
||||
raise ValueError("Circular reference detected")
|
||||
markers[markerid] = o
|
||||
for chunk in self._iterencode_default(o, markers):
|
||||
yield chunk
|
||||
if markers is not None:
|
||||
del markers[markerid]
|
||||
|
||||
encoder = JSObjectEncoder()
|
||||
|
||||
class JSBridgeDisconnectError(Exception):
|
||||
"""exception raised when an unexpected disconect happens"""
|
||||
|
||||
|
||||
class Bridge(Telnet):
|
||||
|
||||
trashes = []
|
||||
reading = False
|
||||
sbuffer = ''
|
||||
events_list = []
|
||||
|
||||
callbacks = {}
|
||||
|
||||
bridge_type = "bridge"
|
||||
|
||||
registered = False
|
||||
timeout_ctr = 0. # global timeout counter
|
||||
|
||||
def __init__(self, host, port, timeout=60.):
|
||||
"""
|
||||
- timeout : failsafe timeout for each call to run in seconds
|
||||
"""
|
||||
self.timeout = timeout
|
||||
Telnet.__init__(self, host, port)
|
||||
sleep(.1)
|
||||
|
||||
# XXX we've actually already connected in Telnet
|
||||
self.connect((host, port))
|
||||
|
||||
def handle_connect(self):
|
||||
self.register()
|
||||
|
||||
def run(self, _uuid, exec_string, interval=.2, raise_exeption=True):
|
||||
|
||||
|
||||
exec_string += '\r\n'
|
||||
self.send(exec_string)
|
||||
|
||||
while _uuid not in self.callbacks.keys():
|
||||
|
||||
Bridge.timeout_ctr += interval
|
||||
if Bridge.timeout_ctr > self.timeout:
|
||||
print 'Timeout: %s' % exec_string
|
||||
raise JSBridgeDisconnectError("Connection timed out")
|
||||
|
||||
sleep(interval)
|
||||
try:
|
||||
self.send('')
|
||||
except socket.error:
|
||||
raise JSBridgeDisconnectError("Connected disconnected")
|
||||
|
||||
Bridge.timeout_ctr = 0. # reset the counter
|
||||
|
||||
callback = self.callbacks.pop(_uuid)
|
||||
if callback['result'] is False and raise_exeption is True:
|
||||
raise JavaScriptException(callback['exception'])
|
||||
return callback
|
||||
|
||||
def register(self):
|
||||
_uuid = str(uuid.uuid1())
|
||||
self.send('bridge.register("'+_uuid+'", "'+self.bridge_type+'")\r\n')
|
||||
self.registered = True
|
||||
|
||||
def execFunction(self, func_name, args, interval=.25):
|
||||
_uuid = str(uuid.uuid1())
|
||||
exec_args = [encoder.encode(_uuid), func_name, encoder.encode(args)]
|
||||
return self.run(_uuid, 'bridge.execFunction('+ ', '.join(exec_args)+')', interval)
|
||||
|
||||
def setAttribute(self, obj_name, name, value):
|
||||
_uuid = str(uuid.uuid1())
|
||||
exec_args = [encoder.encode(_uuid), obj_name, encoder.encode(name), encoder.encode(value)]
|
||||
return self.run(_uuid, 'bridge.setAttribute('+', '.join(exec_args)+')')
|
||||
|
||||
def set(self, obj_name):
|
||||
_uuid = str(uuid.uuid1())
|
||||
return self.run(_uuid, 'bridge.set('+', '.join([encoder.encode(_uuid), obj_name])+')')
|
||||
|
||||
def describe(self, obj_name):
|
||||
_uuid = str(uuid.uuid1())
|
||||
return self.run(_uuid, 'bridge.describe('+', '.join([encoder.encode(_uuid), obj_name])+')')
|
||||
|
||||
def fire_callbacks(self, obj):
|
||||
self.callbacks[obj['uuid']] = obj
|
||||
|
||||
def process_read(self, data):
|
||||
"""Parse out json objects and fire callbacks."""
|
||||
self.sbuffer += data
|
||||
self.reading = True
|
||||
self.parsing = True
|
||||
while self.parsing:
|
||||
# Remove erroneus data in front of callback object
|
||||
index = self.sbuffer.find('{')
|
||||
if index is not -1 and index is not 0:
|
||||
self.sbuffer = self.sbuffer[index:]
|
||||
# Try to get a json object from the data stream
|
||||
try:
|
||||
obj, index = decoder.raw_decode(self.sbuffer)
|
||||
except Exception, e:
|
||||
self.parsing = False
|
||||
# If we got an object fire the callback infra
|
||||
if self.parsing:
|
||||
self.fire_callbacks(obj)
|
||||
self.sbuffer = self.sbuffer[index:]
|
||||
|
||||
class BackChannel(Bridge):
|
||||
|
||||
bridge_type = "backchannel"
|
||||
|
||||
def __init__(self, host, port):
|
||||
Bridge.__init__(self, host, port)
|
||||
self.uuid_listener_index = {}
|
||||
self.event_listener_index = {}
|
||||
self.global_listeners = []
|
||||
|
||||
def fire_callbacks(self, obj):
|
||||
"""Handle all callback fireing on json objects pulled from the data stream."""
|
||||
self.fire_event(**dict([(str(key), value,) for key, value in obj.items()]))
|
||||
|
||||
def add_listener(self, callback, uuid=None, eventType=None):
|
||||
if uuid is not None:
|
||||
self.uuid_listener_index.setdefault(uuid, []).append(callback)
|
||||
if eventType is not None:
|
||||
self.event_listener_index.setdefault(eventType, []).append(callback)
|
||||
|
||||
def add_global_listener(self, callback):
|
||||
self.global_listeners.append(callback)
|
||||
|
||||
def fire_event(self, eventType=None, uuid=None, result=None, exception=None):
|
||||
Bridge.timeout_ctr = 0. # reset the counter
|
||||
event = eventType
|
||||
if uuid is not None and self.uuid_listener_index.has_key(uuid):
|
||||
for callback in self.uuid_listener_index[uuid]:
|
||||
callback(result)
|
||||
if event is not None and self.event_listener_index.has_key(event):
|
||||
for callback in self.event_listener_index[event]:
|
||||
callback(result)
|
||||
for listener in self.global_listeners:
|
||||
listener(eventType, result)
|
||||
|
||||
thread = None
|
||||
|
||||
def create_network(hostname, port):
|
||||
back_channel = BackChannel(hostname, port)
|
||||
bridge = Bridge(hostname, port)
|
||||
global thread
|
||||
if not thread or not thread.isAlive():
|
||||
def do():
|
||||
try: asyncore.loop(use_poll=True)
|
||||
except select.error:pass
|
||||
|
||||
thread = Thread(target=do)
|
||||
getattr(thread, 'setDaemon', lambda x : None)(True)
|
||||
thread.start()
|
||||
|
||||
return back_channel, bridge
|
|
@ -1,76 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Corporation Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mikeal Rogers.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import sys
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
desc = """Python to JavaScript bridge interface."""
|
||||
summ = """A powerful and extensible Python to JavaScript bridge interface."""
|
||||
|
||||
PACKAGE_NAME = "jsbridge"
|
||||
PACKAGE_VERSION = "2.4.1rc2"
|
||||
|
||||
requires = ['mozrunner == 2.5.2rc2']
|
||||
|
||||
if not sys.version.startswith('2.6'):
|
||||
requires.append('simplejson')
|
||||
|
||||
setup(name=PACKAGE_NAME,
|
||||
version=PACKAGE_VERSION,
|
||||
description=desc,
|
||||
long_description=summ,
|
||||
author='Mikeal Rogers, Mozilla',
|
||||
author_email='mikeal.rogers@gmail.com',
|
||||
url='http://github.com/mozautomation/mozmill',
|
||||
license='http://www.apache.org/licenses/LICENSE-2.0',
|
||||
packages=find_packages(exclude=['test']),
|
||||
include_package_data=True,
|
||||
package_data = {'': ['*.js', '*.css', '*.html', '*.txt', '*.xpi', '*.rdf', '*.xul', '*.jsm', '*.xml' 'extension'],},
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
jsbridge = jsbridge:cli
|
||||
""",
|
||||
platforms =['Any'],
|
||||
install_requires = requires,
|
||||
classifiers=['Development Status :: 4 - Beta',
|
||||
'Environment :: Console',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
]
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
recursive-include docs *
|
||||
recursive-include mozmill/extension *
|
|
@ -1,75 +0,0 @@
|
|||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview over all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
|
||||
clean:
|
||||
-rm -rf _build/*
|
||||
|
||||
html:
|
||||
mkdir -p _build/html _build/doctrees
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in _build/html."
|
||||
|
||||
pickle:
|
||||
mkdir -p _build/pickle _build/doctrees
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
web: pickle
|
||||
|
||||
json:
|
||||
mkdir -p _build/json _build/doctrees
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
mkdir -p _build/htmlhelp _build/doctrees
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in _build/htmlhelp."
|
||||
|
||||
latex:
|
||||
mkdir -p _build/latex _build/doctrees
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in _build/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
mkdir -p _build/changes _build/doctrees
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
|
||||
@echo
|
||||
@echo "The overview file is in _build/changes."
|
||||
|
||||
linkcheck:
|
||||
mkdir -p _build/linkcheck _build/doctrees
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in _build/linkcheck/output.txt."
|
|
@ -1,188 +0,0 @@
|
|||
:mod:`mozmill` --- Full automation of XULRunner applications.
|
||||
=============================================================
|
||||
|
||||
.. module:: mozmill
|
||||
:synopsis: Full automation of XULRunner applications.
|
||||
.. moduleauthor:: Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
.. sectionauthor:: Mikeal Rogers <mikeal.rogers@gmail.com>
|
||||
|
||||
Command Line Usage
|
||||
------------------
|
||||
|
||||
The mozmill command line is versatile and includes a fair amount of debugging options. Even though all these options are available mozmill should run by default without any arguments and find your locally installed Firefox and run with mozmill.
|
||||
|
||||
In most modes, ctrl-c will shut down Firefox and exit out of the mozmill Python side as well.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ mozmill
|
||||
|
||||
.. cmdoption:: -h, --help
|
||||
|
||||
Show help message.
|
||||
|
||||
.. cmdoption:: -b <binary>, --binary <binary>
|
||||
|
||||
Specify application binary location.
|
||||
|
||||
Default :class:`mozrunner.Profile` and :class:`mozrunner.Runner` are still
|
||||
:class:`mozrunner.FirefoxProfile` and :class:`mozrunner.FirefoxRunner`. You can
|
||||
change this by creating your own command line utility by subclassing :class:`CLI`
|
||||
|
||||
.. cmdoption:: -d <defaultprofile>
|
||||
|
||||
Specify the path to the default **clean** profile used to create new profiles.
|
||||
|
||||
.. cmdoption:: -n, --no-new-profile
|
||||
|
||||
Do not create a new fresh profile.
|
||||
|
||||
.. cmdoption:: -p <profile>, --profile <profile>
|
||||
|
||||
Specifies a profile to use. Must be used with --no-new-profile.
|
||||
|
||||
.. cmdoption:: -w <plugins>, --plugins <plugins>
|
||||
|
||||
Comma seperated list of additional paths to plugins to install.
|
||||
|
||||
Plugins can be either .xpi zip compressed extensions or deflated extension directories.
|
||||
|
||||
.. cmdoption:: -l <logfile>, --logfile <logfile>
|
||||
|
||||
Log all events to *logfile*.
|
||||
|
||||
.. cmdoption:: --report <uri>
|
||||
|
||||
*Currently in development.*
|
||||
|
||||
POST results to given brasstacks results server at *uri*.
|
||||
|
||||
.. cmdoption:: -t <test>, --test <test>
|
||||
|
||||
Run *test*. Can be either single test file or directory of tests.
|
||||
|
||||
.. cmdoption:: --showall
|
||||
|
||||
Show all test output.
|
||||
|
||||
.. cmdoption:: -D, --debug
|
||||
|
||||
Install debugging extensions and run with -jsconole
|
||||
|
||||
.. cmdoption:: --show-errors
|
||||
|
||||
Print all logger errors to the console. When running tests only test failures and skipped
|
||||
tests are printed, this option print all other errors.
|
||||
|
||||
.. cmdoption:: -s, --shell
|
||||
|
||||
Starts a Python shell for debugging.
|
||||
|
||||
.. cmdoption:: -u, --usecode
|
||||
|
||||
By default --shell mode will use iPython if install and fall back to using the code module.
|
||||
This option forces the use of the code module instead of iPython even when installed.
|
||||
|
||||
.. cmdoption:: -P <port>, --port <port>
|
||||
|
||||
Specify port for jsbridge.
|
||||
|
||||
Command Line Class
|
||||
------------------
|
||||
|
||||
.. class:: CLI
|
||||
|
||||
Inherits from :class:`jsbridge.CLI` which inherits from :class:`mozrunner.CLI`.
|
||||
|
||||
All the heavy lifting is handled by jsbridge and mozrunner. If you are subclassing
|
||||
this in order to creat a new command line interface be sure to call :func:`super` on all
|
||||
related methods.
|
||||
|
||||
.. attribute:: runner_class
|
||||
|
||||
Default runner class. Should be subclass of :class:`mozrunner.Runner`.
|
||||
Defaults to :class:`mozrunner.FirefoxRunner`.
|
||||
|
||||
.. attribute:: profile_class
|
||||
|
||||
Default profile class. Should be subclass of :class:`mozruner.Profile`.
|
||||
Defaults to :class:`mozrunner.FirefoxProfile`.
|
||||
|
||||
Running MozMill from Python
|
||||
---------------------------
|
||||
|
||||
.. class:: MozMill([runner_class[, profile_class[, jsbridge_port]]])
|
||||
|
||||
Manages an instance of Firefox w/ jsbridge and provides facilities for running tests and
|
||||
keeping track of results with callback methods.
|
||||
|
||||
Default *runner_class* is :class:`mozrunner.FirefoxRunner`. Value should be a subclass of
|
||||
:class:`mozrunner.Runner`.
|
||||
|
||||
Default *profile_class* is :class:`mozrunner.FirefoxProfile`. Value should be a subclass of
|
||||
:class:`mozrunner.Profile`.
|
||||
|
||||
Default *jsbridge_port* is `24242`.
|
||||
|
||||
.. attribute:: runner_class
|
||||
|
||||
Set during initialization to subclass of :class:`mozrunner.Runner`.
|
||||
|
||||
.. attribute:: profile_class
|
||||
|
||||
Set during initialization to subclass of :class:`mozrunner.Profile`.
|
||||
|
||||
.. attribute:: jsbridge_port
|
||||
|
||||
Set during initialization to :class:`numbers.Integral`.
|
||||
|
||||
.. method:: start([profile[, runner]])
|
||||
|
||||
Start mozrunner and jsbridge pre-requisites.
|
||||
|
||||
*profile* should be an instance of a `mozrunner.Profile` subclass. If one is not passed
|
||||
an instance of `self.profile_class` is created. `self.profile` will be set to this
|
||||
value.
|
||||
|
||||
*runner* should be an instance of a `mozrunner.Runner` subclass. If one is not passed an
|
||||
instance of :attr:`runner_class` will be created. :attr:`runner` will be set to this value.
|
||||
|
||||
This method will also run `runner.start()` and :func:`mozrunner.wait_and_create_network`
|
||||
and sets :attr:`back_channel` and :attr:`bridge` to instances of
|
||||
:class:`jsbridge.BackChannel` and :class:`jsbridge.Bridge` respectively.
|
||||
|
||||
.. attribute:: profile
|
||||
|
||||
Set during :meth:`start` to subclass of :class:`mozrunner.Profile`.
|
||||
|
||||
.. attribute:: runner
|
||||
|
||||
Set during :meth:`start` to subclass of :class:`mozrunner.Runner`.
|
||||
|
||||
.. attribute:: back_channel
|
||||
|
||||
Set during :meth:`start` to subclass of :class:`jsbridge.BackChannel`.
|
||||
|
||||
.. attribute:: bridge
|
||||
|
||||
Set during :meth:`start` to subclass of :class:`jsbridge.Bridge`
|
||||
|
||||
.. method:: run_tests(test[, report])
|
||||
|
||||
Run *test* in live Firefox using :attr:`bridge`.
|
||||
|
||||
Adds local listeners :meth:`endTest_listener` and :meth:`endRunner_listener` to
|
||||
`"endTest"` and `"endRunner"` events using :meth:`jsbridge.BackChannel.add_listener` of
|
||||
:attr:`back_channel`.
|
||||
|
||||
When tests are done the results are posted to a results server at *report* if passed.
|
||||
|
||||
.. method:: endTest_listener(test)
|
||||
|
||||
When a test is finished the test object will be passed to this callback.
|
||||
|
||||
.. method:: endRunner_listener(obj)
|
||||
|
||||
When all the tests are done running this callback will be fired.
|
||||
|
||||
|
|
@ -1,657 +0,0 @@
|
|||
/**
|
||||
* Sphinx Doc Design
|
||||
*/
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
background-color: #11303d;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* :::: LAYOUT :::: */
|
||||
|
||||
div.document {
|
||||
background-color: #1c4e63;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 0 0 230px;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: white;
|
||||
padding: 0 20px 30px 20px;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: 230px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
padding: 9px 0 9px 0;
|
||||
text-align: center;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.related {
|
||||
background-color: #133f52;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
line-height: 30px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* ::: TOC :::: */
|
||||
div.sphinxsidebar h3 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
color: white;
|
||||
font-size: 1.4em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
color: white;
|
||||
font-size: 1.3em;
|
||||
font-weight: normal;
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.topless {
|
||||
margin: 5px 10px 10px 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #98dbcc;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* :::: MODULE CLOUD :::: */
|
||||
div.modulecloud {
|
||||
margin: -5px 10px 5px 10px;
|
||||
padding: 10px;
|
||||
line-height: 160%;
|
||||
border: 1px solid #cbe7e5;
|
||||
background-color: #f2fbfd;
|
||||
}
|
||||
|
||||
div.modulecloud a {
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
/* :::: SEARCH :::: */
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* :::: COMMON FORM STYLES :::: */
|
||||
|
||||
div.actions {
|
||||
padding: 5px 10px 5px 10px;
|
||||
border-top: 1px solid #cbe7e5;
|
||||
border-bottom: 1px solid #cbe7e5;
|
||||
background-color: #e0f6f4;
|
||||
}
|
||||
|
||||
form dl {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form dt {
|
||||
clear: both;
|
||||
float: left;
|
||||
min-width: 110px;
|
||||
margin-right: 10px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
input#homepage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.error {
|
||||
margin: 5px 20px 0 0;
|
||||
padding: 5px;
|
||||
border: 1px solid #d00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* :::: INDEX PAGE :::: */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* :::: INDEX STYLES :::: */
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable dl, table.indextable dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
form.pfform {
|
||||
margin: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
/* :::: GLOBAL STYLES :::: */
|
||||
|
||||
.docwarning {
|
||||
background-color: #ffe4e4;
|
||||
padding: 10px;
|
||||
margin: 0 -20px 0 -20px;
|
||||
border-bottom: 1px solid #f66;
|
||||
}
|
||||
|
||||
p.subhead {
|
||||
font-weight: bold;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #355f7c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
background-color: #f2f2f2;
|
||||
font-weight: normal;
|
||||
color: #20435c;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 20px -20px 10px -20px;
|
||||
padding: 3px 0 3px 10px;
|
||||
}
|
||||
|
||||
div.body h1 { margin-top: 0; font-size: 200%; }
|
||||
div.body h2 { font-size: 160%; }
|
||||
div.body h3 { font-size: 140%; }
|
||||
div.body h4 { font-size: 120%; }
|
||||
div.body h5 { font-size: 110%; }
|
||||
div.body h6 { font-size: 100%; }
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f;
|
||||
font-size: 0.8em;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #c60f0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
text-align: justify;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.fakelist {
|
||||
list-style: none;
|
||||
margin: 10px 0 10px 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/* "Footnotes" heading */
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Sidebars */
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px 7px 0 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* "Topics" */
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px 7px 0 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Admonitions */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.admonition dl {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
table.docutils {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 0;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
table.footnote td, table.footnote th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
dd p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.refcount {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
dt:target,
|
||||
.highlight {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 5px;
|
||||
background-color: #efc;
|
||||
color: #333;
|
||||
border: 1px solid #ac9;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 5px 0px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
padding: 0 1px 0 1px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
tt.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.footnote:target { background-color: #ffa }
|
||||
|
||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
form.comment {
|
||||
margin: 0;
|
||||
padding: 10px 30px 10px 30px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
form.comment h3 {
|
||||
background-color: #326591;
|
||||
color: white;
|
||||
margin: -10px -30px 10px -30px;
|
||||
padding: 5px;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
form.comment input,
|
||||
form.comment textarea {
|
||||
border: 1px solid #ccc;
|
||||
padding: 2px;
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
form.comment input[type="text"] {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
form.comment textarea {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* :::: PRINT :::: */
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
div#comments div.new-comment-box,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
/// XXX: make it cross browser
|
||||
|
||||
/**
|
||||
* make the code below compatible with browsers without
|
||||
* an installed firebug like debugger
|
||||
*/
|
||||
if (!window.console || !console.firebug) {
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
|
||||
"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
*/
|
||||
jQuery.urlencode = encodeURIComponent;
|
||||
|
||||
/**
|
||||
* This function returns the parsed url parameters of the
|
||||
* current request. Multiple values per key are supported,
|
||||
* it will always return arrays of strings for the value parts.
|
||||
*/
|
||||
jQuery.getQueryParameters = function(s) {
|
||||
if (typeof s == 'undefined')
|
||||
s = document.location.search;
|
||||
var parts = s.substr(s.indexOf('?') + 1).split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var tmp = parts[i].split('=', 2);
|
||||
var key = jQuery.urldecode(tmp[0]);
|
||||
var value = jQuery.urldecode(tmp[1]);
|
||||
if (key in result)
|
||||
result[key].push(value);
|
||||
else
|
||||
result[key] = [value];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* small function to check if an array contains
|
||||
* a given item.
|
||||
*/
|
||||
jQuery.contains = function(arr, item) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (arr[i] == item)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* highlight a given string on a jquery object by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
jQuery.fn.highlightText = function(text, className) {
|
||||
function highlight(node) {
|
||||
if (node.nodeType == 3) {
|
||||
var val = node.nodeValue;
|
||||
var pos = val.toLowerCase().indexOf(text);
|
||||
if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
|
||||
var span = document.createElement("span");
|
||||
span.className = className;
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling));
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
}
|
||||
}
|
||||
else if (!jQuery(node).is("button, select, textarea")) {
|
||||
jQuery.each(node.childNodes, function() {
|
||||
highlight(this)
|
||||
});
|
||||
}
|
||||
}
|
||||
return this.each(function() {
|
||||
highlight(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
var Documentation = {
|
||||
|
||||
init : function() {
|
||||
this.fixFirefoxAnchorBug();
|
||||
this.highlightSearchWords();
|
||||
this.initModIndex();
|
||||
},
|
||||
|
||||
/**
|
||||
* i18n support
|
||||
*/
|
||||
TRANSLATIONS : {},
|
||||
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
|
||||
LOCALE : 'unknown',
|
||||
|
||||
// gettext and ngettext don't access this so that the functions
|
||||
// can savely bound to a different name (_ = Documentation.gettext)
|
||||
gettext : function(string) {
|
||||
var translated = Documentation.TRANSLATIONS[string];
|
||||
if (typeof translated == 'undefined')
|
||||
return string;
|
||||
return (typeof translated == 'string') ? translated : translated[0];
|
||||
},
|
||||
|
||||
ngettext : function(singular, plural, n) {
|
||||
var translated = Documentation.TRANSLATIONS[singular];
|
||||
if (typeof translated == 'undefined')
|
||||
return (n == 1) ? singular : plural;
|
||||
return translated[Documentation.PLURALEXPR(n)];
|
||||
},
|
||||
|
||||
addTranslations : function(catalog) {
|
||||
for (var key in catalog.messages)
|
||||
this.TRANSLATIONS[key] = catalog.messages[key];
|
||||
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
|
||||
this.LOCALE = catalog.locale;
|
||||
},
|
||||
|
||||
/**
|
||||
* add context elements like header anchor links
|
||||
*/
|
||||
addContextElements : function() {
|
||||
$('div[@id] > :header:first').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this headline')).
|
||||
appendTo(this);
|
||||
});
|
||||
$('dt[@id]').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this definition')).
|
||||
appendTo(this);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* workaround a firefox stupidity
|
||||
*/
|
||||
fixFirefoxAnchorBug : function() {
|
||||
if (document.location.hash && $.browser.mozilla)
|
||||
window.setTimeout(function() {
|
||||
document.location.href += '';
|
||||
}, 10);
|
||||
},
|
||||
|
||||
/**
|
||||
* highlight the search words provided in the url in the text
|
||||
*/
|
||||
highlightSearchWords : function() {
|
||||
var params = $.getQueryParameters();
|
||||
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
|
||||
if (terms.length) {
|
||||
var body = $('div.body');
|
||||
window.setTimeout(function() {
|
||||
$.each(terms, function() {
|
||||
body.highlightText(this.toLowerCase(), 'highlight');
|
||||
});
|
||||
}, 10);
|
||||
$('<li class="highlight-link"><a href="javascript:Documentation.' +
|
||||
'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
|
||||
.appendTo($('.sidebar .this-page-menu'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* init the modindex toggle buttons
|
||||
*/
|
||||
initModIndex : function() {
|
||||
var togglers = $('img.toggler').click(function() {
|
||||
var src = $(this).attr('src');
|
||||
var idnum = $(this).attr('id').substr(7);
|
||||
console.log($('tr.cg-' + idnum).toggle());
|
||||
if (src.substr(-9) == 'minus.png')
|
||||
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
|
||||
else
|
||||
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
|
||||
}).css('display', '');
|
||||
if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
|
||||
togglers.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to hide the search marks again
|
||||
*/
|
||||
hideSearchWords : function() {
|
||||
$('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
|
||||
$('span.highlight').removeClass('highlight');
|
||||
},
|
||||
|
||||
/**
|
||||
* make the url absolute
|
||||
*/
|
||||
makeURL : function(relativeURL) {
|
||||
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
|
||||
},
|
||||
|
||||
/**
|
||||
* get the current relative url
|
||||
*/
|
||||
getCurrentURL : function() {
|
||||
var path = document.location.pathname;
|
||||
var parts = path.split(/\//);
|
||||
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
|
||||
if (this == '..')
|
||||
parts.pop();
|
||||
});
|
||||
var url = parts.join('/');
|
||||
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
|
||||
}
|
||||
};
|
||||
|
||||
// quick alias for translations
|
||||
_ = Documentation.gettext;
|
||||
|
||||
$(document).ready(function() {
|
||||
Documentation.init();
|
||||
});
|