From 75139375b76cb277546da2429d8e983ca6758f61 Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Wed, 2 Jan 2013 14:56:40 -0800 Subject: added addon-sdk-1.7, without any changes --- .../python-lib/cuddlefish/__init__.py | 797 +++++++++++++++++++++ .../python-lib/cuddlefish/_version.py | 171 +++++ .../cuddlefish/app-extension/application.ini | 11 + .../cuddlefish/app-extension/bootstrap.js | 216 ++++++ .../cuddlefish/app-extension/install.rdf | 33 + tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py | 34 + .../python-lib/cuddlefish/docs/__init__.py | 4 + .../python-lib/cuddlefish/docs/apiparser.py | 392 ++++++++++ .../python-lib/cuddlefish/docs/apirenderer.py | 302 ++++++++ .../python-lib/cuddlefish/docs/generate.py | 292 ++++++++ .../python-lib/cuddlefish/docs/renderapi.readme.md | 210 ++++++ .../python-lib/cuddlefish/docs/webdocs.py | 193 +++++ .../python-lib/cuddlefish/manifest.py | 751 +++++++++++++++++++ .../cuddlefish/mobile-utils/bootstrap.js | 78 ++ .../python-lib/cuddlefish/mobile-utils/install.rdf | 39 + .../python-lib/cuddlefish/options_defaults.py | 26 + .../python-lib/cuddlefish/options_xul.py | 64 ++ .../python-lib/cuddlefish/packaging.py | 435 +++++++++++ .../python-lib/cuddlefish/preflight.py | 77 ++ tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py | 115 +++ .../python-lib/cuddlefish/property_parser.py | 106 +++ tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py | 190 +++++ .../addon-sdk-1.7/python-lib/cuddlefish/runner.py | 696 ++++++++++++++++++ .../python-lib/cuddlefish/templates.py | 83 +++ .../python-lib/cuddlefish/tests/__init__.py | 65 ++ .../cuddlefish/tests/addons/simplest-test/main.js | 17 + .../tests/addons/simplest-test/package.json | 6 + .../addons/simplest-test/tests/test-minimal.js | 7 + .../packages/explicit-icon/explicit-icon.png | 0 .../packages/explicit-icon/explicit-icon64.png | 0 .../packages/explicit-icon/lib/main.js | 4 + .../packages/explicit-icon/package.json | 5 + .../packages/implicit-icon/icon.png | 0 .../packages/implicit-icon/icon64.png | 0 .../packages/implicit-icon/lib/main.js | 4 + .../packages/implicit-icon/package.json | 3 + .../bug-588119-files/packages/no-icon/lib/main.js | 4 + .../bug-588119-files/packages/no-icon/package.json | 3 + .../packages/bar/lib/bar-loader.js | 4 + .../bug-588661-files/packages/bar/package.json | 3 + .../packages/foo/lib/foo-loader.js | 4 + .../bug-588661-files/packages/foo/package.json | 4 + .../tests/bug-611495-files/jspath-one/docs/main.md | 5 + .../tests/bug-611495-files/jspath-one/lib/main.js | 8 + .../tests/bug-611495-files/jspath-one/package.json | 5 + .../packages/commonjs-naming/doc/foo.md | 5 + .../packages/commonjs-naming/lib/foo-loader.js | 5 + .../packages/commonjs-naming/package.json | 3 + .../packages/commonjs-naming/test/test-foo.js | 7 + .../packages/original-naming/docs/foo.md | 5 + .../packages/original-naming/lib/foo-loader.js | 5 + .../packages/original-naming/package.json | 3 + .../packages/original-naming/tests/test-foo.js | 7 + .../packages/default-lib/doc/foo.md | 5 + .../packages/default-lib/lib/foo.js | 5 + .../packages/default-lib/lib/loader.js | 5 + .../packages/default-lib/package.json | 3 + .../packages/default-lib/test/test-foo.js | 7 + .../packages/default-locale/locale/emptyFolder | 0 .../packages/default-locale/package.json | 1 + .../packages/default-root/doc/foo.md | 5 + .../bug-652227-files/packages/default-root/foo.js | 5 + .../packages/default-root/loader.js | 5 + .../packages/default-root/package.json | 3 + .../packages/default-root/test/test-foo.js | 7 + .../packages/explicit-dir-lib/alt-lib/foo.js | 5 + .../packages/explicit-dir-lib/alt-lib/loader.js | 5 + .../packages/explicit-dir-lib/doc/foo.md | 5 + .../packages/explicit-dir-lib/package.json | 4 + .../packages/explicit-dir-lib/test/test-foo.js | 7 + .../packages/explicit-lib/alt2-lib/foo.js | 5 + .../packages/explicit-lib/alt2-lib/loader.js | 5 + .../packages/explicit-lib/doc/foo.md | 5 + .../packages/explicit-lib/package.json | 4 + .../packages/explicit-lib/test/test-foo.js | 7 + .../packages/extra-options/docs/main.md | 5 + .../packages/extra-options/lib/main.js | 8 + .../packages/extra-options/package.json | 6 + .../tests/bug-715340-files/pkg-1-pack/package.json | 10 + .../bug-715340-files/pkg-2-unpack/package.json | 10 + .../tests/bug-715340-files/pkg-3-pack/package.json | 9 + .../packages/foo/lib/bar-e10s-adapter.js | 11 + .../e10s-adapter-files/packages/foo/lib/bar.js | 5 + .../e10s-adapter-files/packages/foo/lib/foo.js | 5 + .../e10s-adapter-files/packages/foo/package.json | 1 + .../cuddlefish/tests/linker-files/five/lib/main.js | 5 + .../tests/linker-files/five/package.json | 3 + .../linker-files/four-deps/four-a/lib/misc.js | 5 + .../linker-files/four-deps/four-a/package.json | 4 + .../linker-files/four-deps/four-a/topfiles/main.js | 5 + .../cuddlefish/tests/linker-files/four/lib/main.js | 5 + .../tests/linker-files/four/package.json | 3 + .../cuddlefish/tests/linker-files/one/lib/main.js | 9 + .../tests/linker-files/one/lib/subdir/three.js | 6 + .../cuddlefish/tests/linker-files/one/lib/two.js | 8 + .../cuddlefish/tests/linker-files/one/package.json | 4 + .../tests/linker-files/seven/data/text.data | 1 + .../tests/linker-files/seven/lib/main.js | 6 + .../tests/linker-files/seven/lib/unused.js | 5 + .../tests/linker-files/seven/package.json | 4 + .../tests/linker-files/six/lib/unused.js | 5 + .../cuddlefish/tests/linker-files/six/package.json | 3 + .../tests/linker-files/six/unreachable.js | 5 + .../linker-files/three-deps/three-a/data/msg.txt | 1 + .../three-deps/three-a/data/subdir/submsg.txt | 1 + .../linker-files/three-deps/three-a/lib/main.js | 8 + .../three-deps/three-a/lib/subdir/subfile.js | 5 + .../linker-files/three-deps/three-a/lib/unused.js | 5 + .../three-deps/three-a/locale/fr-FR.properties | 5 + .../linker-files/three-deps/three-a/package.json | 3 + .../linker-files/three-deps/three-b/lib/main.js | 5 + .../three-deps/three-b/locale/fr-FR.properties | 6 + .../linker-files/three-deps/three-b/package.json | 3 + .../linker-files/three-deps/three-c/lib/main.js | 5 + .../linker-files/three-deps/three-c/lib/sub/foo.js | 6 + .../three-deps/three-c/locale/fr-FR.properties | 9 + .../linker-files/three-deps/three-c/package.json | 3 + .../tests/linker-files/three/lib/main.js | 8 + .../tests/linker-files/three/package.json | 3 + .../tests/linker-files/three/tests/nontest.js | 5 + .../tests/linker-files/three/tests/test-one.js | 5 + .../tests/linker-files/three/tests/test-two.js | 5 + .../packages/no-prefs/lib/main.js | 4 + .../packages/no-prefs/package.json | 6 + .../packages/simple-prefs/lib/main.js | 4 + .../packages/simple-prefs/package.json | 18 + .../static-files/doc/dev-guide-source/index.md | 7 + .../static-files/doc/dev-guide-source/no_h1.md | 7 + .../static-files/doc/static-files/another.html | 5 + .../tests/static-files/doc/static-files/base.html | 161 +++++ .../tests/static-files/doc/static-files/index.html | 27 + .../tests/static-files/docs/APIreference.html | 469 ++++++++++++ .../tests/static-files/docs/APIsample.md | 162 +++++ .../packages/aardvark/doc/aardvark-feeder.md | 12 + .../static-files/packages/aardvark/doc/main.md | 0 .../static-files/packages/aardvark/lib/ignore_me | 3 + .../static-files/packages/aardvark/lib/main.js | 8 + .../aardvark/lib/surprise.js/ignore_me_too | 2 + .../static-files/packages/aardvark/package.json | 7 + .../packages/anteater_files/lib/main.js | 8 + .../packages/anteater_files/package.json | 8 + .../static-files/packages/api-utils/lib/loader.js | 7 + .../static-files/packages/api-utils/package.json | 5 + .../packages/barbeque/lib/bar-module.js | 7 + .../static-files/packages/barbeque/package.json | 4 + .../static-files/packages/minimal/docs/main.md | 5 + .../static-files/packages/minimal/lib/main.js | 8 + .../static-files/packages/minimal/package.json | 4 + .../xpi-template/components/harness.js | 8 + .../python-lib/cuddlefish/tests/test_apiparser.py | 538 ++++++++++++++ .../cuddlefish/tests/test_apirenderer.py | 31 + .../python-lib/cuddlefish/tests/test_generate.py | 173 +++++ .../python-lib/cuddlefish/tests/test_init.py | 148 ++++ .../python-lib/cuddlefish/tests/test_licenses.py | 88 +++ .../python-lib/cuddlefish/tests/test_linker.py | 234 ++++++ .../python-lib/cuddlefish/tests/test_manifest.py | 254 +++++++ .../python-lib/cuddlefish/tests/test_packaging.py | 116 +++ .../python-lib/cuddlefish/tests/test_preflight.py | 147 ++++ .../cuddlefish/tests/test_property_parser.py | 75 ++ .../python-lib/cuddlefish/tests/test_rdf.py | 45 ++ .../python-lib/cuddlefish/tests/test_runner.py | 27 + .../python-lib/cuddlefish/tests/test_util.py | 22 + .../python-lib/cuddlefish/tests/test_version.py | 28 + .../python-lib/cuddlefish/tests/test_webdocs.py | 97 +++ .../python-lib/cuddlefish/tests/test_xpi.py | 412 +++++++++++ tools/addon-sdk-1.7/python-lib/cuddlefish/util.py | 23 + .../python-lib/cuddlefish/version_comparator.py | 206 ++++++ tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py | 155 ++++ 168 files changed, 9641 insertions(+) create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/_version.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/application.ini create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/bootstrap.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/install.rdf create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apiparser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apirenderer.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/generate.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/renderapi.readme.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/docs/webdocs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/manifest.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/bootstrap.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/install.rdf create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/options_defaults.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/options_xul.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/packaging.py create mode 100755 tools/addon-sdk-1.7/python-lib/cuddlefish/preflight.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/property_parser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/runner.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/templates.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/__init__.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon64.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon64.png create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/lib/bar-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/docs/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/lib/foo-loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/tests/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/locale/emptyFolder create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/doc/foo.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/test/test-foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-1-pack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-2-unpack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-3-pack/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar-e10s-adapter.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/lib/misc.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/topfiles/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/subdir/three.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/two.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/data/text.data create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/unreachable.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/msg.txt create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/subdir/submsg.txt create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/subdir/subfile.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/unused.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/sub/foo.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/locale/fr-FR.properties create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/nontest.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-one.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-two.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/index.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/no_h1.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/another.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/base.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/index.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIreference.html create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIsample.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/aardvark-feeder.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/ignore_me create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/surprise.js/ignore_me_too create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/lib/loader.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/lib/bar-module.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/docs/main.md create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/lib/main.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/package.json create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/xpi-template/components/harness.js create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apiparser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apirenderer.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_generate.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_init.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_licenses.py create mode 100755 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_linker.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_manifest.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_packaging.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_preflight.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_property_parser.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_rdf.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_runner.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_util.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_version.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_webdocs.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_xpi.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/util.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/version_comparator.py create mode 100644 tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py (limited to 'tools/addon-sdk-1.7/python-lib/cuddlefish') diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py new file mode 100644 index 0000000..9792eb9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py @@ -0,0 +1,797 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import sys +import os +import optparse +import webbrowser + +from copy import copy +import simplejson as json +from cuddlefish import packaging +from cuddlefish._version import get_versions + +MOZRUNNER_BIN_NOT_FOUND = 'Mozrunner could not locate your binary' +MOZRUNNER_BIN_NOT_FOUND_HELP = """ +I can't find the application binary in any of its default locations +on your system. Please specify one using the -b/--binary option. +""" + +UPDATE_RDF_FILENAME = "%s.update.rdf" +XPI_FILENAME = "%s.xpi" + +usage = """ +%prog [options] command [command-specific options] + +Supported Commands: + docs - view web-based documentation + init - create a sample addon in an empty directory + test - run tests + run - run program + xpi - generate an xpi + +Internal Commands: + sdocs - export static documentation + testcfx - test the cfx tool + testex - test all example code + testpkgs - test all installed packages + testall - test whole environment + +Experimental and internal commands and options are not supported and may be +changed or removed in the future. +""" + +global_options = [ + (("-v", "--verbose",), dict(dest="verbose", + help="enable lots of output", + action="store_true", + default=False)), + ] + +parser_groups = ( + ("Supported Command-Specific Options", [ + (("", "--update-url",), dict(dest="update_url", + help="update URL in install.rdf", + metavar=None, + default=None, + cmds=['xpi'])), + (("", "--update-link",), dict(dest="update_link", + help="generate update.rdf", + metavar=None, + default=None, + cmds=['xpi'])), + (("-p", "--profiledir",), dict(dest="profiledir", + help=("profile directory to pass to " + "app"), + metavar=None, + default=None, + cmds=['test', 'run', 'testex', + 'testpkgs', 'testall'])), + (("-b", "--binary",), dict(dest="binary", + help="path to app binary", + metavar=None, + default=None, + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--binary-args",), dict(dest="cmdargs", + help=("additional arguments passed to the " + "binary"), + metavar=None, + default=None, + cmds=['run', 'test'])), + (("", "--dependencies",), dict(dest="dep_tests", + help="include tests for all deps", + action="store_true", + default=False, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("", "--times",), dict(dest="iterations", + type="int", + help="number of times to run tests", + default=1, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("-f", "--filter",), dict(dest="filter", + help=("only run tests whose filenames " + "match FILENAME and optionally " + "match TESTNAME, both regexps"), + metavar="FILENAME[:TESTNAME]", + default=None, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("-g", "--use-config",), dict(dest="config", + help="use named config from local.json", + metavar=None, + default="default", + cmds=['test', 'run', 'xpi', 'testex', + 'testpkgs', 'testall'])), + (("", "--templatedir",), dict(dest="templatedir", + help="XULRunner app/ext. template", + metavar=None, + default=None, + cmds=['run', 'xpi'])), + (("", "--package-path",), dict(dest="packagepath", action="append", + help="extra directories for package search", + metavar=None, + default=[], + cmds=['run', 'xpi', 'test'])), + (("", "--extra-packages",), dict(dest="extra_packages", + help=("extra packages to include, " + "comma-separated. Default is " + "'addon-kit'."), + metavar=None, + default="addon-kit", + cmds=['run', 'xpi', 'test', 'testex', + 'testpkgs', 'testall', + 'testcfx'])), + (("", "--pkgdir",), dict(dest="pkgdir", + help=("package dir containing " + "package.json; default is " + "current directory"), + metavar=None, + default=None, + cmds=['run', 'xpi', 'test'])), + (("", "--static-args",), dict(dest="static_args", + help="extra harness options as JSON", + type="json", + metavar=None, + default="{}", + cmds=['run', 'xpi'])), + ] + ), + + ("Experimental Command-Specific Options", [ + (("-a", "--app",), dict(dest="app", + help=("app to run: firefox (default), fennec, " + "fennec-on-device, xulrunner or " + "thunderbird"), + metavar=None, + type="choice", + choices=["firefox", "fennec", + "fennec-on-device", "thunderbird", + "xulrunner"], + default="firefox", + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--no-run",), dict(dest="no_run", + help=("Instead of launching the " + "application, just show the command " + "for doing so. Use this to launch " + "the application in a debugger like " + "gdb."), + action="store_true", + default=False, + cmds=['run', 'test'])), + (("", "--no-strip-xpi",), dict(dest="no_strip_xpi", + help="retain unused modules in XPI", + action="store_true", + default=False, + cmds=['xpi'])), + (("", "--force-mobile",), dict(dest="enable_mobile", + help="Force compatibility with Firefox Mobile", + action="store_true", + default=False, + cmds=['run', 'test', 'xpi', 'testall'])), + (("", "--mobile-app",), dict(dest="mobile_app_name", + help=("Name of your Android application to " + "use. Possible values: 'firefox', " + "'firefox_beta', 'fennec_aurora', " + "'fennec' (for nightly)."), + metavar=None, + default=None, + cmds=['run', 'test', 'testall'])), + (("", "--harness-option",), dict(dest="extra_harness_option_args", + help=("Extra properties added to " + "harness-options.json"), + action="append", + metavar="KEY=VALUE", + default=[], + cmds=['xpi'])), + (("", "--stop-on-error",), dict(dest="stopOnError", + help="Stop running tests after the first failure", + action="store_true", + metavar=None, + default=False, + cmds=['test', 'testex', 'testpkgs'])), + ] + ), + + ("Internal Command-Specific Options", [ + (("", "--addons",), dict(dest="addons", + help=("paths of addons to install, " + "comma-separated"), + metavar=None, + default=None, + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--baseurl",), dict(dest="baseurl", + help=("root of static docs tree: " + "for example: 'http://me.com/the_docs/'"), + metavar=None, + default='', + cmds=['sdocs'])), + (("", "--test-runner-pkg",), dict(dest="test_runner_pkg", + help=("name of package " + "containing test runner " + "program (default is " + "test-harness)"), + default="test-harness", + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + # --keydir was removed in 1.0b5, but we keep it around in the options + # parser to make life easier for frontends like FlightDeck which + # might still pass it. It can go away once the frontends are updated. + (("", "--keydir",), dict(dest="keydir", + help=("obsolete, ignored"), + metavar=None, + default=None, + cmds=['test', 'run', 'xpi', 'testex', + 'testpkgs', 'testall'])), + (("", "--e10s",), dict(dest="enable_e10s", + help="enable out-of-process Jetpacks", + action="store_true", + default=False, + cmds=['test', 'run', 'testex', 'testpkgs'])), + (("", "--logfile",), dict(dest="logfile", + help="log console output to file", + metavar=None, + default=None, + cmds=['run', 'test', 'testex', 'testpkgs'])), + # TODO: This should default to true once our memory debugging + # issues are resolved; see bug 592774. + (("", "--profile-memory",), dict(dest="profileMemory", + help=("profile memory usage " + "(default is false)"), + type="int", + action="store", + default=0, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + ] + ), + ) + +def find_parent_package(cur_dir): + tail = True + while tail: + if os.path.exists(os.path.join(cur_dir, 'package.json')): + return cur_dir + cur_dir, tail = os.path.split(cur_dir) + return None + +def check_json(option, opt, value): + # We return the parsed JSON here; see bug 610816 for background on why. + try: + return json.loads(value) + except ValueError: + raise optparse.OptionValueError("Option %s must be JSON." % opt) + +class CfxOption(optparse.Option): + TYPES = optparse.Option.TYPES + ('json',) + TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER) + TYPE_CHECKER['json'] = check_json + +def parse_args(arguments, global_options, usage, version, parser_groups, + defaults=None): + parser = optparse.OptionParser(usage=usage.strip(), option_class=CfxOption, + version=version) + + def name_cmp(a, b): + # a[0] = name sequence + # a[0][0] = short name (possibly empty string) + # a[0][1] = long name + names = [] + for seq in (a, b): + names.append(seq[0][0][1:] if seq[0][0] else seq[0][1][2:]) + return cmp(*names) + + global_options.sort(name_cmp) + for names, opts in global_options: + parser.add_option(*names, **opts) + + for group_name, options in parser_groups: + group = optparse.OptionGroup(parser, group_name) + options.sort(name_cmp) + for names, opts in options: + if 'cmds' in opts: + cmds = opts['cmds'] + del opts['cmds'] + cmds.sort() + if not 'help' in opts: + opts['help'] = "" + opts['help'] += " (%s)" % ", ".join(cmds) + group.add_option(*names, **opts) + parser.add_option_group(group) + + if defaults: + parser.set_defaults(**defaults) + + (options, args) = parser.parse_args(args=arguments) + + if not args: + parser.print_help() + parser.exit() + + return (options, args) + +# all tests emit progress messages to stderr, not stdout. (the mozrunner +# console output goes to stderr and is hard to change, and +# unittest.TextTestRunner prefers stderr, so we send everything else there +# too, to keep all the messages in order) + +def test_all(env_root, defaults): + fail = False + + print >>sys.stderr, "Testing cfx..." + sys.stderr.flush() + result = test_cfx(env_root, defaults['verbose']) + if result.failures or result.errors: + fail = True + + if not fail or not defaults.get("stopOnError"): + print >>sys.stderr, "Testing all examples..." + sys.stderr.flush() + + try: + test_all_examples(env_root, defaults) + except SystemExit, e: + fail = (e.code != 0) or fail + + if not fail or not defaults.get("stopOnError"): + print >>sys.stderr, "Testing all packages..." + sys.stderr.flush() + try: + test_all_packages(env_root, defaults) + except SystemExit, e: + fail = (e.code != 0) or fail + + if fail: + print >>sys.stderr, "Some tests were unsuccessful." + sys.exit(1) + print >>sys.stderr, "All tests were successful. Ship it!" + sys.exit(0) + +def test_cfx(env_root, verbose): + import cuddlefish.tests + + # tests write to stderr. flush everything before and after to avoid + # confusion later. + sys.stdout.flush(); sys.stderr.flush() + olddir = os.getcwd() + os.chdir(env_root) + retval = cuddlefish.tests.run(verbose) + os.chdir(olddir) + sys.stdout.flush(); sys.stderr.flush() + return retval + +def test_all_examples(env_root, defaults): + examples_dir = os.path.join(env_root, "examples") + examples = [dirname for dirname in os.listdir(examples_dir) + if os.path.isdir(os.path.join(examples_dir, dirname))] + examples.sort() + fail = False + for dirname in examples: + print >>sys.stderr, "Testing %s..." % dirname + sys.stderr.flush() + try: + run(arguments=["test", + "--pkgdir", + os.path.join(examples_dir, dirname)], + defaults=defaults, + env_root=env_root) + except SystemExit, e: + fail = (e.code != 0) or fail + if fail and defaults.get("stopOnError"): + break + + if fail: + print >>sys.stderr, "Some examples tests were unsuccessful." + sys.exit(-1) + +def test_all_packages(env_root, defaults): + packages_dir = os.path.join(env_root, "packages") + packages = [dirname for dirname in os.listdir(packages_dir) + if os.path.isdir(os.path.join(packages_dir, dirname))] + packages.sort() + print >>sys.stderr, "Testing all available packages: %s." % (", ".join(packages)) + sys.stderr.flush() + fail = False + for dirname in packages: + print >>sys.stderr, "Testing %s..." % dirname + sys.stderr.flush() + try: + run(arguments=["test", + "--pkgdir", + os.path.join(packages_dir, dirname)], + defaults=defaults, + env_root=env_root) + except SystemExit, e: + fail = (e.code != 0) or fail + if fail and defaults.get('stopOnError'): + break + if fail: + print >>sys.stderr, "Some package tests were unsuccessful." + sys.exit(-1) + +def get_config_args(name, env_root): + local_json = os.path.join(env_root, "local.json") + if not (os.path.exists(local_json) and + os.path.isfile(local_json)): + if name == "default": + return [] + else: + print >>sys.stderr, "File does not exist: %s" % local_json + sys.exit(1) + local_json = packaging.load_json_file(local_json) + if 'configs' not in local_json: + print >>sys.stderr, "'configs' key not found in local.json." + sys.exit(1) + if name not in local_json.configs: + if name == "default": + return [] + else: + print >>sys.stderr, "No config found for '%s'." % name + sys.exit(1) + config = local_json.configs[name] + if type(config) != list: + print >>sys.stderr, "Config for '%s' must be a list of strings." % name + sys.exit(1) + return config + +def initializer(env_root, args, out=sys.stdout, err=sys.stderr): + from templates import MAIN_JS, PACKAGE_JSON, README_DOC, MAIN_JS_DOC, TEST_MAIN_JS + path = os.getcwd() + addon = os.path.basename(path) + # if more than one argument + if len(args) > 1: + print >>err, 'Too many arguments.' + return 1 + # avoid clobbering existing files, but we tolerate things like .git + existing = [fn for fn in os.listdir(path) if not fn.startswith(".")] + if existing: + print >>err, 'This command must be run in an empty directory.' + return 1 + for d in ['lib','data','test','doc']: + os.mkdir(os.path.join(path,d)) + print >>out, '*', d, 'directory created' + open('README.md','w').write(README_DOC % {'name':addon}) + print >>out, '* README.md written' + open('package.json','w').write(PACKAGE_JSON % {'name':addon.lower(), + 'fullName':addon }) + print >>out, '* package.json written' + open(os.path.join(path,'test','test-main.js'),'w').write(TEST_MAIN_JS) + print >>out, '* test/test-main.js written' + open(os.path.join(path,'lib','main.js'),'w').write(MAIN_JS) + print >>out, '* lib/main.js written' + open(os.path.join(path,'doc','main.md'),'w').write(MAIN_JS_DOC) + print >>out, '* doc/main.md written' + print >>out, '\nYour sample add-on is now ready.' + print >>out, 'Do "cfx test" to test it and "cfx run" to try it. Have fun!' + return 0 + +def buildJID(target_cfg): + if "id" in target_cfg: + jid = target_cfg["id"] + else: + import uuid + jid = str(uuid.uuid4()) + if not ("@" in jid or jid.startswith("{")): + jid = jid + "@jetpack" + return jid + +def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, + defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT'), + stdout=sys.stdout): + versions = get_versions() + sdk_version = versions["version"] + display_version = "Add-on SDK %s (%s)" % (sdk_version, versions["full"]) + parser_kwargs = dict(arguments=arguments, + global_options=global_options, + parser_groups=parser_groups, + usage=usage, + version=display_version, + defaults=defaults) + + (options, args) = parse_args(**parser_kwargs) + + config_args = get_config_args(options.config, env_root); + + # reparse configs with arguments from local.json + if config_args: + parser_kwargs['arguments'] += config_args + (options, args) = parse_args(**parser_kwargs) + + command = args[0] + + if command == "init": + initializer(env_root, args) + return + if command == "testpkgs": + test_all_packages(env_root, defaults=options.__dict__) + return + elif command == "testex": + test_all_examples(env_root, defaults=options.__dict__) + return + elif command == "testall": + test_all(env_root, defaults=options.__dict__) + return + elif command == "testcfx": + test_cfx(env_root, options.verbose) + return + elif command == "docs": + from cuddlefish.docs import generate + if len(args) > 1: + docs_home = generate.generate_named_file(env_root, filename=args[1]) + else: + docs_home = generate.generate_local_docs(env_root) + webbrowser.open(docs_home) + return + elif command == "sdocs": + from cuddlefish.docs import generate + filename = generate.generate_static_docs(env_root) + print >>stdout, "Wrote %s." % filename + return + elif command not in ["xpi", "test", "run"]: + print >>sys.stderr, "Unknown command: %s" % command + print >>sys.stderr, "Try using '--help' for assistance." + sys.exit(1) + + target_cfg_json = None + if not target_cfg: + if not options.pkgdir: + options.pkgdir = find_parent_package(os.getcwd()) + if not options.pkgdir: + print >>sys.stderr, ("cannot find 'package.json' in the" + " current directory or any parent.") + sys.exit(1) + else: + options.pkgdir = os.path.abspath(options.pkgdir) + if not os.path.exists(os.path.join(options.pkgdir, 'package.json')): + print >>sys.stderr, ("cannot find 'package.json' in" + " %s." % options.pkgdir) + sys.exit(1) + + target_cfg_json = os.path.join(options.pkgdir, 'package.json') + target_cfg = packaging.get_config_in_dir(options.pkgdir) + + # At this point, we're either building an XPI or running Jetpack code in + # a Mozilla application (which includes running tests). + + use_main = False + inherited_options = ['verbose', 'enable_e10s'] + enforce_timeouts = False + + if command == "xpi": + use_main = True + elif command == "test": + if 'tests' not in target_cfg: + target_cfg['tests'] = [] + inherited_options.extend(['iterations', 'filter', 'profileMemory', + 'stopOnError']) + enforce_timeouts = True + elif command == "run": + use_main = True + else: + assert 0, "shouldn't get here" + + if use_main and 'main' not in target_cfg: + # If the user supplies a template dir, then the main + # program may be contained in the template. + if not options.templatedir: + print >>sys.stderr, "package.json does not have a 'main' entry." + sys.exit(1) + + if not pkg_cfg: + pkg_cfg = packaging.build_config(env_root, target_cfg, options.packagepath) + + target = target_cfg.name + + # TODO: Consider keeping a cache of dynamic UUIDs, based + # on absolute filesystem pathname, in the root directory + # or something. + if command in ('xpi', 'run'): + from cuddlefish.preflight import preflight_config + if target_cfg_json: + config_was_ok, modified = preflight_config(target_cfg, + target_cfg_json) + if not config_was_ok: + if modified: + # we need to re-read package.json . The safest approach + # is to re-run the "cfx xpi"/"cfx run" command. + print >>sys.stderr, ("package.json modified: please re-run" + " 'cfx %s'" % command) + else: + print >>sys.stderr, ("package.json needs modification:" + " please update it and then re-run" + " 'cfx %s'" % command) + sys.exit(1) + # if we make it this far, we have a JID + else: + assert command == "test" + + jid = buildJID(target_cfg) + + targets = [target] + if command == "test": + targets.append(options.test_runner_pkg) + + extra_packages = [] + if options.extra_packages: + extra_packages = options.extra_packages.split(",") + if extra_packages: + targets.extend(extra_packages) + target_cfg.extra_dependencies = extra_packages + + deps = packaging.get_deps_for_targets(pkg_cfg, targets) + + from cuddlefish.manifest import build_manifest, ModuleNotFoundError + # Figure out what loader files should be scanned. This is normally + # computed inside packaging.generate_build_for_target(), by the first + # dependent package that defines a "loader" property in its package.json. + # This property is interpreted as a filename relative to the top of that + # file, and stored as a path in build.loader . generate_build_for_target() + # cannot be called yet (it needs the list of used_deps that + # build_manifest() computes, but build_manifest() needs the list of + # loader files that it computes). We could duplicate or factor out this + # build.loader logic, but that would be messy, so instead we hard-code + # the choice of loader for manifest-generation purposes. In practice, + # this means that alternative loaders probably won't work with + # --strip-xpi. + assert packaging.DEFAULT_LOADER == "api-utils" + assert pkg_cfg.packages["api-utils"].loader == "lib/cuddlefish.js" + cuddlefish_js_path = os.path.join(pkg_cfg.packages["api-utils"].root_dir, + "lib", "cuddlefish.js") + loader_modules = [("api-utils", "lib", "cuddlefish", cuddlefish_js_path)] + scan_tests = command == "test" + test_filter_re = None + if scan_tests and options.filter: + test_filter_re = options.filter + if ":" in options.filter: + test_filter_re = options.filter.split(":")[0] + try: + manifest = build_manifest(target_cfg, pkg_cfg, deps, + scan_tests, test_filter_re, + loader_modules) + except ModuleNotFoundError, e: + print str(e) + sys.exit(1) + used_deps = manifest.get_used_packages() + if command == "test": + # The test runner doesn't appear to link against any actual packages, + # because it loads everything at runtime (invisible to the linker). + # If we believe that, we won't set up URI mappings for anything, and + # tests won't be able to run. + used_deps = deps + for xp in extra_packages: + if xp not in used_deps: + used_deps.append(xp) + + build = packaging.generate_build_for_target( + pkg_cfg, target, used_deps, + include_dep_tests=options.dep_tests + ) + + harness_options = { + 'jetpackID': jid, + 'staticArgs': options.static_args, + 'name': target, + } + + harness_options.update(build) + + extra_environment = {} + if command == "test": + # This should be contained in the test runner package. + # maybe just do: target_cfg.main = 'test-harness/run-tests' + harness_options['main'] = 'test-harness/run-tests' + harness_options['mainPath'] = manifest.get_manifest_entry("test-harness", "lib", "run-tests").get_path() + else: + harness_options['main'] = target_cfg.get('main') + harness_options['mainPath'] = manifest.top_path + extra_environment["CFX_COMMAND"] = command + + for option in inherited_options: + harness_options[option] = getattr(options, option) + + harness_options['metadata'] = packaging.get_metadata(pkg_cfg, used_deps) + + harness_options['sdkVersion'] = sdk_version + + packaging.call_plugins(pkg_cfg, used_deps) + + retval = 0 + + if options.templatedir: + app_extension_dir = os.path.abspath(options.templatedir) + else: + mydir = os.path.dirname(os.path.abspath(__file__)) + app_extension_dir = os.path.join(mydir, "app-extension") + + + if target_cfg.get('preferences'): + harness_options['preferences'] = target_cfg.get('preferences') + + harness_options['manifest'] = manifest.get_harness_options_manifest() + harness_options['allTestModules'] = manifest.get_all_test_modules() + + from cuddlefish.rdf import gen_manifest, RDFUpdate + + manifest_rdf = gen_manifest(template_root_dir=app_extension_dir, + target_cfg=target_cfg, + jid=jid, + update_url=options.update_url, + bootstrap=True, + enable_mobile=options.enable_mobile) + + if command == "xpi" and options.update_link: + rdf_name = UPDATE_RDF_FILENAME % target_cfg.name + print >>stdout, "Exporting update description to %s." % rdf_name + update = RDFUpdate() + update.add(manifest_rdf, options.update_link) + open(rdf_name, "w").write(str(update)) + + # ask the manifest what files were used, so we can construct an XPI + # without the rest. This will include the loader (and everything it + # uses) because of the "loader_modules" starting points we passed to + # build_manifest earlier + used_files = None + if command == "xpi": + used_files = set(manifest.get_used_files()) + + if options.no_strip_xpi: + used_files = None # disables the filter, includes all files + + if command == 'xpi': + from cuddlefish.xpi import build_xpi + extra_harness_options = {} + for kv in options.extra_harness_option_args: + key,value = kv.split("=", 1) + extra_harness_options[key] = value + xpi_path = XPI_FILENAME % target_cfg.name + print >>stdout, "Exporting extension to %s." % xpi_path + build_xpi(template_root_dir=app_extension_dir, + manifest=manifest_rdf, + xpi_path=xpi_path, + harness_options=harness_options, + limit_to=used_files, + extra_harness_options=extra_harness_options) + else: + from cuddlefish.runner import run_app + + if options.profiledir: + options.profiledir = os.path.expanduser(options.profiledir) + options.profiledir = os.path.abspath(options.profiledir) + + if options.addons is not None: + options.addons = options.addons.split(",") + + try: + retval = run_app(harness_root_dir=app_extension_dir, + manifest_rdf=manifest_rdf, + harness_options=harness_options, + app_type=options.app, + binary=options.binary, + profiledir=options.profiledir, + verbose=options.verbose, + enforce_timeouts=enforce_timeouts, + logfile=options.logfile, + addons=options.addons, + args=options.cmdargs, + extra_environment=extra_environment, + norun=options.no_run, + used_files=used_files, + enable_mobile=options.enable_mobile, + mobile_app_name=options.mobile_app_name) + except ValueError, e: + print "" + print "A given cfx option has an inappropriate value:" + print >>sys.stderr, " " + " \n ".join(str(e).split("\n")) + retval = -1 + except Exception, e: + if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND): + print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip() + retval = -1 + else: + raise + sys.exit(retval) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/_version.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/_version.py new file mode 100644 index 0000000..61e7178 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/_version.py @@ -0,0 +1,171 @@ + +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (build by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by versioneer-0.6 +# (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = " (HEAD, 1.7rc2, 1.7, origin/stabilization, stabilization)" +git_full = "075becdd649500d845fa15aea09129e6aef02bef" + + +import subprocess + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError, e: + if verbose: + print "unable to run %s" % args[0] + print e + return None + stdout = p.communicate()[0].strip() + if p.returncode != 0: + if verbose: + print "unable to run %s (error)" % args[0] + return None + return stdout + + +import sys +import re +import os.path + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + refs.discard(ref) + # Assume all version tags have a digit. git's %d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, thus + # the containing directory is the root of the source tree), or someone + # ran a project-specific entry point (and this code is in _version.py, + # thus the containing directory is somewhere deeper in the source tree). + # This only gets called if the git-archive 'subst' variables were *not* + # expanded, and _version.py hasn't already been rewritten with a short + # version string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + if not os.path.exists(os.path.join(root, ".git")): + return {} + + GIT = "git" + if sys.platform == "win32": + GIT = "git.cmd" + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print "tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + try: + here = os.path.abspath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to _version.py, when + # this is used by the runtime. Invert this to find the root from + # __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + except NameError: + # try a couple different things to handle py2exe, bbfreeze, and + # non-CPython implementations which don't do __file__. This code + # either lives in versioneer.py (used by setup.py) or _version.py + # (used by the runtime). In the versioneer.py case, sys.argv[0] will + # be setup.py, in the root of the source tree. In the _version.py + # case, we have no idea what sys.argv[0] is (some + # application-specific runner). + root = os.path.dirname(os.path.abspath(sys.argv[0])) + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print "dirname '%s' doesn't start with prefix '%s'" % (dirname, parentdir_prefix) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +tag_prefix = "" +parentdir_prefix = "addon-sdk-" +versionfile_source = "python-lib/cuddlefish/_version.py" + +def get_versions(): + variables = { "refnames": git_refnames, "full": git_full } + ver = versions_from_expanded_variables(variables, tag_prefix) + if not ver: + ver = versions_from_vcs(tag_prefix, versionfile_source) + if not ver: + ver = versions_from_parentdir(parentdir_prefix, versionfile_source) + if not ver: + ver = {"version": "unknown", "full": ""} + return ver + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/application.ini b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/application.ini new file mode 100644 index 0000000..6cec69a --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/application.ini @@ -0,0 +1,11 @@ +[App] +Vendor=Varma +Name=Test App +Version=1.0 +BuildID=20060101 +Copyright=Copyright (c) 2009 Atul Varma +ID=xulapp@toolness.com + +[Gecko] +MinVersion=1.9.2.0 +MaxVersion=2.0.* diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/bootstrap.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/bootstrap.js new file mode 100644 index 0000000..661f2bb --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/bootstrap.js @@ -0,0 +1,216 @@ +/* vim:set ts=2 sw=2 sts=2 expandtab */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp + +"use strict"; + +const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, + results: Cr, manager: Cm } = Components; +const ioService = Cc['@mozilla.org/network/io-service;1']. + getService(Ci.nsIIOService); +const resourceHandler = ioService.getProtocolHandler('resource') + .QueryInterface(Ci.nsIResProtocolHandler); +const XMLHttpRequest = CC('@mozilla.org/xmlextras/xmlhttprequest;1', + 'nsIXMLHttpRequest'); +const prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + QueryInterface(Ci.nsIPrefBranch2); +const mozIJSSubScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. + getService(Ci.mozIJSSubScriptLoader); + +const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable', + 'install', 'uninstall', 'upgrade', 'downgrade' ]; + +let loader = null; +let loaderUri = null; + +const URI = __SCRIPT_URI_SPEC__.replace(/bootstrap\.js$/, ""); + +// Initializes default preferences +function setDefaultPrefs() { + let branch = prefs.getDefaultBranch(""); + let prefLoaderScope = { + pref: function(key, val) { + switch (typeof val) { + case "boolean": + branch.setBoolPref(key, val); + break; + case "number": + if (val % 1 == 0) // number must be a integer, otherwise ignore it + branch.setIntPref(key, val); + break; + case "string": + branch.setCharPref(key, val); + break; + } + } + }; + + let uri = ioService.newURI( + "defaults/preferences/prefs.js", + null, + ioService.newURI(URI, null, null)); + + // if there is a prefs.js file, then import the default prefs + try { + // setup default prefs + mozIJSSubScriptLoader.loadSubScript(uri.spec, prefLoaderScope); + } + // errors here should not kill addon + catch (e) { + Cu.reportError(e); + } +} + +// Gets the topic that fit best as application startup event, in according with +// the current application (e.g. Firefox, Fennec, Thunderbird...) +function getAppStartupTopic() { + // The following mapping of application names to GUIDs was taken + // from `xul-app` module. They should keep in sync, so if you change one, + // change the other too! + let ids = { + Firefox: '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}', + Mozilla: '{86c18b42-e466-45a9-ae7a-9b95ba6f5640}', + Sunbird: '{718e30fb-e89b-41dd-9da7-e25a45638b28}', + SeaMonkey: '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}', + Fennec: '{aa3c5121-dab2-40e2-81ca-7ea25febc110}', + Thunderbird: '{3550f703-e582-4d05-9a08-453d09bdfdc6}' + }; + + let id = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULAppInfo).ID; + + switch (id) { + case ids.Firefox: + case ids.SeaMonkey: + return 'sessionstore-windows-restored'; + case ids.Thunderbird: + return 'mail-startup-done'; + // Temporary, until Fennec Birch will support sessionstore event + case ids.Fennec: + default: + return 'final-ui-startup'; + } +} + +// Utility function that synchronously reads local resource from the given +// `uri` and returns content string. +function readURI(uri) { + let ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + let channel = ioservice.newChannel(uri, "UTF-8", null); + let stream = channel.open(); + + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream); + cstream.init(stream, "UTF-8", 0, 0); + + let str = {}; + let data = ""; + let read = 0; + do { + read = cstream.readString(0xffffffff, str); + data += str.value; + } while (read != 0); + + cstream.close(); + + return data; +} + +// Function takes `topic` to be observer via `nsIObserverService` and returns +// promise that will be delivered once notification is published. +function on(topic) { + return function promise(deliver) { + const observerService = Cc['@mozilla.org/observer-service;1']. + getService(Ci.nsIObserverService); + + observerService.addObserver({ + observe: function observer(subject, topic, data) { + observerService.removeObserver(this, topic); + deliver(subject, topic, data); + } + }, topic, false); + } +} + +// We don't do anything on install & uninstall yet, but in a future +// we should allow add-ons to cleanup after uninstall. +function install(data, reason) {} +function uninstall(data, reason) {} + +function startup(data, reason) { + // TODO: When bug 564675 is implemented this will no longer be needed + // Always set the default prefs, because they disappear on restart + setDefaultPrefs(); + + // TODO: Maybe we should perform read harness-options.json asynchronously, + // since we can't do anything until 'sessionstore-windows-restored' anyway. + let options = JSON.parse(readURI(URI + './harness-options.json')); + options.loadReason = REASON[reason]; + + // URI for the root of the XPI file. + // 'jar:' URI if the addon is packed, 'file:' URI otherwise. + // (Used by l10n module in order to fetch `locale` folder) + options.rootURI = data.resourceURI.spec; + + // Register a new resource "domain" for this addon which is mapping to + // XPI's `resources` folder. + // Generate the domain name by using jetpack ID, which is the extension ID + // by stripping common characters that doesn't work as a domain name: + let uuidRe = + /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/; + let domain = options.jetpackID.toLowerCase() + .replace(/@/g, "-at-") + .replace(/\./g, "-dot-") + .replace(uuidRe, "$1"); + + let resourcesUri = ioService.newURI(URI + '/resources/', null, null); + resourceHandler.setSubstitution(domain, resourcesUri); + options.uriPrefix = "resource://" + domain + "/"; + + // Import loader module using `Cu.imports` and bootstrap module loader. + loaderUri = options.uriPrefix + options.loader; + loader = Cu.import(loaderUri).Loader.new(options); + + // Creating a promise, that will be delivered once application is ready. + // If application is at startup then promise is delivered on + // the application startup topic, otherwise it's delivered immediately. + let promise = reason === APP_STARTUP ? on(getAppStartupTopic()) : + function promise(deliver) deliver() + + // Once application is ready we spawn a new process with main module of + // on add-on. + promise(function() { + try { + loader.spawn(options.main, options.mainPath); + } catch (error) { + // If at this stage we have an error only thing we can do is report about + // it via error console. Keep in mind that error won't automatically show + // up there when called via observerService. + Cu.reportError(error); + throw error; + } + }); + +}; + +function shutdown(data, reason) { + // If loader is already present unload it, since add-on is disabled. + if (loader) { + reason = REASON[reason]; + let system = loader.require('api-utils/system'); + loader.unload(reason); + + // Bug 724433: We need to unload JSM otherwise it will stay alive + // and keep a reference to this compartment. + Cu.unload(loaderUri); + loader = null; + + // If add-on is lunched via `cfx run` we need to use `system.exit` to let + // cfx know we're done (`cfx test` will take care of exit so we don't do + // anything here). + if (system.env.CFX_COMMAND === 'run' && reason === 'shutdown') + system.exit(0); + } +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/install.rdf b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/install.rdf new file mode 100644 index 0000000..8bbcacb --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/app-extension/install.rdf @@ -0,0 +1,33 @@ + + + + + + + xulapp@toolness.com + 1.0 + 2 + true + false + + + + + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + 12.0 + 13.* + + + + + Test App + Harness for tests. + Mozilla Corporation + + + + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py new file mode 100644 index 0000000..5efa79f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/bunch.py @@ -0,0 +1,34 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Taken from Paver's paver.options module. + +class Bunch(dict): + """A dictionary that provides attribute-style access.""" + + def __repr__(self): + keys = self.keys() + keys.sort() + args = ', '.join(['%s=%r' % (key, self[key]) for key in keys]) + return '%s(%s)' % (self.__class__.__name__, args) + + def __getitem__(self, key): + item = dict.__getitem__(self, key) + if callable(item): + return item() + return item + + def __getattr__(self, name): + try: + return self[name] + except KeyError: + raise AttributeError(name) + + __setattr__ = dict.__setitem__ + + def __delattr__(self, name): + try: + del self[name] + except KeyError: + raise AttributeError(name) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/__init__.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/__init__.py new file mode 100644 index 0000000..5501cd4 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/__init__.py @@ -0,0 +1,4 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apiparser.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apiparser.py new file mode 100644 index 0000000..b6ccf22 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apiparser.py @@ -0,0 +1,392 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import sys, re, textwrap + +VERSION = 4 + +class ParseError(Exception): + # args[1] is the line number that caused the problem + def __init__(self, why, lineno): + self.why = why + self.lineno = lineno + def __str__(self): + return ("ParseError: the JS API docs were unparseable on line %d: %s" % + (self.lineno, self.why)) + +class Accumulator: + def __init__(self, holder, firstline): + self.holder = holder + self.firstline = firstline + self.otherlines = [] + def addline(self, line): + self.otherlines.append(line) + def finish(self): + # take a list of strings like: + # "initial stuff" (this is in firstline) + # " more stuff" (this is in lines[0]) + # " yet more stuff" + # " indented block" + # " indented block" + # " nonindented stuff" (lines[-1]) + # + # calculate the indentation level by looking at all but the first + # line, and removing the whitespace they all have in common. Then + # join the results with newlines and return a single string. + pieces = [] + if self.firstline: + pieces.append(self.firstline) + if self.otherlines: + pieces.append(textwrap.dedent("\n".join(self.otherlines))) + self.holder["description"] = "\n".join(pieces) + + +class APIParser: + def parse(self, lines, lineno): + api = {"line_number": lineno + 1} +# assign the name from the first line, of the form "" + title_line = lines[lineno].rstrip("\n") + api["name"] = self._parse_title_line(title_line, lineno + 1) + lineno += 1 +# finished with the first line, assigned the name + working_set = self._initialize_working_set() + props = [] + currentPropHolder = api +# fetch the next line, of the form "@tag [name] {datatype} description" +# and parse it into tag, info, description + tag, info, firstline = self._parseTypeLine(lines[lineno], lineno + 1) + api["type"] = tag +# if this API element is a property then datatype must be set + if tag == 'property': + api['datatype'] = info['datatype'] + # info is ignored + currentAccumulator = Accumulator(api, firstline) + lineno += 1 + while (lineno) < len(lines): + line = lines[lineno].rstrip("\n") + # accumulate any multiline descriptive text belonging to + # the preceding "@" section + if self._is_description_line(line): + currentAccumulator.addline(line) + else: + currentAccumulator.finish() + if line.startswith(" element + tag, info, desc = self._parseTypeLine(line, lineno + 1) + currentAccumulator = Accumulator(info, desc) + if tag == "prop": + # build up props[] + props.append(info) + elif tag == "returns": + # close off the @prop list + if props and currentPropHolder: + currentPropHolder["props"] = props + props = [] + api["returns"] = info + currentPropHolder = info + elif tag == "param": + # close off the @prop list + if props and currentPropHolder: + currentPropHolder["props"] = props + props = [] + working_set["params"].append(info) + currentPropHolder = info + elif tag == "argument": + # close off the @prop list + if props and currentPropHolder: + currentPropHolder["props"] = props + props = [] + working_set["arguments"].append(info) + currentPropHolder = info + else: + raise ParseError("unknown '@' section header %s in \ + '%s'" % (tag, line), lineno + 1) + lineno += 1 + raise ParseError("closing tag not found for ", lineno + 1) + + def _parse_title_line(self, title_line, lineno): + if "name" not in title_line: + raise ParseError("Opening tag must have a name attribute.", + lineno) + m = re.search("name=['\"]{0,1}([-\w\.]*?)['\"]", title_line) + if not m: + raise ParseError("No value for name attribute found in " + "opening tag.", lineno) + return m.group(1) + + def _is_description_line(self, line): + return not ( (line.lstrip().startswith("@")) or + (line.lstrip().startswith(" 0: + signature += params[0]["name"] + for param in params[1:]: + signature += ", " + param["name"] + signature += ")" + api_element["signature"] = signature + + def _assemble_api_element(self, api_element, working_set): + # if any of this working set's lists are non-empty, + # add it to the current api element + if (api_element["type"] == "constructor") or \ + (api_element["type"] == "function") or \ + (api_element["type"] == "method"): + self._assemble_signature(api_element, working_set["params"]) + if len(working_set["params"]) > 0: + api_element["params"] = working_set["params"] + if len(working_set["properties"]) > 0: + api_element["properties"] = working_set["properties"] + if len(working_set["constructors"]) > 0: + api_element["constructors"] = working_set["constructors"] + if len(working_set["methods"]) > 0: + api_element["methods"] = working_set["methods"] + if len(working_set["events"]) > 0: + api_element["events"] = working_set["events"] + if len(working_set["arguments"]) > 0: + api_element["arguments"] = working_set["arguments"] + + def _validate_info(self, tag, info, line, lineno): + if tag == 'property': + if not 'datatype' in info: + raise ParseError("No type found for @property.", lineno) + elif tag == "param": + if info.get("required", False) and "default" in info: + raise ParseError( + "required parameters should not have defaults: '%s'" + % line, lineno) + elif tag == "prop": + if "datatype" not in info: + raise ParseError("@prop lines must include {type}: '%s'" % + line, lineno) + if "name" not in info: + raise ParseError("@prop lines must provide a name: '%s'" % + line, lineno) + + def _parseTypeLine(self, line, lineno): + # handle these things: + # @method + # @returns description + # @returns {string} description + # @param NAME {type} description + # @param NAME + # @prop NAME {type} description + # @prop NAME + # returns: + # tag: type of api element + # info: linenumber, required, default, name, datatype + # description + + info = {"line_number": lineno} + line = line.rstrip("\n") + pieces = line.split() + + if not pieces: + raise ParseError("line is too short: '%s'" % line, lineno) + if not pieces[0].startswith("@"): + raise ParseError("type line should start with @: '%s'" % line, + lineno) + tag = pieces[0][1:] + skip = 1 + + expect_name = tag in ("param", "prop") + + if len(pieces) == 1: + description = "" + else: + if pieces[1].startswith("{"): + # NAME is missing, pieces[1] is TYPE + pass + else: + if expect_name: + info["required"] = not pieces[1].startswith("[") + name = pieces[1].strip("[ ]") + if "=" in name: + name, info["default"] = name.split("=") + info["name"] = name + skip += 1 + + if len(pieces) > skip and pieces[skip].startswith("{"): + info["datatype"] = pieces[skip].strip("{ }") + skip += 1 + + # we've got the metadata, now extract the description + pieces = line.split(None, skip) + if len(pieces) > skip: + description = pieces[skip] + else: + description = "" + self._validate_info(tag, info, line, lineno) + return tag, info, description + +def parse_hunks(text): + # return a list of tuples. Each is one of: + # ("raw", string) : non-API blocks + # ("api-json", dict) : API blocks + yield ("version", VERSION) + lines = text.splitlines(True) + line_number = 0 + markdown_string = "" + while line_number < len(lines): + line = lines[line_number] + if line.startswith(" 0: + yield ("markdown", markdown_string) + markdown_string = "" + api, line_number = APIParser().parse(lines, line_number) + # this business with 'leftover' is a horrible thing to do, + # and exists only to collect the \n after the closing /api tag. + # It's not needed probably, except to help keep compatibility + # with the previous behaviour + leftover = lines[line_number].lstrip("") + if len(leftover) > 0: + markdown_string += leftover + line_number = line_number + 1 + yield ("api-json", api) + else: + markdown_string += line + line_number = line_number + 1 + if len(markdown_string) > 0: + yield ("markdown", markdown_string) + +class TestRenderer: + # render docs for test purposes + + def getm(self, d, key): + return d.get(key, "") + + def join_lines(self, text): + return " ".join([line.strip() for line in text.split("\n")]) + + def render_prop(self, p): + s = "props[%s]: " % self.getm(p, "name") + pieces = [] + for k in ("type", "description", "required", "default"): + if k in p: + pieces.append("%s=%s" % (k, self.join_lines(str(p[k])))) + return s + ", ".join(pieces) + + def render_param(self, p): + pieces = [] + for k in ("name", "type", "description", "required", "default"): + if k in p: + pieces.append("%s=%s" % (k, self.join_lines(str(p[k])))) + yield ", ".join(pieces) + for prop in p.get("props", []): + yield " " + self.render_prop(prop) + + def render_method(self, method): + yield "name= %s" % self.getm(method, "name") + yield "type= %s" % self.getm(method, "type") + yield "description= %s" % self.getm(method, "description") + signature = method.get("signature") + if signature: + yield "signature= %s" % self.getm(method, "signature") + params = method.get("params", []) + if params: + yield "parameters:" + for p in params: + for pline in self.render_param(p): + yield " " + pline + r = method.get("returns", None) + if r: + yield "returns:" + if "type" in r: + yield " type= %s" % r["type"] + if "description" in r: + yield " description= %s" % self.join_lines(r["description"]) + props = r.get("props", []) + for p in props: + yield " " + self.render_prop(p) + + def format_api(self, api): + for mline in self.render_method(api): + yield mline + constructors = api.get("constructors", []) + if constructors: + yield "constructors:" + for m in constructors: + for mline in self.render_method(m): + yield " " + mline + methods = api.get("methods", []) + if methods: + yield "methods:" + for m in methods: + for mline in self.render_method(m): + yield " " + mline + properties = api.get("properties", []) + if properties: + yield "properties:" + for p in properties: + yield " " + self.render_prop(p) + + def render_docs(self, docs_json, outf=sys.stdout): + + for (t,data) in docs_json: + if t == "api-json": + for line in self.format_api(data): + line = line.rstrip("\n") + outf.write("API: " + line + "\n") + else: + for line in str(data).split("\n"): + outf.write("MD :" + line + "\n") + +def hunks_to_dict(docs_json): + exports = {} + for (t,data) in docs_json: + if t != "api-json": + continue + if data["name"]: + exports[data["name"]] = data + return exports + +if __name__ == "__main__": + json = False + if sys.argv[1] == "--json": + json = True + del sys.argv[1] + docs_text = open(sys.argv[1]).read() + docs_parsed = list(parse_hunks(docs_text)) + if json: + import simplejson + print simplejson.dumps(docs_parsed, indent=2) + else: + TestRenderer().render_docs(docs_parsed) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apirenderer.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apirenderer.py new file mode 100644 index 0000000..36e46ef --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/apirenderer.py @@ -0,0 +1,302 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import sys, os +import markdown +import apiparser + +# list of all the 'class' and 'id' attributes assigned to +#
and tags by the renderer. +API_REFERENCE = 'api_reference' +MODULE_API_DOCS_CLASS = 'module_api_docs' +MODULE_API_DOCS_ID = '_module_api_docs' +API_HEADER = 'api_header' +API_NAME = 'api_name' +API_COMPONENT_GROUP = 'api_component_group' +API_COMPONENT = 'api_component' +DATATYPE = 'datatype' +RETURNS = 'returns' +PARAMETER_SET = 'parameter_set' +MODULE_DESCRIPTION = 'module_description' + +HTML_HEADER = ''' +\n +\n +\n + \n + \n + \n + \n + Add-on SDK Documentation\n + \n +\n + \n +\n +\n +\n''' + +HTML_FOOTER = ''' +\n +\n +\n''' + +def indent(text_in): + text_out = '' + lines = text_in.splitlines(True) + indentation_level = 0 + indentation_depth = 2 + for line in lines: + if (line.startswith('' in line: + indentation_level += 1 + else: + if (line.startswith('
')): + indentation_level -= 1 + text_out += ((' ' * indentation_depth) * indentation_level) + line + return text_out + +def tag_wrap_id(text, classname, id, tag = 'div'): + return ''.join(['\n<'+ tag + ' id="', id, '" class="', \ + classname, '">\n', text + '\n\n']) + +def tag_wrap(text, classname, tag = 'div', inline = False): + if inline: + return ''.join(['\n<' + tag + ' class="', classname, '">', \ + text, '\n']) + else: + return ''.join(['\n<' + tag + ' class="', classname, '">', \ + text, '\n\n']) + +def tag_wrap_inline(text, classname, tag = 'div'): + return ''.join(['\n<' + tag + ' class="', classname, '">', \ + text, '\n']) + +def span_wrap(text, classname): + return ''.join(['', \ + text, '']) + +class API_Renderer(object): + def __init__(self, json, tag): + self.name = json.get('name', None) + self.tag = tag + self.description = json.get('description', '') + self.json = json + + def render_name(self): + raise Exception('not implemented in this class') + + def render_description(self): + return markdown.markdown(self.description) + + def render_subcomponents(self): + raise Exception('not implemented in this class') + + def get_tag(self): + return self.tag + +class Class_Doc(API_Renderer): + def __init__(self, json, tag): + API_Renderer.__init__(self, json, tag) + + def render_name(self): + return self.name + + def render_subcomponents(self): + return render_object_contents(self.json, 'h5', 'h6') + +class Event_Doc(API_Renderer): + def __init__(self, json, tag): + API_Renderer.__init__(self, json, tag) + self.arguments_json = json.get('arguments', None) + + def render_name(self): + return self.name + + def render_subcomponents(self): + if not self.arguments_json: + return '' + text = ''.join([render_comp(Argument_Doc(argument_json, 'div')) \ + for argument_json in self.arguments_json]) + return tag_wrap(text, PARAMETER_SET) + +class Argument_Doc(API_Renderer): + def __init__(self, json, tag): + API_Renderer.__init__(self, json, tag) + self.datatype = json.get('datatype', None) + + def render_name(self): + return span_wrap(self.datatype, DATATYPE) + + def render_subcomponents(self): + return '' + +class Function_Doc(API_Renderer): + def __init__(self, json, tag): + API_Renderer.__init__(self, json, tag) + self.signature = json['signature'] + self.returns = json.get('returns', None) + self.parameters_json = json.get('params', None) + + def render_name(self): + return self.signature + + def render_subcomponents(self): + return self._render_parameters() + self._render_returns() + + def _render_parameters(self): + if not self.parameters_json: + return '' + text = ''.join([render_comp(Parameter_Doc(parameter_json, 'div')) \ + for parameter_json in self.parameters_json]) + return tag_wrap(text, PARAMETER_SET) + + def _render_returns(self): + if not self.returns: + return '' + text = 'Returns: ' + span_wrap(self.returns['datatype'], DATATYPE) + text += markdown.markdown(self.returns['description']) + return tag_wrap(text, RETURNS) + +class Property_Doc(API_Renderer): + def __init__(self, json, tag): + API_Renderer.__init__(self, json, tag) + self.datatype = json.get('datatype', None) + self.required = json.get('required', True) + self.default = json.get('default', False) + + def render_name(self): + rendered = self.name + if self.default: + rendered = rendered + " = " + self.default + if self.datatype: + rendered = rendered + ' : ' + span_wrap(self.datatype, DATATYPE) + if not self.required: + rendered = '[ ' + rendered + ' ]' + return rendered + + def render_subcomponents(self): + return render_object_contents(self.json) + +class Parameter_Doc(Property_Doc): + def __init__(self, json, tag): + Property_Doc.__init__(self, json, tag) + self.properties_json = json.get('props', None) + + def render_subcomponents(self): + if not self.properties_json: + return '' + text = ''.join([render_comp(Property_Doc(property_json, 'div')) \ + for property_json in self.properties_json]) + return text + +def render_object_contents(json, tag = 'div', comp_tag = 'div'): + ctors = json.get('constructors', None) + text = render_comp_group(ctors, 'Constructors', Function_Doc, tag, comp_tag) + methods = json.get('methods', None) + text += render_comp_group(methods, 'Methods', Function_Doc, tag, comp_tag) + properties = json.get('properties', None) + text += render_comp_group(properties, 'Properties', Property_Doc, tag, comp_tag) + events = json.get('events', None) + text += render_comp_group(events, 'Events', Event_Doc, tag, comp_tag) + return text + +def render_comp(component): + # a component is wrapped inside a single div marked 'API_COMPONENT' + # containing: + # 1) the component name, marked 'API_NAME' + text = tag_wrap(component.render_name(), API_NAME, component.get_tag(), True) + # 2) the component description + text += component.render_description() + # 3) the component contents + text += component.render_subcomponents() + return tag_wrap(text, API_COMPONENT) + +def render_comp_group(group, group_name, ctor, tag = 'div', comp_tag = 'div'): + if not group: + return '' + # component group is a list of components in a single div called + # 'API_COMPONENT_GROUP' containing: + # 1) a title for the group marked with 'API_HEADER' + text = tag_wrap(group_name, API_HEADER, tag, True) + # 2) each component + text += ''.join([render_comp(ctor(api, comp_tag)) for api in group]) + return tag_wrap(text, API_COMPONENT_GROUP) + +def render_descriptions(descriptions_md): + text = ''.join([description_md for description_md in descriptions_md]) + return tag_wrap(markdown.markdown(text), MODULE_DESCRIPTION) + +def render_api_reference(api_docs): + if (len(api_docs) == 0): + return '' + # at the top level api reference is in a single div marked 'API_REFERENCE', + # containing: + # 1) a title 'API Reference' marked with 'API_HEADER' + text = tag_wrap('API Reference', API_HEADER, 'h2', True) + # 2) a component group called 'Classes' containing any class elements + classes = [api for api in api_docs if api['type'] == 'class'] + text += render_comp_group(classes, 'Classes', Class_Doc, 'h3', 'h4') + # 3) a component group called 'Functions' containing any global functions + functions = [api for api in api_docs if api['type'] == 'function'] + text += render_comp_group(functions, 'Functions', Function_Doc, 'h3', 'h4') + # 4) a component group called 'Properties' containing any global properties + properties = [api for api in api_docs if api['type'] == 'property'] + text += render_comp_group(properties, 'Properties', Property_Doc, 'h3', 'h4') + # 5) a component group called 'Events' containing any global events + events = [api for api in api_docs if api['type'] == 'event'] + text += render_comp_group(events, 'Events', Event_Doc, 'h3', 'h4') + return tag_wrap(text, API_REFERENCE) + +# take the JSON output of apiparser +# return the HTML DIV containing the rendered component +def json_to_div(json, markdown_filename): + module_name, ext = os.path.splitext(os.path.basename(markdown_filename)) + descriptions = [hunk[1] for hunk in json if hunk[0]=='markdown'] + api_docs = [hunk[1] for hunk in json if hunk[0]=='api-json'] + text = "

" + module_name + "

" + text += render_descriptions(descriptions) + text += render_api_reference(api_docs) + text = tag_wrap_id(text, MODULE_API_DOCS_CLASS, \ + module_name + MODULE_API_DOCS_ID) + return text.encode('utf8') + +# take the JSON output of apiparser +# return standalone HTML containing the rendered component +def json_to_html(json, markdown_filename): + return indent(HTML_HEADER + \ + json_to_div(json, markdown_filename) + HTML_FOOTER) + +# take the name of a Markdown file +# return the HTML DIV containing the rendered component +def md_to_div(markdown_filename): + markdown_contents = open(markdown_filename).read().decode('utf8') + json = list(apiparser.parse_hunks(markdown_contents)) + return json_to_div(json, markdown_filename) + +# take the name of a Markdown file +# return standalone HTML containing the rendered component +def md_to_html(markdown_filename): + return indent(HTML_HEADER + md_to_div(markdown_filename) + HTML_FOOTER) + +if __name__ == '__main__': + if (len(sys.argv) == 0): + print 'Supply the name of a docs file to parse' + else: + print md_to_html(sys.argv[1]) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/generate.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/generate.py new file mode 100644 index 0000000..19ef109 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/generate.py @@ -0,0 +1,292 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import sys +import shutil +import hashlib +import tarfile +import StringIO +import HTMLParser +import urlparse + +from cuddlefish import packaging +from cuddlefish.docs import apiparser +from cuddlefish.docs import apirenderer +from cuddlefish.docs import webdocs +import simplejson as json + +DIGEST = "status.md5" +TGZ_FILENAME = "addon-sdk-docs.tgz" + +def get_sdk_docs_path(env_root): + return os.path.join(env_root, "doc") + +def get_base_url(env_root): + sdk_docs_path = get_sdk_docs_path(env_root).lstrip("/") + return "file://"+"/"+"/".join(sdk_docs_path.split(os.sep))+"/" + +def clean_generated_docs(docs_dir): + status_file = os.path.join(docs_dir, "status.md5") + if os.path.exists(status_file): + os.remove(status_file) + index_file = os.path.join(docs_dir, "index.html") + if os.path.exists(index_file): + os.remove(index_file) + dev_guide_dir = os.path.join(docs_dir, "dev-guide") + if os.path.exists(dev_guide_dir): + shutil.rmtree(dev_guide_dir) + api_doc_dir = os.path.join(docs_dir, "packages") + if os.path.exists(api_doc_dir): + shutil.rmtree(api_doc_dir) + +def generate_static_docs(env_root): + clean_generated_docs(get_sdk_docs_path(env_root)) + generate_docs(env_root, stdout=StringIO.StringIO()) + tgz = tarfile.open(TGZ_FILENAME, 'w:gz') + tgz.add(get_sdk_docs_path(env_root), "doc") + tgz.close() + return TGZ_FILENAME + +def generate_local_docs(env_root): + return generate_docs(env_root, get_base_url(env_root)) + +def generate_named_file(env_root, filename): + web_docs = webdocs.WebDocs(env_root, get_base_url(env_root)) + # next, generate api doc or guide doc + abs_path = os.path.abspath(filename) + if abs_path.startswith(os.path.join(env_root, 'packages')): + doc_html, dest_dir, filename = generate_api_doc(env_root, abs_path, web_docs) + write_file(env_root, doc_html, dest_dir, filename) + elif abs_path.startswith(os.path.join(get_sdk_docs_path(env_root), 'dev-guide-source')): + doc_html, dest_dir, filename = generate_guide_doc(env_root, abs_path, web_docs) + write_file(env_root, doc_html, dest_dir, filename, False) + else: + raise ValueError("Not a valid path to a documentation file") + +def generate_docs(env_root, base_url=None, stdout=sys.stdout): + docs_dir = get_sdk_docs_path(env_root) + # if the generated docs don't exist, generate everything + if not os.path.exists(os.path.join(docs_dir, "dev-guide")): + print >>stdout, "Generating documentation..." + generate_docs_from_scratch(env_root, base_url) + current_status = calculate_current_status(env_root) + open(os.path.join(docs_dir, DIGEST), "w").write(current_status) + else: + current_status = calculate_current_status(env_root) + previous_status_file = os.path.join(docs_dir, DIGEST) + docs_are_up_to_date = False + if os.path.exists(previous_status_file): + docs_are_up_to_date = current_status == open(previous_status_file, "r").read() + # if the docs are not up to date, generate everything + if not docs_are_up_to_date: + print >>stdout, "Regenerating documentation..." + generate_docs_from_scratch(env_root, base_url) + open(os.path.join(docs_dir, DIGEST), "w").write(current_status) + return get_base_url(env_root) + "index.html" + +# this function builds a hash of the name and last modification date of: +# * every file in "packages" which ends in ".md" +# * every file in "static-files" which does not start with "." +def calculate_current_status(env_root): + docs_dir = get_sdk_docs_path(env_root) + current_status = hashlib.md5() + package_src_dir = os.path.join(env_root, "packages") + for (dirpath, dirnames, filenames) in os.walk(package_src_dir): + for filename in filenames: + if filename.endswith(".md"): + current_status.update(filename) + current_status.update(str(os.path.getmtime(os.path.join(dirpath, filename)))) + guide_src_dir = os.path.join(docs_dir, "dev-guide-source") + for (dirpath, dirnames, filenames) in os.walk(guide_src_dir): + for filename in filenames: + if filename.endswith(".md"): + current_status.update(filename) + current_status.update(str(os.path.getmtime(os.path.join(dirpath, filename)))) + base_html_file = os.path.join(docs_dir, "static-files", "base.html") + current_status.update(base_html_file) + current_status.update(str(os.path.getmtime(os.path.join(dirpath, base_html_file)))) + return current_status.digest() + +def generate_docs_from_scratch(env_root, base_url): + docs_dir = get_sdk_docs_path(env_root) + web_docs = webdocs.WebDocs(env_root, base_url) + must_rewrite_links = True + if base_url: + must_rewrite_links = False + clean_generated_docs(docs_dir) + + # py2.5 doesn't have ignore=, so we delete tempfiles afterwards. If we + # required >=py2.6, we could use ignore=shutil.ignore_patterns("*~") + for (dirpath, dirnames, filenames) in os.walk(docs_dir): + for n in filenames: + if n.endswith("~"): + os.unlink(os.path.join(dirpath, n)) + + # generate api docs from all packages + os.mkdir(os.path.join(docs_dir, "packages")) + # create the index file and save that + pkg_cfg = packaging.build_pkg_cfg(env_root) + index = json.dumps(packaging.build_pkg_index(pkg_cfg)) + index_path = os.path.join(docs_dir, "packages", 'index.json') + open(index_path, 'w').write(index) + + # for each package, generate its docs + for pkg_name, pkg in pkg_cfg['packages'].items(): + src_dir = pkg.root_dir + package_dirname = os.path.basename(src_dir) + dest_dir = os.path.join(docs_dir, "packages", package_dirname) + os.mkdir(dest_dir) + + src_readme = os.path.join(src_dir, "README.md") + if os.path.exists(src_readme): + shutil.copyfile(src_readme, + os.path.join(dest_dir, "README.md")) + + # create the package page + package_filename = os.path.join(dest_dir, "index.html") + if not os.path.exists(package_filename): + package_doc_html = web_docs.create_package_page(pkg_name) + replace_file(env_root, package_filename, package_doc_html, must_rewrite_links) + + # generate all the API docs + docs_src_dir = os.path.join(src_dir, "doc") + if os.path.isdir(os.path.join(src_dir, "docs")): + docs_src_dir = os.path.join(src_dir, "docs") + generate_file_tree(env_root, docs_src_dir, web_docs, generate_api_doc, must_rewrite_links) + + # generate all the guide docs + dev_guide_src = os.path.join(docs_dir, "dev-guide-source") + generate_file_tree(env_root, dev_guide_src, web_docs, generate_guide_doc, must_rewrite_links) + + # make /md/dev-guide/welcome.html the top level index file + doc_html, dest_dir, filename = generate_guide_doc(env_root, os.path.join(docs_dir, 'dev-guide-source', 'index.md'), web_docs) + write_file(env_root, doc_html, docs_dir, 'index', False) + +def generate_file_tree(env_root, src_dir, web_docs, generate_file, must_rewrite_links): + for (dirpath, dirnames, filenames) in os.walk(src_dir): + assert dirpath.startswith(src_dir) # what is this for?? + for filename in filenames: + if filename.endswith("~"): + continue + src_path = os.path.join(dirpath, filename) + if src_path.endswith(".md"): + # write the standalone HTML files + doc_html, dest_dir, filename = generate_file(env_root, src_path, web_docs) + write_file(env_root, doc_html, dest_dir, filename, must_rewrite_links) + +def generate_api_doc(env_root, src_dir, web_docs): + doc_html = web_docs.create_module_page(src_dir) + dest_dir, filename = get_api_doc_dest_path(env_root, src_dir) + return doc_html, dest_dir, filename + +def generate_guide_doc(env_root, src_dir, web_docs): + doc_html = web_docs.create_guide_page(src_dir) + dest_dir, filename = get_guide_doc_dest_path(env_root, src_dir) + return doc_html, dest_dir, filename + +def write_file(env_root, doc_html, dest_dir, filename, must_rewrite_links): + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + dest_path_html = os.path.join(dest_dir, filename) + ".html" + replace_file(env_root, dest_path_html, doc_html, must_rewrite_links) + return dest_path_html + +def replace_file(env_root, dest_path, file_contents, must_rewrite_links): + if os.path.exists(dest_path): + os.remove(dest_path) + # before we copy the final version, we'll rewrite the links + # I'll do this last, just because we know definitely what the dest_path is at this point + if must_rewrite_links and dest_path.endswith(".html"): + file_contents = rewrite_links(env_root, file_contents, dest_path) + open(dest_path, "w").write(file_contents) + +def rewrite_links(env_root, page, dest_path): + dest_path_depth = len(dest_path.split(os.sep)) -1 # because dest_path includes filename + docs_root_depth = len(get_sdk_docs_path(env_root).split(os.sep)) + relative_depth = dest_path_depth - docs_root_depth + linkRewriter = LinkRewriter("../" * relative_depth) + return linkRewriter.rewrite_links(page) + +# Given the full path to an API source file, and the root, +# return a tuple of: +# 1) the full path to the corresponding HTML file, without the filename +# 2) the filename without the extension +def get_guide_doc_dest_path(env_root, src_dir): + src_dir_relative = src_dir[len(os.path.join(get_sdk_docs_path(env_root), "dev-guide-source")) + 1:] + return os.path.split(os.path.join(get_sdk_docs_path(env_root), "dev-guide", src_dir_relative)[:-3]) + +# Given the full path to a dev guide source file, and the root, +# return a tuple of: +# 1) the full path to the corresponding HTML file, without the filename +# 2) the filename without the extension +def get_api_doc_dest_path(env_root, src_dir): + src_dir_relative = src_dir[len(env_root) + 1:] + src_dir_relative_pieces = src_dir_relative.split(os.sep) + del src_dir_relative_pieces[2] + src_dir_relative = os.sep.join(src_dir_relative_pieces) + return os.path.split(os.path.join(get_sdk_docs_path(env_root), src_dir_relative)[:-3]) + +class LinkRewriter(HTMLParser.HTMLParser): + def __init__(self, link_prefix): + HTMLParser.HTMLParser.__init__(self) + self.stack = [] + self.link_prefix = link_prefix + + def rewrite_links(self, page): + self.feed(page) + self.close() + page = ''.join(self.stack) + self.stack = [] + return page + + def handle_decl(self, decl): + self.stack.append("") + + def handle_comment(self, decl): + self.stack.append("") + + def handle_starttag(self, tag, attrs): + self.stack.append(self.__html_start_tag(tag, self._rewrite_link(attrs))) + + def handle_entityref(self, name): + self.stack.append("&" + name + ";") + + def handle_endtag(self, tag): + self.stack.append(self.__html_end_tag(tag)) + + def handle_startendtag(self, tag, attrs): + self.stack.append(self.__html_startend_tag(tag, self._rewrite_link(attrs))) + + def _rewrite_link(self, attrs): + attrs = dict(attrs) + href = attrs.get('href', '') + if href: + parsed = urlparse.urlparse(href) + if not parsed.scheme: + attrs['href'] = self.link_prefix + href + src = attrs.get('src', '') + if src: + parsed = urlparse.urlparse(src) + if not parsed.scheme: + attrs['src'] = self.link_prefix + src + return attrs + + def handle_data(self, data): + self.stack.append(data) + + def __html_start_tag(self, tag, attrs): + return '<%s%s>' % (tag, self.__html_attrs(attrs)) + + def __html_startend_tag(self, tag, attrs): + return '<%s%s/>' % (tag, self.__html_attrs(attrs)) + + def __html_end_tag(self, tag): + return '' % (tag) + + def __html_attrs(self, attrs): + _attrs = '' + if attrs: + _attrs = ' %s' % (' '.join([('%s="%s"' % (k,v)) for k,v in dict(attrs).iteritems()])) + return _attrs diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/renderapi.readme.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/renderapi.readme.md new file mode 100644 index 0000000..627c2a6 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/renderapi.readme.md @@ -0,0 +1,210 @@ + + + +This document describes the structure of the HTML generated by the renderapi.py +tool, both for use in the API docs shown by "cfx docs" and as exported by +"cfx sdocs". The particular HTML id and class attributes embedded in the files, +as well as their organization, represent the interface between the tool and any +front-end code wanting to style the docs in some particular way. + +renderapi generates two sorts of files: + +- a file called ".div": this is the contents of the parsed +Markdown file rendered inside a well-defined DIV tag + +- a file called ".html": this is the DIV from above inserted into +a simple HTML template that references a sample CSS file which styles the +contents of the DIV. This CSS file is the same as the one used by the SDK +itself. + +DIV tags +-------- +The following class and id attributes are used in the DIV: + +renderapi uses a number of class attributes and a single id attribute in the DIV: + +id attribute "_module_api_docs" +class attribute "api_reference" +class attribute "module_api_docs" +class attribute "api_header" +class attribute "api_name" +class attribute "api_component_group" +class attribute "api_component" +class attribute "datatype" +class attribute "returns" +class attribute "parameter_set" +class attribute "module_description" + +DIV structure +------------- +The top level DIV is marked with the id attribute and the "module_api_docs" class +attribute: + +
+ //module doc contents +
+ + +Inside this: + +- the first item is an

heading containing the name of the module: + +- all "markdown" hunks (that is, all descriptive text not occurring +inside tags) are rendered inside a DIV marked with the +"module-description" class attribute + +- all content is rendered, enclosed in a single tag marked +with the "api_reference" class attribute: + +
+
+ //descriptions +
+
+ //api reference +
+
+ +If there is no content, then the "api-reference" section is absent. + +### API Reference structure ### + +The first item in API reference is an

heading title marked with the +"api_header" attribute. This might have the text content "API Reference" +(but you should not rely on that): + +
+ +

API Reference

+ + //api contents + +
+ +After the title come one or more component groups. + +#### Component Group #### + +A component group is marked with the "api_component_group" attribute. The +component group is a collection of some sort of component: for example, a group +of classes, a group of functions, or a group of events. + +Each component group starts off with a header marked with the +"api_header" attribute and is followed by one or more sections marked with the +"api_component" attribute. +At the top level (that is, when they are directly under the "API Reference" +heading), the "api_header" items are

headings, otherwise they are divs. + +
+ +

API Reference

+ +
+ +

Classes

+ +
+ // the first class +
+ +
+ // another class +
+ +
+ +
+ //some different components + +

Functions

+ +
+ the first function +
+ +
+ another function +
+ +
+ +
+ +#### Component #### + +API components represent actual objects in the API like classes, functions, +properties and events. + +Each component starts with a section marked with the +"api_name" tag, which includes the name of the component in the API: for +example "postMessage(message)". + +Components at the top level (i.e., directly under h3 headings) are

+headings, otherwise they are divs. + +After the name, the component's contents are listed. Different sorts of +components may have different sorts of contents: for example, a function might +have parameters. If the component is composite then it may contain its own +component group. For example, a class may contain methods and properties, +which might be grouped together. + +
+ +

Panel

+ +
+ +
+ Methods +
+ +
+ show() +
+ +
+ +
+ +Other attributes +----------------------------- + +### Datatype ### +All primitive data types, like "string" and "number", are marked with the +"datatype" class attribute: + +
+ +
+ label : string +
+ +

A required string description of the widget used for accessibility, + title bars, and error reporting.

+ +
+ +### Returns ### + +Functions mark return values with the "returns" class attribute. + +
+ +
+ get() +
+ + Make a `GET` request. + +
+ Returns: Request +
+ +
+ +### Parameter_set ### + +Functions that take parameters mark them with the parameter_set class +attribute. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/webdocs.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/webdocs.py new file mode 100644 index 0000000..dcecc78 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/docs/webdocs.py @@ -0,0 +1,193 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os, re, errno +import markdown +import cgi + +from cuddlefish import packaging +from cuddlefish.docs import apirenderer +from cuddlefish._version import get_versions + +INDEX_PAGE = '/doc/static-files/base.html' +BASE_URL_INSERTION_POINT = '\n' + return result + +def is_third_party(package_json): + return (not is_high_level(package_json)) and \ + (not(is_low_level(package_json))) + +def is_high_level(package_json): + return 'jetpack-high-level' in package_json.get('keywords', []) + +def is_low_level(package_json): + return 'jetpack-low-level' in package_json.get('keywords', []) + +def insert_after(target, insertion_point_id, text_to_insert): + insertion_point = target.find(insertion_point_id) + len(insertion_point_id) + return target[:insertion_point] + text_to_insert + target[insertion_point:] + +class WebDocs(object): + def __init__(self, root, base_url = None): + self.root = root + self.pkg_cfg = packaging.build_pkg_cfg(root) + self.packages_json = packaging.build_pkg_index(self.pkg_cfg) + self.base_page = self._create_base_page(root, base_url) + + def create_guide_page(self, path): + path, ext = os.path.splitext(path) + md_path = path + '.md' + md_content = unicode(open(md_path, 'r').read(), 'utf8') + guide_content = markdown.markdown(md_content) + return self._create_page(guide_content) + + def create_module_page(self, path): + path, ext = os.path.splitext(path) + md_path = path + '.md' + module_content = apirenderer.md_to_div(md_path) + return self._create_page(module_content) + + def create_package_page(self, package_name): + package_content = self._create_package_detail(package_name) + return self._create_page(package_content) + + def _create_page(self, page_content): + page = self._insert_title(self.base_page, page_content) + page = insert_after(page, CONTENT_ID, page_content) + return page.encode('utf8') + + def _create_module_list(self, package_json): + package_name = package_json['name'] + libs = package_json['files'][1]['lib'][1] + doc_path = package_json.get('doc', None) + if not doc_path: + return '' + modules = get_documentation(package_name, libs, doc_path) + modules.sort() + module_items = '' + relative_doc_path = doc_path[len(self.root) + 1:] + relative_doc_path_pieces = relative_doc_path.split(os.sep) + del relative_doc_path_pieces[-1] + relative_doc_URL = "/".join(relative_doc_path_pieces) + for module in modules: + module_link = tag_wrap('/'.join(module), 'a', \ + {'href': relative_doc_URL + '/' + '/'.join(module) + '.html'}) + module_items += module_link + return module_items + + def _create_package_summaries(self, packages_json, include): + packages = '' + for package_name in packages_json.keys(): + package_json = packages_json[package_name] + if not include(package_json): + continue + package_path = self.pkg_cfg["packages"][package_name]["root_dir"] + package_directory = package_path[len(self.root) + 1:] + package_directory = "/".join(package_directory.split(os.sep)) + package_link = tag_wrap(package_name, 'a', {'href': \ + package_directory + "/" \ + + 'index.html'}) + text = tag_wrap(package_link, 'h4') + text += self._create_module_list(package_json) + packages += tag_wrap(text, 'li', {'class':'package-summary', \ + 'style':'display: block;'}) + return packages + + def _create_base_page(self, root, base_url): + base_page = unicode(open(root + INDEX_PAGE, 'r').read(), 'utf8') + if base_url: + base_tag = 'href="' + base_url + '"' + base_page = insert_after(base_page, BASE_URL_INSERTION_POINT, base_tag) + sdk_version = get_versions()["version"] + base_page = insert_after(base_page, VERSION_INSERTION_POINT, "Version " + sdk_version) + third_party_summaries = \ + self._create_package_summaries(self.packages_json, is_third_party) + base_page = insert_after(base_page, \ + THIRD_PARTY_PACKAGE_SUMMARIES, third_party_summaries) + high_level_summaries = \ + self._create_package_summaries(self.packages_json, is_high_level) + base_page = insert_after(base_page, \ + HIGH_LEVEL_PACKAGE_SUMMARIES, high_level_summaries) + low_level_summaries = \ + self._create_package_summaries(self.packages_json, is_low_level) + base_page = insert_after(base_page, \ + LOW_LEVEL_PACKAGE_SUMMARIES, low_level_summaries) + return base_page + + def _create_package_detail_row(self, field_value, \ + field_descriptor, field_name): + meta = tag_wrap(tag_wrap(field_descriptor, 'span', \ + {'class':'meta-header'}), 'td') + value = tag_wrap(tag_wrap(field_value, 'span', \ + {'class':field_name}), 'td') + return tag_wrap(meta + value, 'tr') + + def _create_package_detail_table(self, package_json): + table_contents = '' + if package_json.get('author', None): + table_contents += self._create_package_detail_row(\ + cgi.escape(package_json['author']), 'Author', 'author') + if package_json.get('version', None): + table_contents += self._create_package_detail_row(\ + package_json['version'], 'Version', 'version') + if package_json.get('license', None): + table_contents += self._create_package_detail_row(\ + package_json['license'], 'License', 'license') + if package_json.get('dependencies', None): + table_contents += self._create_package_detail_row(\ + ', '.join(package_json['dependencies']), \ + 'Dependencies', 'dependencies') + table_contents += self._create_package_detail_row(\ + self._create_module_list(package_json), 'Modules', 'modules') + return tag_wrap(tag_wrap(table_contents, 'tbody'), 'table', \ + {'class':'meta-table'}) + + def _create_package_detail(self, package_name): + package_json = self.packages_json.get(package_name, None) + if not package_json: + raise IOError(errno.ENOENT, 'Package not found') + # pieces of the package detail: 1) title, 2) table, 3) description + package_title = tag_wrap(package_name, 'h1') + table = self._create_package_detail_table(package_json) + description = '' + if package_json.get('readme', None): + description += tag_wrap(tag_wrap(\ + markdown.markdown(\ + package_json['readme']), 'p'), 'div', {'class':'docs'}) + return tag_wrap(package_title + table + description, 'div', \ + {'class':'package-detail'}) + + def _insert_title(self, target, content): + match = re.search('

.*

', content) + if match: + title = match.group(0)[len('

'):-len('

')] + ' - ' + \ + DEFAULT_TITLE + else: + title = DEFAULT_TITLE + target = insert_after(target, TITLE_ID, title) + return target diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/manifest.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/manifest.py new file mode 100644 index 0000000..abe37d3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/manifest.py @@ -0,0 +1,751 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import os, sys, re, hashlib +import simplejson as json +SEP = os.path.sep +from cuddlefish.util import filter_filenames, filter_dirnames + +def js_zipname(packagename, modulename): + return "%s-lib/%s.js" % (packagename, modulename) +def docs_zipname(packagename, modulename): + return "%s-docs/%s.md" % (packagename, modulename) +def datamap_zipname(packagename): + return "%s-data.json" % packagename +def datafile_zipname(packagename, datapath): + return "%s-data/%s" % (packagename, datapath) + +def to_json(o): + return json.dumps(o, indent=1).encode("utf-8")+"\n" + +class ModuleNotFoundError(Exception): + def __init__(self, requirement_type, requirement_name, + used_by, line_number, looked_in): + Exception.__init__(self) + self.requirement_type = requirement_type # "require" or "define" + self.requirement_name = requirement_name # string, what they require()d + self.used_by = used_by # string, full path to module which did require() + self.line_number = line_number # int, 1-indexed line number of first require() + self.looked_in = looked_in # list of full paths to potential .js files + def __str__(self): + what = "%s(%s)" % (self.requirement_type, self.requirement_name) + where = self.used_by + if self.line_number is not None: + where = "%s:%d" % (self.used_by, self.line_number) + searched = "Looked for it in:\n %s\n" % "\n ".join(self.looked_in) + return ("ModuleNotFoundError: unable to satisfy: %s from\n" + " %s:\n" % (what, where)) + searched + +class BadModuleIdentifier(Exception): + pass +class BadSection(Exception): + pass +class UnreachablePrefixError(Exception): + pass + +class ManifestEntry: + def __init__(self): + self.docs_filename = None + self.docs_hash = None + self.requirements = {} + self.datamap = None + + def get_path(self): + path = "%s/%s/%s" % \ + (self.packageName, self.sectionName, self.moduleName) + if not path.endswith(".js"): + path += ".js" + return path + + def get_entry_for_manifest(self): + entry = { "packageName": self.packageName, + "sectionName": self.sectionName, + "moduleName": self.moduleName, + "jsSHA256": self.js_hash, + "docsSHA256": self.docs_hash, + "requirements": {}, + } + for req in self.requirements: + if isinstance(self.requirements[req], ManifestEntry): + them = self.requirements[req] # this is another ManifestEntry + them_path = them.get_path() + entry["requirements"][req] = {"path": them_path} + else: + # something magic. The manifest entry indicates that they're + # allowed to require() it + entry["requirements"][req] = self.requirements[req] + assert isinstance(entry["requirements"][req], dict) + if self.datamap: + entry["requirements"]["self"] = { + "path": "self", + "mapSHA256": self.datamap.data_manifest_hash, + "mapName": self.packageName+"-data", + "dataURIPrefix": "%s/data/" % (self.packageName), + } + return entry + + def add_js(self, js_filename): + self.js_filename = js_filename + self.js_hash = hash_file(js_filename) + def add_docs(self, docs_filename): + self.docs_filename = docs_filename + self.docs_hash = hash_file(docs_filename) + def add_requirement(self, reqname, reqdata): + self.requirements[reqname] = reqdata + def add_data(self, datamap): + self.datamap = datamap + + def get_js_zipname(self): + return js_zipname(self.packagename, self.modulename) + def get_docs_zipname(self): + if self.docs_hash: + return docs_zipname(self.packagename, self.modulename) + return None + # self.js_filename + # self.docs_filename + + +def hash_file(fn): + return hashlib.sha256(open(fn,"rb").read()).hexdigest() + +def get_datafiles(datadir): + # yields pathnames relative to DATADIR, ignoring some files + for dirpath, dirnames, filenames in os.walk(datadir): + filenames = list(filter_filenames(filenames)) + # this tells os.walk to prune the search + dirnames[:] = filter_dirnames(dirnames) + for filename in filenames: + fullname = os.path.join(dirpath, filename) + assert fullname.startswith(datadir+SEP), "%s%s not in %s" % (datadir, SEP, fullname) + yield fullname[len(datadir+SEP):] + + +class DataMap: + # one per package + def __init__(self, pkg): + self.pkg = pkg + self.name = pkg.name + self.files_to_copy = [] + datamap = {} + datadir = os.path.join(pkg.root_dir, "data") + for dataname in get_datafiles(datadir): + absname = os.path.join(datadir, dataname) + zipname = datafile_zipname(pkg.name, dataname) + datamap[dataname] = hash_file(absname) + self.files_to_copy.append( (zipname, absname) ) + self.data_manifest = to_json(datamap) + self.data_manifest_hash = hashlib.sha256(self.data_manifest).hexdigest() + self.data_manifest_zipname = datamap_zipname(pkg.name) + self.data_uri_prefix = "%s/data/" % (self.name) + +class BadChromeMarkerError(Exception): + pass + +class ModuleInfo: + def __init__(self, package, section, name, js, docs): + self.package = package + self.section = section + self.name = name + self.js = js + self.docs = docs + + def __hash__(self): + return hash( (self.package.name, self.section, self.name, + self.js, self.docs) ) + def __eq__(self, them): + if them.__class__ is not self.__class__: + return False + if ((them.package.name, them.section, them.name, them.js, them.docs) != + (self.package.name, self.section, self.name, self.js, self.docs) ): + return False + return True + + def __repr__(self): + return "ModuleInfo [%s %s %s] (%s, %s)" % (self.package.name, + self.section, + self.name, + self.js, self.docs) + +class ManifestBuilder: + def __init__(self, target_cfg, pkg_cfg, deps, extra_modules, + stderr=sys.stderr): + self.manifest = {} # maps (package,section,module) to ManifestEntry + self.target_cfg = target_cfg # the entry point + self.pkg_cfg = pkg_cfg # all known packages + self.deps = deps # list of package names to search + self.used_packagenames = set() + self.stderr = stderr + self.extra_modules = extra_modules + self.modules = {} # maps ModuleInfo to URI in self.manifest + self.datamaps = {} # maps package name to DataMap instance + self.files = [] # maps manifest index to (absfn,absfn) js/docs pair + self.test_modules = [] # for runtime + + def build(self, scan_tests, test_filter_re): + # process the top module, which recurses to process everything it + # reaches + if "main" in self.target_cfg: + top_me = self.process_module(self.find_top(self.target_cfg)) + self.top_path = top_me.get_path() + if scan_tests: + mi = self._find_module_in_package("test-harness", "lib", "run-tests", []) + self.process_module(mi) + # also scan all test files in all packages that we use. By making + # a copy of self.used_packagenames first, we refrain from + # processing tests in packages that our own tests depend upon. If + # we're running tests for package A, and either modules in A or + # tests in A depend upon modules from package B, we *don't* want + # to run tests for package B. + test_modules = [] + dirnames = self.target_cfg["tests"] + if isinstance(dirnames, basestring): + dirnames = [dirnames] + dirnames = [os.path.join(self.target_cfg.root_dir, d) + for d in dirnames] + for d in dirnames: + for filename in os.listdir(d): + if filename.startswith("test-") and filename.endswith(".js"): + testname = filename[:-3] # require(testname) + if test_filter_re: + if not re.search(test_filter_re, testname): + continue + tmi = ModuleInfo(self.target_cfg, "tests", testname, + os.path.join(d, filename), None) + # scan the test's dependencies + tme = self.process_module(tmi) + test_modules.append( (testname, tme) ) + # also add it as an artificial dependency of unit-test-finder, so + # the runtime dynamic load can work. + test_finder = self.get_manifest_entry("api-utils", "lib", + "unit-test-finder") + for (testname,tme) in test_modules: + test_finder.add_requirement(testname, tme) + # finally, tell the runtime about it, so they won't have to + # search for all tests. self.test_modules will be passed + # through the harness-options.json file in the + # .allTestModules property. + self.test_modules.append(testname) + + # include files used by the loader + for em in self.extra_modules: + (pkgname, section, modname, js) = em + mi = ModuleInfo(self.pkg_cfg.packages[pkgname], section, modname, + js, None) + self.process_module(mi) + + + def get_module_entries(self): + return frozenset(self.manifest.values()) + def get_data_entries(self): + return frozenset(self.datamaps.values()) + + def get_used_packages(self): + used = set() + for index in self.manifest: + (package, section, module) = index + used.add(package) + return sorted(used) + + def get_used_files(self): + # returns all .js files that we reference, plus data/ files. You will + # need to add the loader, off-manifest files that it needs, and + # generated metadata. + for me in self.get_module_entries(): + yield me.js_filename + if me.datamap: + for (zipname, absname) in me.datamap.files_to_copy: + yield absname + + def get_all_test_modules(self): + return self.test_modules + + def get_harness_options_manifest(self): + manifest = {} + for me in self.get_module_entries(): + path = me.get_path() + manifest[path] = me.get_entry_for_manifest() + return manifest + + def get_manifest_entry(self, package, section, module): + index = (package, section, module) + if index not in self.manifest: + m = self.manifest[index] = ManifestEntry() + m.packageName = package + m.sectionName = section + m.moduleName = module + self.used_packagenames.add(package) + return self.manifest[index] + + def uri_name_from_path(self, pkg, fn): + # given a filename like .../pkg1/lib/bar/foo.js, and a package + # specification (with a .root_dir like ".../pkg1" and a .lib list of + # paths where .lib[0] is like "lib"), return the appropriate NAME + # that can be put into a URI like resource://JID-pkg1-lib/NAME . This + # will throw an exception if the file is outside of the lib/ + # directory, since that means we can't construct a URI that points to + # it. + # + # This should be a lot easier, and shouldn't fail when the file is in + # the root of the package. Both should become possible when the XPI + # is rearranged and our URI scheme is simplified. + fn = os.path.abspath(fn) + pkglib = pkg.lib[0] + libdir = os.path.abspath(os.path.join(pkg.root_dir, pkglib)) + # AARGH, section and name! we need to reverse-engineer a + # ModuleInfo instance that will produce a URI (in the form + # PREFIX/PKGNAME-SECTION/JS) that will map to the existing file. + # Until we fix URI generation to get rid of "sections", this is + # limited to files in the same .directories.lib as the rest of + # the package uses. So if the package's main files are in lib/, + # but the main.js is in the package root, there is no URI we can + # construct that will point to it, and we must fail. + # + # This will become much easier (and the failure case removed) + # when we get rid of sections and change the URIs to look like + # (PREFIX/PKGNAME/PATH-TO-JS). + + # AARGH 2, allowing .lib to be a list is really getting in the + # way. That needs to go away eventually too. + if not fn.startswith(libdir): + raise UnreachablePrefixError("Sorry, but the 'main' file (%s) in package %s is outside that package's 'lib' directory (%s), so I cannot construct a URI to reach it." + % (fn, pkg.name, pkglib)) + name = fn[len(libdir):].lstrip(SEP)[:-len(".js")] + return name + + + def parse_main(self, root_dir, main, check_lib_dir=None): + # 'main' can be like one of the following: + # a: ./lib/main.js b: ./lib/main c: lib/main + # we require it to be a path to the file, though, and ignore the + # .directories stuff. So just "main" is insufficient if you really + # want something in a "lib/" subdirectory. + if main.endswith(".js"): + main = main[:-len(".js")] + if main.startswith("./"): + main = main[len("./"):] + # package.json must always use "/", but on windows we'll replace that + # with "\" before using it as an actual filename + main = os.sep.join(main.split("/")) + paths = [os.path.join(root_dir, main+".js")] + if check_lib_dir is not None: + paths.append(os.path.join(root_dir, check_lib_dir, main+".js")) + return paths + + def find_top_js(self, target_cfg): + for libdir in target_cfg.lib: + for n in self.parse_main(target_cfg.root_dir, target_cfg.main, + libdir): + if os.path.exists(n): + return n + raise KeyError("unable to find main module '%s.js' in top-level package" % target_cfg.main) + + def find_top(self, target_cfg): + top_js = self.find_top_js(target_cfg) + n = os.path.join(target_cfg.root_dir, "README.md") + if os.path.exists(n): + top_docs = n + else: + top_docs = None + name = self.uri_name_from_path(target_cfg, top_js) + return ModuleInfo(target_cfg, "lib", name, top_js, top_docs) + + def process_module(self, mi): + pkg = mi.package + #print "ENTERING", pkg.name, mi.name + # mi.name must be fully-qualified + assert (not mi.name.startswith("./") and + not mi.name.startswith("../")) + # create and claim the manifest row first + me = self.get_manifest_entry(pkg.name, mi.section, mi.name) + + me.add_js(mi.js) + if mi.docs: + me.add_docs(mi.docs) + + js_lines = open(mi.js,"r").readlines() + requires, problems, locations = scan_module(mi.js,js_lines,self.stderr) + if problems: + # the relevant instructions have already been written to stderr + raise BadChromeMarkerError() + + # We update our requirements on the way out of the depth-first + # traversal of the module graph + + for reqname in sorted(requires.keys()): + if reqname in ("chrome", "@packaging", "@loader"): + me.add_requirement(reqname, {"path": reqname}) + elif reqname == "self": + # this might reference bundled data, so: + # 1: hash that data, add the hash as a dependency + # 2: arrange for the data to be copied into the XPI later + if pkg.name not in self.datamaps: + self.datamaps[pkg.name] = DataMap(pkg) + dm = self.datamaps[pkg.name] + me.add_data(dm) # 'self' is implicit + else: + # when two modules require() the same name, do they get a + # shared instance? This is a deep question. For now say yes. + + # find_req_for() returns an entry to put in our + # 'requirements' dict, and will recursively process + # everything transitively required from here. It will also + # populate the self.modules[] cache. Note that we must + # tolerate cycles in the reference graph. + looked_in = [] # populated by subroutines + them_me = self.find_req_for(mi, reqname, looked_in) + if them_me is None: + if mi.section == "tests": + # tolerate missing modules in tests, because + # test-securable-module.js, and the modules/red.js + # that it imports, both do that intentionally + continue + lineno = locations.get(reqname) # None means define() + if lineno is None: + reqtype = "define" + else: + reqtype = "require" + err = ModuleNotFoundError(reqtype, reqname, + mi.js, lineno, looked_in) + raise err + else: + me.add_requirement(reqname, them_me) + + return me + #print "LEAVING", pkg.name, mi.name + + def find_req_for(self, from_module, reqname, looked_in): + # handle a single require(reqname) statement from from_module . + # Return a uri that exists in self.manifest + # Populate looked_in with places we looked. + def BAD(msg): + return BadModuleIdentifier(msg + " in require(%s) from %s" % + (reqname, from_module)) + + if not reqname: + raise BAD("no actual modulename") + + # Allow things in tests/*.js to require both test code and real code. + # But things in lib/*.js can only require real code. + if from_module.section == "tests": + lookfor_sections = ["tests", "lib"] + elif from_module.section == "lib": + lookfor_sections = ["lib"] + else: + raise BadSection(from_module.section) + modulename = from_module.name + + #print " %s require(%s))" % (from_module, reqname) + bits = reqname.split("/") + + if reqname.startswith("./") or reqname.startswith("../"): + # 1: they want something relative to themselves, always from + # their own package + them = modulename.split("/")[:-1] + while bits[0] in (".", ".."): + if not bits: + raise BAD("no actual modulename") + if bits[0] == "..": + if not them: + raise BAD("too many ..") + them.pop() + bits.pop(0) + bits = them+bits + lookfor_pkg = from_module.package.name + lookfor_mod = "/".join(bits) + return self._get_module_from_package(lookfor_pkg, + lookfor_sections, lookfor_mod, + looked_in) + + # non-relative import. Might be a short name (requiring a search + # through "library" packages), or a fully-qualified one. + + if "/" in reqname: + # 2: PKG/MOD: find PKG, look inside for MOD + lookfor_pkg = bits[0] + lookfor_mod = "/".join(bits[1:]) + mi = self._get_module_from_package(lookfor_pkg, + lookfor_sections, lookfor_mod, + looked_in) + if mi: # caution, 0==None + return mi + else: + # 3: try finding PKG, if found, use its main.js entry point + lookfor_pkg = reqname + mi = self._get_entrypoint_from_package(lookfor_pkg, looked_in) + if mi: + return mi + + # 4: search packages for MOD or MODPARENT/MODCHILD. We always search + # their own package first, then the list of packages defined by their + # .dependencies list + from_pkg = from_module.package.name + return self._search_packages_for_module(from_pkg, + lookfor_sections, reqname, + looked_in) + + def _handle_module(self, mi): + if not mi: + return None + + # we tolerate cycles in the reference graph, which means we need to + # populate the self.modules cache before recursing into + # process_module() . We must also check the cache first, so recursion + # can terminate. + if mi in self.modules: + return self.modules[mi] + + # this creates the entry + new_entry = self.get_manifest_entry(mi.package.name, mi.section, mi.name) + # and populates the cache + self.modules[mi] = new_entry + self.process_module(mi) + return new_entry + + def _get_module_from_package(self, pkgname, sections, modname, looked_in): + if pkgname not in self.pkg_cfg.packages: + return None + mi = self._find_module_in_package(pkgname, sections, modname, + looked_in) + return self._handle_module(mi) + + def _get_entrypoint_from_package(self, pkgname, looked_in): + if pkgname not in self.pkg_cfg.packages: + return None + pkg = self.pkg_cfg.packages[pkgname] + main = pkg.get("main", None) + if not main: + return None + for js in self.parse_main(pkg.root_dir, main): + looked_in.append(js) + if os.path.exists(js): + section = "lib" + name = self.uri_name_from_path(pkg, js) + docs = None + mi = ModuleInfo(pkg, section, name, js, docs) + return self._handle_module(mi) + return None + + def _search_packages_for_module(self, from_pkg, sections, reqname, + looked_in): + searchpath = [] # list of package names + searchpath.append(from_pkg) # search self first + us = self.pkg_cfg.packages[from_pkg] + if 'dependencies' in us: + # only look in dependencies + searchpath.extend(us['dependencies']) + else: + # they didn't declare any dependencies (or they declared an empty + # list, but we'll treat that as not declaring one, because it's + # easier), so look in all deps, sorted alphabetically, so + # addon-kit comes first. Note that self.deps includes all + # packages found by traversing the ".dependencies" lists in each + # package.json, starting from the main addon package, plus + # everything added by --extra-packages + searchpath.extend(sorted(self.deps)) + for pkgname in searchpath: + mi = self._find_module_in_package(pkgname, sections, reqname, + looked_in) + if mi: + return self._handle_module(mi) + return None + + def _find_module_in_package(self, pkgname, sections, name, looked_in): + # require("a/b/c") should look at ...\a\b\c.js on windows + filename = os.sep.join(name.split("/")) + # normalize filename, make sure that we do not add .js if it already has + # it. + if not filename.endswith(".js"): + filename += ".js" + basename = filename[:-3] + + pkg = self.pkg_cfg.packages[pkgname] + if isinstance(sections, basestring): + sections = [sections] + for section in sections: + for sdir in pkg.get(section, []): + js = os.path.join(pkg.root_dir, sdir, filename) + looked_in.append(js) + if os.path.exists(js): + docs = None + maybe_docs = os.path.join(pkg.root_dir, "docs", + basename+".md") + if section == "lib" and os.path.exists(maybe_docs): + docs = maybe_docs + return ModuleInfo(pkg, section, name, js, docs) + return None + +def build_manifest(target_cfg, pkg_cfg, deps, scan_tests, + test_filter_re=None, extra_modules=[]): + """ + Perform recursive dependency analysis starting from entry_point, + building up a manifest of modules that need to be included in the XPI. + Each entry will map require() names to the URL of the module that will + be used to satisfy that dependency. The manifest will be used by the + runtime's require() code. + + This returns a ManifestBuilder object, with two public methods. The + first, get_module_entries(), returns a set of ManifestEntry objects, each + of which can be asked for the following: + + * its contribution to the harness-options.json '.manifest' + * the local disk name + * the name in the XPI at which it should be placed + + The second is get_data_entries(), which returns a set of DataEntry + objects, each of which has: + + * local disk name + * name in the XPI + + note: we don't build the XPI here, but our manifest is passed to the + code which does, so it knows what to copy into the XPI. + """ + + mxt = ManifestBuilder(target_cfg, pkg_cfg, deps, extra_modules) + mxt.build(scan_tests, test_filter_re) + return mxt + + + +COMMENT_PREFIXES = ["//", "/*", "*", "dump("] + +REQUIRE_RE = r"(?>stderr, """ +The following lines from file %(fn)s: +%(lines)s +use 'Components' to access chrome authority. To do so, you need to add a +line somewhat like the following: + + const {%(needs)s} = require("chrome"); + +Then you can use 'Components' as well as any shortcuts to its properties +that you import from the 'chrome' module ('Cc', 'Ci', 'Cm', 'Cr', and +'Cu' for the 'classes', 'interfaces', 'manager', 'results', and 'utils' +properties, respectively). + +(Note: once bug 636145 is fixed, to access 'Components' directly you'll +need to retrieve it from the 'chrome' module by adding it to the list of +symbols you import from the module. To avoid having to make this change +in the future, replace all occurrences of 'Components' in your code with +the equivalent shortcuts now.) +""" % { "fn": fn, "needs": ",".join(sorted(old_chrome)), + "lines": "\n".join([" %3d: %s" % (lineno,line) + for (lineno, line) in old_chrome_lines]), + } + problems = True + return problems + +def scan_module(fn, lines, stderr=sys.stderr): + filename = os.path.basename(fn) + requires, locations = scan_requirements_with_grep(fn, lines) + if filename == "cuddlefish.js": + # this is the loader: don't scan for chrome + problems = False + elif "chrome" in requires: + # if they declare require("chrome"), we tolerate the use of + # Components (see bug 663541 for rationale) + problems = False + else: + problems = scan_for_bad_chrome(fn, lines, stderr) + return requires, problems, locations + + + +if __name__ == '__main__': + for fn in sys.argv[1:]: + requires, problems, locations = scan_module(fn, open(fn).readlines()) + print + print "---", fn + if problems: + print "PROBLEMS" + sys.exit(1) + print "requires: %s" % (",".join(sorted(requires.keys()))) + print "locations: %s" % locations + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/bootstrap.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/bootstrap.js new file mode 100644 index 0000000..7bf6d84 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/bootstrap.js @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Components.utils.import("resource://gre/modules/Services.jsm"); + +const DEBUG = false; + +let log = DEBUG ? dump : function (){}; + + +function startup(data, reason) { + // This code allow to make all stdIO work + try { + Components.utils.import("resource://gre/modules/ctypes.jsm"); + let libdvm = ctypes.open("libdvm.so"); + let dvmStdioConverterStartup = libdvm.declare("dvmStdioConverterStartup", ctypes.default_abi, ctypes.void_t); + dvmStdioConverterStartup(); + log("MU: console redirected to adb logcat.\n"); + } catch(e) { + Cu.reportError("MU: unable to execute jsctype hack: "+e); + } + + // This code allow to kill firefox from adb + try { + let Watcher = { + window: null, + onOpenWindow: function(window) { + window = window.docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow); + window.addEventListener("keydown", this, true); + }, + onCloseWindow: function (window) {}, + onWindowTitleChange: function () {}, + handleEvent: function(event) { + // This event is dispatched via: abd shell input keycode 19 + // KEYCODE_DPAD_UP = 19, UP can't be fired by virtual keyboard, + // so it should be safe to take this event as a kill signal. + // `adb shell input` and `JS keyCode` values doesn't map to same values + // In JS, KeyUp maps to DOM_VK_UP = 38: + // https://developer.mozilla.org/en/DOM/KeyboardEvent + if (event.keyCode == 38 && event.which == 38) { + Cu.reportError("Mobile killer triggered!"); + let appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. + getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eForceQuit); + } + } + }; + Services.wm.addListener(Watcher); + log("MU: key listener to close firefox set.\n"); + } + catch(e) { + log("MU: Unable to register window watcher: " + e + "\n"); + } + + try { + let QuitObserver = { + observe: function (aSubject, aTopic, aData) { + Services.obs.removeObserver(QuitObserver, "quit-application", false); + dump("MU: APPLICATION-QUIT\n"); + } + }; + Services.obs.addObserver(QuitObserver, "quit-application", false); + log("MU: ready to watch firefox exit.\n"); + } catch(e) { + log("MU: unable to register quit-application observer: " + e + "\n"); + } +} + +function install() {} +function shutdown() {} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/install.rdf b/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/install.rdf new file mode 100644 index 0000000..0b81a0e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/mobile-utils/install.rdf @@ -0,0 +1,39 @@ + + + + + + + mobile-utils@mozilla.com + 1.0 + 2 + true + + + + + {a23983c0-fd0e-11dc-95ff-0800200c9a66} + 1 + * + + + + + + + {aa3c5121-dab2-40e2-81ca-7ea25febc110} + 1 + * + + + + + Mobile Addon-SDK utility addon + Allow better integration with cfx tool. + Mozilla Corporation + + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/options_defaults.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/options_defaults.py new file mode 100644 index 0000000..5931a26 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/options_defaults.py @@ -0,0 +1,26 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +def parse_options_defaults(options, jetpack_id): + # this returns a unicode string + pref_list = [] + + for pref in options: + if ('value' in pref): + value = pref["value"] + + if isinstance(value, float): + continue + elif isinstance(value, bool): + value = str(pref["value"]).lower() + elif isinstance(value, str): # presumably ASCII + value = "\"" + unicode(pref["value"]) + "\"" + elif isinstance(value, unicode): + value = "\"" + pref["value"] + "\"" + else: + value = str(pref["value"]) + + pref_list.append("pref(\"extensions." + jetpack_id + "." + pref["name"] + "\", " + value + ");") + + return "\n".join(pref_list) + "\n" diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/options_xul.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/options_xul.py new file mode 100644 index 0000000..6f11311 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/options_xul.py @@ -0,0 +1,64 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from xml.dom.minidom import Document + +VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color', 'file', + 'directory', 'control'] + +class Error(Exception): + pass + +class BadPrefTypeError(Error): + pass + +class MissingPrefAttr(Error): + pass + +def validate_prefs(options): + for pref in options: + # Make sure there is a 'title' + if ("title" not in pref): + raise MissingPrefAttr("The '%s' pref requires a 'title'" % (pref["name"])) + + # Make sure that the pref type is a valid inline pref type + if (pref["type"] not in VALID_PREF_TYPES): + raise BadPrefTypeError('%s is not a valid inline pref type' % (pref["type"])) + + # Make sure the 'control' type has a 'label' + if (pref["type"] == "control"): + if ("label" not in pref): + raise MissingPrefAttr("The 'control' inline pref type requires a 'label'") + + # TODO: Check that pref["type"] matches default value type + +def parse_options(options, jetpack_id): + doc = Document() + root = doc.createElement("vbox") + root.setAttribute("xmlns", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") + doc.appendChild(root) + + for pref in options: + setting = doc.createElement("setting") + setting.setAttribute("pref", "extensions." + jetpack_id + "." + pref["name"]) + setting.setAttribute("type", pref["type"]) + setting.setAttribute("title", pref["title"]) + + if ("description" in pref): + setting.appendChild(doc.createTextNode(pref["description"])) + + if (pref["type"] == "control"): + button = doc.createElement("button") + button.setAttribute("label", pref["label"]) + button.setAttribute("oncommand", "Services.obs.notifyObservers(null, '" + + jetpack_id + "-cmdPressed', '" + + pref["name"] + "');"); + setting.appendChild(button) + elif (pref["type"] == "boolint"): + setting.setAttribute("on", pref["on"]) + setting.setAttribute("off", pref["off"]) + + root.appendChild(setting) + + return doc.toprettyxml(indent=" ") diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/packaging.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/packaging.py new file mode 100644 index 0000000..757d5ac --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/packaging.py @@ -0,0 +1,435 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import sys +import re +import copy + +import simplejson as json +from cuddlefish.bunch import Bunch + +MANIFEST_NAME = 'package.json' + +DEFAULT_LOADER = 'api-utils' + +DEFAULT_PROGRAM_MODULE = 'main' + +DEFAULT_ICON = 'icon.png' +DEFAULT_ICON64 = 'icon64.png' + +METADATA_PROPS = ['name', 'description', 'keywords', 'author', 'version', + 'contributors', 'license', 'homepage', 'icon', 'icon64', + 'main', 'directories'] + +RESOURCE_HOSTNAME_RE = re.compile(r'^[a-z0-9_\-]+$') + +class Error(Exception): + pass + +class MalformedPackageError(Error): + pass + +class MalformedJsonFileError(Error): + pass + +class DuplicatePackageError(Error): + pass + +class PackageNotFoundError(Error): + def __init__(self, missing_package, reason): + self.missing_package = missing_package + self.reason = reason + def __str__(self): + return "%s (%s)" % (self.missing_package, self.reason) + +class BadChromeMarkerError(Error): + pass + +def validate_resource_hostname(name): + """ + Validates the given hostname for a resource: URI. + + For more information, see: + + https://bugzilla.mozilla.org/show_bug.cgi?id=566812#c13 + + Examples: + + >>> validate_resource_hostname('blarg') + + >>> validate_resource_hostname('bl arg') + Traceback (most recent call last): + ... + ValueError: Error: the name of your package contains an invalid character. + Package names can contain only lower-case letters, numbers, underscores, and dashes. + Current package name: bl arg + + >>> validate_resource_hostname('BLARG') + Traceback (most recent call last): + ... + ValueError: Error: the name of your package contains upper-case letters. + Package names can contain only lower-case letters, numbers, underscores, and dashes. + Current package name: BLARG + + >>> validate_resource_hostname('foo@bar') + Traceback (most recent call last): + ... + ValueError: Error: the name of your package contains an invalid character. + Package names can contain only lower-case letters, numbers, underscores, and dashes. + Current package name: foo@bar + """ + + # See https://bugzilla.mozilla.org/show_bug.cgi?id=568131 for details. + if not name.islower(): + raise ValueError("""Error: the name of your package contains upper-case letters. +Package names can contain only lower-case letters, numbers, underscores, and dashes. +Current package name: %s""" % name) + + if not RESOURCE_HOSTNAME_RE.match(name): + raise ValueError("""Error: the name of your package contains an invalid character. +Package names can contain only lower-case letters, numbers, underscores, and dashes. +Current package name: %s""" % name) + +def find_packages_with_module(pkg_cfg, name): + # TODO: Make this support more than just top-level modules. + filename = "%s.js" % name + packages = [] + for cfg in pkg_cfg.packages.itervalues(): + if 'lib' in cfg: + matches = [dirname for dirname in resolve_dirs(cfg, cfg.lib) + if os.path.exists(os.path.join(dirname, filename))] + if matches: + packages.append(cfg.name) + return packages + +def resolve_dirs(pkg_cfg, dirnames): + for dirname in dirnames: + yield resolve_dir(pkg_cfg, dirname) + +def resolve_dir(pkg_cfg, dirname): + return os.path.join(pkg_cfg.root_dir, dirname) + +def get_metadata(pkg_cfg, deps): + metadata = Bunch() + for pkg_name in deps: + cfg = pkg_cfg.packages[pkg_name] + metadata[pkg_name] = Bunch() + for prop in METADATA_PROPS: + if cfg.get(prop): + metadata[pkg_name][prop] = cfg[prop] + return metadata + +def set_section_dir(base_json, name, base_path, dirnames, allow_root=False): + resolved = compute_section_dir(base_json, base_path, dirnames, allow_root) + if resolved: + base_json[name] = os.path.abspath(resolved) + +def compute_section_dir(base_json, base_path, dirnames, allow_root): + # PACKAGE_JSON.lib is highest priority + # then PACKAGE_JSON.directories.lib + # then lib/ (if it exists) + # then . (but only if allow_root=True) + for dirname in dirnames: + if base_json.get(dirname): + return os.path.join(base_path, base_json[dirname]) + if "directories" in base_json: + for dirname in dirnames: + if dirname in base_json.directories: + return os.path.join(base_path, base_json.directories[dirname]) + for dirname in dirnames: + if os.path.isdir(os.path.join(base_path, dirname)): + return os.path.join(base_path, dirname) + if allow_root: + return os.path.abspath(base_path) + return None + +def normalize_string_or_array(base_json, key): + if base_json.get(key): + if isinstance(base_json[key], basestring): + base_json[key] = [base_json[key]] + +def load_json_file(path): + data = open(path, 'r').read() + try: + return Bunch(json.loads(data)) + except ValueError, e: + raise MalformedJsonFileError('%s when reading "%s"' % (str(e), + path)) + +def get_config_in_dir(path): + package_json = os.path.join(path, MANIFEST_NAME) + if not (os.path.exists(package_json) and + os.path.isfile(package_json)): + raise MalformedPackageError('%s not found in "%s"' % (MANIFEST_NAME, + path)) + base_json = load_json_file(package_json) + + if 'name' not in base_json: + base_json.name = os.path.basename(path) + + # later processing steps will expect to see the following keys in the + # base_json that we return: + # + # name: name of the package + # lib: list of directories with .js files + # test: list of directories with test-*.js files + # doc: list of directories with documentation .md files + # data: list of directories with bundled arbitrary data files + # packages: ? + + if (not base_json.get('tests') and + os.path.isdir(os.path.join(path, 'test'))): + base_json['tests'] = 'test' + + set_section_dir(base_json, 'lib', path, ['lib'], True) + set_section_dir(base_json, 'tests', path, ['test', 'tests'], False) + set_section_dir(base_json, 'doc', path, ['doc', 'docs']) + set_section_dir(base_json, 'data', path, ['data']) + set_section_dir(base_json, 'packages', path, ['packages']) + set_section_dir(base_json, 'locale', path, ['locale']) + + if (not base_json.get('icon') and + os.path.isfile(os.path.join(path, DEFAULT_ICON))): + base_json['icon'] = DEFAULT_ICON + + if (not base_json.get('icon64') and + os.path.isfile(os.path.join(path, DEFAULT_ICON64))): + base_json['icon64'] = DEFAULT_ICON64 + + for key in ['lib', 'tests', 'dependencies', 'packages']: + # TODO: lib/tests can be an array?? consider interaction with + # compute_section_dir above + normalize_string_or_array(base_json, key) + + if 'main' not in base_json and 'lib' in base_json: + for dirname in base_json['lib']: + program = os.path.join(path, dirname, + '%s.js' % DEFAULT_PROGRAM_MODULE) + if os.path.exists(program): + base_json['main'] = DEFAULT_PROGRAM_MODULE + break + + base_json.root_dir = path + + return base_json + +def _is_same_file(a, b): + if hasattr(os.path, 'samefile'): + return os.path.samefile(a, b) + return a == b + +def build_config(root_dir, target_cfg, packagepath=[]): + dirs_to_scan = [] + + def add_packages_from_config(pkgconfig): + if 'packages' in pkgconfig: + for package_dir in resolve_dirs(pkgconfig, pkgconfig.packages): + dirs_to_scan.append(package_dir) + + add_packages_from_config(target_cfg) + + packages_dir = os.path.join(root_dir, 'packages') + if os.path.exists(packages_dir) and os.path.isdir(packages_dir): + dirs_to_scan.append(packages_dir) + dirs_to_scan.extend(packagepath) + + packages = Bunch({target_cfg.name: target_cfg}) + + while dirs_to_scan: + packages_dir = dirs_to_scan.pop() + if os.path.exists(os.path.join(packages_dir, "package.json")): + package_paths = [packages_dir] + else: + package_paths = [os.path.join(packages_dir, dirname) + for dirname in os.listdir(packages_dir) + if not dirname.startswith('.')] + package_paths = [dirname for dirname in package_paths + if os.path.isdir(dirname)] + + for path in package_paths: + pkgconfig = get_config_in_dir(path) + if pkgconfig.name in packages: + otherpkg = packages[pkgconfig.name] + if not _is_same_file(otherpkg.root_dir, path): + raise DuplicatePackageError(path, otherpkg.root_dir) + else: + packages[pkgconfig.name] = pkgconfig + add_packages_from_config(pkgconfig) + + return Bunch(packages=packages) + +def get_deps_for_targets(pkg_cfg, targets): + visited = [] + deps_left = [[dep, None] for dep in list(targets)] + + while deps_left: + [dep, required_by] = deps_left.pop() + if dep not in visited: + visited.append(dep) + if dep not in pkg_cfg.packages: + required_reason = ("required by '%s'" % (required_by)) \ + if required_by is not None \ + else "specified as target" + raise PackageNotFoundError(dep, required_reason) + dep_cfg = pkg_cfg.packages[dep] + deps_left.extend([[i, dep] for i in dep_cfg.get('dependencies', [])]) + deps_left.extend([[i, dep] for i in dep_cfg.get('extra_dependencies', [])]) + + return visited + +def generate_build_for_target(pkg_cfg, target, deps, + include_tests=True, + include_dep_tests=False, + default_loader=DEFAULT_LOADER): + + build = Bunch(# Contains section directories for all packages: + packages=Bunch(), + locale=Bunch() + ) + + def add_section_to_build(cfg, section, is_code=False, + is_data=False): + if section in cfg: + dirnames = cfg[section] + if isinstance(dirnames, basestring): + # This is just for internal consistency within this + # function, it has nothing to do w/ a non-canonical + # configuration dict. + dirnames = [dirnames] + for dirname in resolve_dirs(cfg, dirnames): + # ensure that package name is valid + try: + validate_resource_hostname(cfg.name) + except ValueError, err: + print err + sys.exit(1) + # ensure that this package has an entry + if not cfg.name in build.packages: + build.packages[cfg.name] = Bunch() + # detect duplicated sections + if section in build.packages[cfg.name]: + raise KeyError("package's section already defined", + cfg.name, section) + # Register this section (lib, data, tests) + build.packages[cfg.name][section] = dirname + + def add_locale_to_build(cfg): + path = resolve_dir(cfg, cfg['locale']) + files = os.listdir(path) + for filename in files: + fullpath = os.path.join(path, filename) + if os.path.isfile(fullpath) and filename.endswith('.properties'): + language = filename[:-len('.properties')] + + from property_parser import parse_file, MalformedLocaleFileError + try: + content = parse_file(fullpath) + except MalformedLocaleFileError, msg: + print msg[0] + sys.exit(1) + + # Merge current locales into global locale hashtable. + # Locale files only contains one big JSON object + # that act as an hastable of: + # "keys to translate" => "translated keys" + if language in build.locale: + merge = (build.locale[language].items() + + content.items()) + build.locale[language] = Bunch(merge) + else: + build.locale[language] = content + + def add_dep_to_build(dep): + dep_cfg = pkg_cfg.packages[dep] + add_section_to_build(dep_cfg, "lib", is_code=True) + add_section_to_build(dep_cfg, "data", is_data=True) + if include_tests and include_dep_tests: + add_section_to_build(dep_cfg, "tests", is_code=True) + if 'locale' in dep_cfg: + add_locale_to_build(dep_cfg) + if ("loader" in dep_cfg) and ("loader" not in build): + build.loader = "%s/%s" % (dep, + dep_cfg.loader) + + target_cfg = pkg_cfg.packages[target] + + if include_tests and not include_dep_tests: + add_section_to_build(target_cfg, "tests", is_code=True) + + for dep in deps: + add_dep_to_build(dep) + + if 'loader' not in build: + add_dep_to_build(DEFAULT_LOADER) + + if 'icon' in target_cfg: + build['icon'] = os.path.join(target_cfg.root_dir, target_cfg.icon) + del target_cfg['icon'] + + if 'icon64' in target_cfg: + build['icon64'] = os.path.join(target_cfg.root_dir, target_cfg.icon64) + del target_cfg['icon64'] + + if ('preferences' in target_cfg): + build['preferences'] = target_cfg.preferences + + return build + +def _get_files_in_dir(path): + data = {} + files = os.listdir(path) + for filename in files: + fullpath = os.path.join(path, filename) + if os.path.isdir(fullpath): + data[filename] = _get_files_in_dir(fullpath) + else: + try: + info = os.stat(fullpath) + data[filename] = ("file", dict(size=info.st_size)) + except OSError: + pass + return ("directory", data) + +def build_pkg_index(pkg_cfg): + pkg_cfg = copy.deepcopy(pkg_cfg) + for pkg in pkg_cfg.packages: + root_dir = pkg_cfg.packages[pkg].root_dir + files = _get_files_in_dir(root_dir) + pkg_cfg.packages[pkg].files = files + try: + readme = open(root_dir + '/README.md').read() + pkg_cfg.packages[pkg].readme = readme + except IOError: + pass + del pkg_cfg.packages[pkg].root_dir + return pkg_cfg.packages + +def build_pkg_cfg(root): + pkg_cfg = build_config(root, Bunch(name='dummy')) + del pkg_cfg.packages['dummy'] + return pkg_cfg + +def call_plugins(pkg_cfg, deps): + for dep in deps: + dep_cfg = pkg_cfg.packages[dep] + dirnames = dep_cfg.get('python-lib', []) + for dirname in resolve_dirs(dep_cfg, dirnames): + sys.path.append(dirname) + module_names = dep_cfg.get('python-plugins', []) + for module_name in module_names: + module = __import__(module_name) + module.init(root_dir=dep_cfg.root_dir) + +def call_cmdline_tool(env_root, pkg_name): + pkg_cfg = build_config(env_root, Bunch(name='dummy')) + if pkg_name not in pkg_cfg.packages: + print "This tool requires the '%s' package." % pkg_name + sys.exit(1) + cfg = pkg_cfg.packages[pkg_name] + for dirname in resolve_dirs(cfg, cfg['python-lib']): + sys.path.append(dirname) + module_name = cfg.get('python-cmdline-tool') + module = __import__(module_name) + module.run() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/preflight.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/preflight.py new file mode 100755 index 0000000..8b500ec --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/preflight.py @@ -0,0 +1,77 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os, sys +import base64 +import simplejson as json + +def create_jid(): + """Return 'jid1-XYZ', where 'XYZ' is a randomly-generated string. (in the + previous jid0- series, the string securely identified a specific public + key). To get a suitable add-on ID, append '@jetpack' to this string. + """ + # per https://developer.mozilla.org/en/Install_Manifests#id all XPI id + # values must either be in the form of a 128-bit GUID (crazy braces + # and all) or in the form of an email address (crazy @ and all). + # Firefox will refuse to install an add-on with an id that doesn't + # match one of these forms. The actual regexp is at: + # http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/XPIProvider.jsm#130 + # So the JID needs an @-suffix, and the only legal punctuation is + # "-._". So we start with a base64 encoding, and replace the + # punctuation (+/) with letters (AB), losing a few bits of integrity. + + # even better: windows has a maximum path length limitation of 256 + # characters: + # http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx + # (unless all paths are prefixed with "\\?\", I kid you not). The + # typical install will put add-on code in a directory like: + # C:\Documents and Settings\\Application Data\Mozilla\Firefox\Profiles\232353483.default\extensions\$JID\... + # (which is 108 chars long without the $JID). + # Then the unpacked XPI contains packaged resources like: + # resources/$JID-api-utils-lib/main.js (35 chars plus the $JID) + # + # We create a random 80 bit string, base64 encode that (with + # AB instead of +/ to be path-safe), then bundle it into + # "jid1-XYZ@jetpack". This gives us 27 characters. The resulting + # main.js will have a path length of 211 characters, leaving us 45 + # characters of margin. + # + # 80 bits is enough to generate one billion JIDs and still maintain lower + # than a one-in-a-million chance of accidental collision. (1e9 JIDs is 30 + # bits, square for the "birthday-paradox" to get 60 bits, add 20 bits for + # the one-in-a-million margin to get 80 bits) + + # if length were no issue, we'd prefer to use this: + h = os.urandom(80/8) + s = base64.b64encode(h, "AB").strip("=") + jid = "jid1-" + s + return jid + +def preflight_config(target_cfg, filename, stderr=sys.stderr): + modified = False + config = json.load(open(filename, 'r')) + + if "id" not in config: + print >>stderr, ("No 'id' in package.json: creating a new ID for you.") + jid = create_jid() + config["id"] = jid + modified = True + + if modified: + i = 0 + backup = filename + ".backup" + while os.path.exists(backup): + if i > 1000: + raise ValueError("I'm having problems finding a good name" + " for the backup file. Please move %s out" + " of the way and try again." + % (filename + ".backup")) + backup = filename + ".backup-%d" % i + i += 1 + os.rename(filename, backup) + new_json = json.dumps(config, indent=4) + open(filename, 'w').write(new_json+"\n") + return False, True + + return True, False diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py new file mode 100644 index 0000000..8d20039 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/prefs.py @@ -0,0 +1,115 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DEFAULT_COMMON_PREFS = { + # allow debug output via dump to be printed to the system console + # (setting it here just in case, even though PlainTextConsole also + # sets this preference) + 'browser.dom.window.dump.enabled': True, + # warn about possibly incorrect code + 'javascript.options.strict': True, + 'javascript.options.showInConsole': True, + + 'extensions.checkCompatibility.nightly' : False, + + # Disable extension updates and notifications. + 'extensions.update.enabled' : False, + 'extensions.update.notifyUser' : False, + + # From: + # http://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l372 + # Only load extensions from the application and user profile. + # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION + 'extensions.enabledScopes' : 5, + # Disable metadata caching for installed add-ons by default + 'extensions.getAddons.cache.enabled' : False, + # Disable intalling any distribution add-ons + 'extensions.installDistroAddons' : False, + # Allow installing extensions dropped into the profile folder + 'extensions.autoDisableScopes' : 10, + + # Point update checks to a nonexistent local URL for fast failures. + 'extensions.update.url' : 'http://localhost/extensions-dummy/updateURL', + 'extensions.blocklist.url' : 'http://localhost/extensions-dummy/blocklistURL', + # Make sure opening about:addons won't hit the network. + 'extensions.webservice.discoverURL' : 'http://localhost/extensions-dummy/discoveryURL' +} + +DEFAULT_FENNEC_PREFS = { + 'browser.console.showInPanel': True, + 'browser.firstrun.show.uidiscovery': False +} + +# When launching a temporary new Firefox profile, use these preferences. +DEFAULT_FIREFOX_PREFS = { + 'browser.startup.homepage' : 'about:blank', + 'startup.homepage_welcome_url' : 'about:blank', + 'devtools.errorconsole.enabled' : True, + + # Disable the feedback extension + 'extensions.testpilot.runStudies' : False, + + # From: + # http://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l388 + # Make url-classifier updates so rare that they won't affect tests. + 'urlclassifier.updateinterval' : 172800, + # Point the url-classifier to a nonexistent local URL for fast failures. + 'browser.safebrowsing.provider.0.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash', + 'browser.safebrowsing.provider.0.keyURL' : 'http://localhost/safebrowsing-dummy/newkey', + 'browser.safebrowsing.provider.0.updateURL' : 'http://localhost/safebrowsing-dummy/update', + } + +# When launching a temporary new Thunderbird profile, use these preferences. +# Note that these were taken from: +# http://mxr.mozilla.org/comm-central/source/mail/test/mozmill/runtest.py +DEFAULT_THUNDERBIRD_PREFS = { + # say no to slow script warnings + 'dom.max_chrome_script_run_time': 200, + 'dom.max_script_run_time': 0, + # do not ask about being the default mail client + 'mail.shell.checkDefaultClient': False, + # disable non-gloda indexing daemons + 'mail.winsearch.enable': False, + 'mail.winsearch.firstRunDone': True, + 'mail.spotlight.enable': False, + 'mail.spotlight.firstRunDone': True, + # disable address books for undisclosed reasons + 'ldap_2.servers.osx.position': 0, + 'ldap_2.servers.oe.position': 0, + # disable the first use junk dialog + 'mailnews.ui.junk.firstuse': False, + # other unknown voodoo + # -- dummied up local accounts to stop the account wizard + 'mail.account.account1.server' : "server1", + 'mail.account.account2.identities' : "id1", + 'mail.account.account2.server' : "server2", + 'mail.accountmanager.accounts' : "account1,account2", + 'mail.accountmanager.defaultaccount' : "account2", + 'mail.accountmanager.localfoldersserver' : "server1", + 'mail.identity.id1.fullName' : "Tinderbox", + 'mail.identity.id1.smtpServer' : "smtp1", + 'mail.identity.id1.useremail' : "tinderbox@invalid.com", + 'mail.identity.id1.valid' : True, + 'mail.root.none-rel' : "[ProfD]Mail", + 'mail.root.pop3-rel' : "[ProfD]Mail", + 'mail.server.server1.directory-rel' : "[ProfD]Mail/Local Folders", + 'mail.server.server1.hostname' : "Local Folders", + 'mail.server.server1.name' : "Local Folders", + 'mail.server.server1.type' : "none", + 'mail.server.server1.userName' : "nobody", + 'mail.server.server2.check_new_mail' : False, + 'mail.server.server2.directory-rel' : "[ProfD]Mail/tinderbox", + 'mail.server.server2.download_on_biff' : True, + 'mail.server.server2.hostname' : "tinderbox", + 'mail.server.server2.login_at_startup' : False, + 'mail.server.server2.name' : "tinderbox@invalid.com", + 'mail.server.server2.type' : "pop3", + 'mail.server.server2.userName' : "tinderbox", + 'mail.smtp.defaultserver' : "smtp1", + 'mail.smtpserver.smtp1.hostname' : "tinderbox", + 'mail.smtpserver.smtp1.username' : "tinderbox", + 'mail.smtpservers' : "smtp1", + 'mail.startup.enabledMailCheckOnce' : True, + 'mailnews.start_page_override.mstone' : "ignore", + } diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/property_parser.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/property_parser.py new file mode 100644 index 0000000..b3f554d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/property_parser.py @@ -0,0 +1,106 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import re +import codecs + +class MalformedLocaleFileError(Exception): + pass + +def parse_file(path): + return parse(read_file(path), path) + +def read_file(path): + try: + return codecs.open( path, "r", "utf-8" ).readlines() + except UnicodeDecodeError, e: + raise MalformedLocaleFileError( + 'Following locale file is not a valid ' + + 'UTF-8 file: %s\n%s"' % (path, str(e))) + +COMMENT = re.compile(r'\s*#') +EMPTY = re.compile(r'^\s+$') +KEYVALUE = re.compile(r"\s*([^=:]+)(=|:)\s*(.*)") + +def parse(lines, path=None): + lines = iter(lines) + lineNo = 1 + pairs = dict() + for line in lines: + if COMMENT.match(line) or EMPTY.match(line) or len(line) == 0: + continue + m = KEYVALUE.match(line) + if not m: + raise MalformedLocaleFileError( + 'Following locale file is not a valid .properties file: %s\n' + 'Line %d is incorrect:\n%s' % (path, lineNo, line)) + + # All spaces are strip. Spaces at the beginning are stripped + # by the regular expression. We have to strip spaces at the end. + key = m.group(1).rstrip() + val = m.group(3).rstrip() + + # `key` can be empty when key is only made of spaces + if not key: + raise MalformedLocaleFileError( + 'Following locale file is not a valid .properties file: %s\n' + 'Key is invalid on line %d is incorrect:\n%s' % + (path, lineNo, line)) + + # Multiline value: keep reading lines, while lines end with backslash + # and strip spaces at the beginning of lines except the last line + # that doesn't end up with backslash, we strip all spaces for this one. + if val.endswith("\\"): + val = val[:-1] + try: + # remove spaces before/after and especially the \n at EOL + line = lines.next().strip() + while line.endswith("\\"): + val += line[:-1].lstrip() + line = lines.next() + lineNo += 1 + val += line.strip() + except StopIteration: + raise MalformedLocaleFileError( + 'Following locale file is not a valid .properties file: %s\n' + 'Unexpected EOF in multiline sequence at line %d:\n%s' % + (path, lineNo, line)) + # Save this new pair + pairs[key] = val + lineNo += 1 + + normalize_plural(path, pairs) + return pairs + +# Plural forms in properties files are defined like this: +# key = other form +# key[one] = one form +# key[...] = ... +# Parse them and merge each key into one object containing all forms: +# key: { +# other: "other form", +# one: "one form", +# ...: ... +# } +PLURAL_FORM = re.compile(r'^(.*)\[(zero|one|two|few|many|other)\]$') +def normalize_plural(path, pairs): + for key in list(pairs.keys()): + m = PLURAL_FORM.match(key) + if not m: + continue + main_key = m.group(1) + plural_form = m.group(2) + if not main_key in pairs: + raise MalformedLocaleFileError( + 'Following locale file is not a valid UTF-8 file: %s\n' + 'This plural form doesn\'t have a matching generic form:\n' + '%s\n' + 'You have to defined following key:\n%s' + % (path, key, main_key)) + # convert generic form into an object if it is still a string + if isinstance(pairs[main_key], unicode): + pairs[main_key] = {"other": pairs[main_key]} + # then, add this new plural form + pairs[main_key][plural_form] = pairs[key] + del pairs[key] diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py new file mode 100644 index 0000000..389f512 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/rdf.py @@ -0,0 +1,190 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import xml.dom.minidom +import StringIO + +RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +EM_NS = "http://www.mozilla.org/2004/em-rdf#" + +class RDF(object): + def __str__(self): + # real files have an .encoding attribute and use it when you + # write() unicode into them: they read()/write() unicode and + # put encoded bytes in the backend file. StringIO objects + # read()/write() unicode and put unicode in the backing store, + # so we must encode the output of getvalue() to get a + # bytestring. (cStringIO objects are weirder: they effectively + # have .encoding hardwired to "ascii" and put only bytes in + # the backing store, so we can't use them here). + # + # The encoding= argument to dom.writexml() merely sets the XML header's + # encoding= attribute. It still writes unencoded unicode to the output file, + # so we have to encode it for real afterwards. + # + # Also see: https://bugzilla.mozilla.org/show_bug.cgi?id=567660 + + buf = StringIO.StringIO() + self.dom.writexml(buf, encoding="utf-8") + return buf.getvalue().encode('utf-8') + +class RDFUpdate(RDF): + def __init__(self): + impl = xml.dom.minidom.getDOMImplementation() + self.dom = impl.createDocument(RDF_NS, "RDF", None) + self.dom.documentElement.setAttribute("xmlns", RDF_NS) + self.dom.documentElement.setAttribute("xmlns:em", EM_NS) + + def _make_node(self, name, value, parent): + elem = self.dom.createElement(name) + elem.appendChild(self.dom.createTextNode(value)) + parent.appendChild(elem) + return elem + + def add(self, manifest, update_link): + desc = self.dom.createElement("Description") + desc.setAttribute( + "about", + "urn:mozilla:extension:%s" % manifest.get("em:id") + ) + self.dom.documentElement.appendChild(desc) + + updates = self.dom.createElement("em:updates") + desc.appendChild(updates) + + seq = self.dom.createElement("Seq") + updates.appendChild(seq) + + li = self.dom.createElement("li") + seq.appendChild(li) + + li_desc = self.dom.createElement("Description") + li.appendChild(li_desc) + + self._make_node("em:version", manifest.get("em:version"), + li_desc) + + apps = manifest.dom.documentElement.getElementsByTagName( + "em:targetApplication" + ) + + for app in apps: + target_app = self.dom.createElement("em:targetApplication") + li_desc.appendChild(target_app) + + ta_desc = self.dom.createElement("Description") + target_app.appendChild(ta_desc) + + for name in ["em:id", "em:minVersion", "em:maxVersion"]: + elem = app.getElementsByTagName(name)[0] + self._make_node(name, elem.firstChild.nodeValue, ta_desc) + + self._make_node("em:updateLink", update_link, ta_desc) + +class RDFManifest(RDF): + def __init__(self, path): + self.dom = xml.dom.minidom.parse(path) + + def set(self, property, value): + elements = self.dom.documentElement.getElementsByTagName(property) + if not elements: + raise ValueError("Element with value not found: %s" % property) + if not elements[0].firstChild: + elements[0].appendChild(self.dom.createTextNode(value)) + else: + elements[0].firstChild.nodeValue = value + + def get(self, property, default=None): + elements = self.dom.documentElement.getElementsByTagName(property) + if not elements: + return default + return elements[0].firstChild.nodeValue + + def remove(self, property): + elements = self.dom.documentElement.getElementsByTagName(property) + if not elements: + return True + else: + for i in elements: + i.parentNode.removeChild(i); + + return True; + +def gen_manifest(template_root_dir, target_cfg, jid, + update_url=None, bootstrap=True, enable_mobile=False): + install_rdf = os.path.join(template_root_dir, "install.rdf") + manifest = RDFManifest(install_rdf) + dom = manifest.dom + + manifest.set("em:id", jid) + manifest.set("em:version", + target_cfg.get('version', '1.0')) + manifest.set("em:name", + target_cfg.get('fullName', target_cfg['name'])) + manifest.set("em:description", + target_cfg.get("description", "")) + manifest.set("em:creator", + target_cfg.get("author", "")) + manifest.set("em:bootstrap", str(bootstrap).lower()) + # XPIs remain packed by default, but package.json can override that. The + # RDF format accepts "true" as True, anything else as False. We expect + # booleans in the .json file, not strings. + manifest.set("em:unpack", "true" if target_cfg.get("unpack") else "false") + + for contributor in target_cfg.get("contributors", [ ]): + elem = dom.createElement("em:contributor"); + elem.appendChild(dom.createTextNode(contributor)) + dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem) + + if update_url: + manifest.set("em:updateURL", update_url) + else: + manifest.remove("em:updateURL") + + if target_cfg.get("preferences"): + manifest.set("em:optionsType", "2") + else: + manifest.remove("em:optionsType") + + if enable_mobile: + target_app = dom.createElement("em:targetApplication") + dom.documentElement.getElementsByTagName("Description")[0].appendChild(target_app) + + ta_desc = dom.createElement("Description") + target_app.appendChild(ta_desc) + + elem = dom.createElement("em:id") + elem.appendChild(dom.createTextNode("{aa3c5121-dab2-40e2-81ca-7ea25febc110}")) + ta_desc.appendChild(elem) + + elem = dom.createElement("em:minVersion") + elem.appendChild(dom.createTextNode("10.0")) + ta_desc.appendChild(elem) + + elem = dom.createElement("em:maxVersion") + elem.appendChild(dom.createTextNode("13.0a1")) + ta_desc.appendChild(elem) + + if target_cfg.get("homepage"): + manifest.set("em:homepageURL", target_cfg.get("homepage")) + else: + manifest.remove("em:homepageURL") + + return manifest + +if __name__ == "__main__": + print "Running smoke test." + root = os.path.join(os.path.dirname(__file__), 'app-extension') + manifest = gen_manifest(root, {'name': 'test extension'}, + 'fakeid', 'http://foo.com/update.rdf') + update = RDFUpdate() + update.add(manifest, "https://foo.com/foo.xpi") + exercise_str = str(manifest) + str(update) + for tagname in ["em:targetApplication", "em:version", "em:id"]: + if not len(update.dom.getElementsByTagName(tagname)): + raise Exception("tag does not exist: %s" % tagname) + if not update.dom.getElementsByTagName(tagname)[0].firstChild: + raise Exception("tag has no children: %s" % tagname) + print "Success!" diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/runner.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/runner.py new file mode 100644 index 0000000..76be215 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/runner.py @@ -0,0 +1,696 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import sys +import time +import tempfile +import atexit +import shlex +import subprocess +import re + +import mozrunner +from cuddlefish.prefs import DEFAULT_COMMON_PREFS +from cuddlefish.prefs import DEFAULT_FIREFOX_PREFS +from cuddlefish.prefs import DEFAULT_THUNDERBIRD_PREFS +from cuddlefish.prefs import DEFAULT_FENNEC_PREFS + +# Used to remove noise from ADB output +CLEANUP_ADB = re.compile(r'^(I|E)/(stdout|stderr|GeckoConsole)\s*\(\s*\d+\):\s*(.*)$') +# Used to filter only messages send by `console` module +FILTER_ONLY_CONSOLE_FROM_ADB = re.compile(r'^I/(stderr)\s*\(\s*\d+\):\s*((info|warning|error|debug): .*)$') + +# Maximum time we'll wait for tests to finish, in seconds. +# The purpose of this timeout is to recover from infinite loops. It should be +# longer than the amount of time any test run takes, including those on slow +# machines running slow (debug) versions of Firefox. +RUN_TIMEOUT = 30 * 60 # 30 minutes + +# Maximum time we'll wait for tests to emit output, in seconds. +# The purpose of this timeout is to recover from hangs. It should be longer +# than the amount of time any test takes to report results. +OUTPUT_TIMEOUT = 60 # one minute + +def follow_file(filename): + """ + Generator that yields the latest unread content from the given + file, or None if no new content is available. + + For example: + + >>> f = open('temp.txt', 'w') + >>> f.write('hello') + >>> f.flush() + >>> tail = follow_file('temp.txt') + >>> tail.next() + 'hello' + >>> tail.next() is None + True + >>> f.write('there') + >>> f.flush() + >>> tail.next() + 'there' + >>> f.close() + >>> os.remove('temp.txt') + """ + + last_pos = 0 + last_size = 0 + while True: + newstuff = None + if os.path.exists(filename): + size = os.stat(filename).st_size + if size > last_size: + last_size = size + f = open(filename, 'r') + f.seek(last_pos) + newstuff = f.read() + last_pos = f.tell() + f.close() + yield newstuff + +# subprocess.check_output only appeared in python2.7, so this code is taken +# from python source code for compatibility with py2.5/2.6 +class CalledProcessError(Exception): + def __init__(self, returncode, cmd, output=None): + self.returncode = returncode + self.cmd = cmd + self.output = output + def __str__(self): + return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + +def check_output(*popenargs, **kwargs): + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd, output=output) + return output + + +class FennecProfile(mozrunner.Profile): + preferences = {} + names = ['fennec'] + +class FennecRunner(mozrunner.Runner): + profile_class = FennecProfile + + names = ['fennec'] + + __DARWIN_PATH = '/Applications/Fennec.app/Contents/MacOS/fennec' + + def __init__(self, binary=None, **kwargs): + if sys.platform == 'darwin' and binary and binary.endswith('.app'): + # Assume it's a Fennec app dir. + binary = os.path.join(binary, 'Contents/MacOS/fennec') + + self.__real_binary = binary + + mozrunner.Runner.__init__(self, **kwargs) + + def find_binary(self): + if not self.__real_binary: + if sys.platform == 'darwin': + if os.path.exists(self.__DARWIN_PATH): + return self.__DARWIN_PATH + self.__real_binary = mozrunner.Runner.find_binary(self) + return self.__real_binary + + +class RemoteFennecRunner(mozrunner.Runner): + profile_class = FennecProfile + + names = ['fennec'] + + _REMOTE_PATH = '/mnt/sdcard/jetpack-profile' + _INTENT_PREFIX = 'org.mozilla.' + + _adb_path = None + + def __init__(self, binary=None, **kwargs): + # Check that we have a binary set + if not binary: + raise ValueError("You have to define `--binary` option set to the " + "path to your ADB executable.") + # Ensure that binary refer to a valid ADB executable + output = subprocess.Popen([binary], stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + output = "".join(output) + if not ("Android Debug Bridge" in output): + raise ValueError("`--binary` option should be the path to your " + "ADB executable.") + self.binary = binary + + mobile_app_name = kwargs['cmdargs'][0] + self.profile = kwargs['profile'] + self._adb_path = binary + + # This pref has to be set to `false` otherwise, we do not receive + # output of adb commands! + subprocess.call([self._adb_path, "shell", + "setprop log.redirect-stdio false"]) + + # Android apps are launched by their "intent" name, + # Automatically detect already installed firefox by using `pm` program + # or use name given as cfx `--mobile-app` argument. + intents = self.getIntentNames() + if not intents: + raise ValueError("Unable to found any Firefox " + "application on your device.") + elif mobile_app_name: + if not mobile_app_name in intents: + raise ValueError("Unable to found Firefox application " + "with intent name '%s'\n" + "Available ones are: %s" % + (mobile_app_name, ", ".join(intents))) + self._intent_name = self._INTENT_PREFIX + mobile_app_name + else: + if "firefox" in intents: + self._intent_name = self._INTENT_PREFIX + "firefox" + elif "firefox_beta" in intents: + self._intent_name = self._INTENT_PREFIX + "firefox_beta" + elif "firefox_nightly" in intents: + self._intent_name = self._INTENT_PREFIX + "firefox_nightly" + else: + self._intent_name = self._INTENT_PREFIX + intents[0] + + print "Launching mobile application with intent name " + self._intent_name + + # First try to kill firefox if it is already running + pid = self.getProcessPID(self._intent_name) + if pid != None: + # Send a key "up" signal to mobile-utils addon + # in order to kill running firefox instance + # KEYCODE_DPAD_UP = 19 + # http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_DPAD_UP + print "Killing running Firefox instance ..." + subprocess.call([self._adb_path, "shell", "input keyevent 19"]) + subprocess.Popen(self.command, stdout=subprocess.PIPE).wait() + time.sleep(2) + + print "Pushing the addon to your device" + + # Create a clean empty profile on the sd card + subprocess.call([self._adb_path, "shell", "rm -r " + self._REMOTE_PATH]) + subprocess.call([self._adb_path, "shell", "mkdir " + self._REMOTE_PATH]) + + # Push the profile folder created by mozrunner to the device + # (we can't simply use `adb push` as it doesn't copy empty folders) + localDir = self.profile.profile + remoteDir = self._REMOTE_PATH + for root, dirs, files in os.walk(localDir, followlinks='true'): + relRoot = os.path.relpath(root, localDir) + # Note about os.path usage below: + # Local files may be using Windows `\` separators but + # remote are always `/`, so we need to convert local ones to `/` + for file in files: + localFile = os.path.join(root, file) + remoteFile = remoteDir.replace("/", os.sep) + if relRoot != ".": + remoteFile = os.path.join(remoteFile, relRoot) + remoteFile = os.path.join(remoteFile, file) + remoteFile = "/".join(remoteFile.split(os.sep)) + subprocess.Popen([self._adb_path, "push", localFile, remoteFile], + stderr=subprocess.PIPE).wait() + for dir in dirs: + targetDir = remoteDir.replace("/", os.sep) + if relRoot != ".": + targetDir = os.path.join(targetDir, relRoot) + targetDir = os.path.join(targetDir, dir) + targetDir = "/".join(targetDir.split(os.sep)) + # `-p` option is not supported on all devices! + subprocess.call([self._adb_path, "shell", "mkdir " + targetDir]) + + @property + def command(self): + """Returns the command list to run.""" + return [self._adb_path, + "shell", + "am start " + + "-a android.activity.MAIN " + + "-n " + self._intent_name + "/" + self._intent_name + ".App " + + "--es args \"-profile " + self._REMOTE_PATH + "\"" + ] + + def start(self): + subprocess.call(self.command) + + def getProcessPID(self, processName): + p = subprocess.Popen([self._adb_path, "shell", "ps"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + line = p.stdout.readline() + while line: + columns = line.split() + pid = columns[1] + name = columns[-1] + line = p.stdout.readline() + if processName in name: + return pid + return None + + def getIntentNames(self): + p = subprocess.Popen([self._adb_path, "shell", "pm list packages"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + names = [] + for line in p.stdout.readlines(): + line = re.sub("(^package:)|\s", "", line) + if self._INTENT_PREFIX in line: + names.append(line.replace(self._INTENT_PREFIX, "")) + return names + + +class XulrunnerAppProfile(mozrunner.Profile): + preferences = {} + names = [] + +class XulrunnerAppRunner(mozrunner.Runner): + """ + Runner for any XULRunner app. Can use a Firefox binary in XULRunner + mode to execute the app, or can use XULRunner itself. Expects the + app's application.ini to be passed in as one of the items in + 'cmdargs' in the constructor. + + This class relies a lot on the particulars of mozrunner.Runner's + implementation, and does some unfortunate acrobatics to get around + some of the class' limitations/assumptions. + """ + + profile_class = XulrunnerAppProfile + + # This is a default, and will be overridden in the instance if + # Firefox is used in XULRunner mode. + names = ['xulrunner'] + + # Default location of XULRunner on OS X. + __DARWIN_PATH = "/Library/Frameworks/XUL.framework/xulrunner-bin" + __LINUX_PATH = "/usr/bin/xulrunner" + + # What our application.ini's path looks like if it's part of + # an "installed" XULRunner app on OS X. + __DARWIN_APP_INI_SUFFIX = '.app/Contents/Resources/application.ini' + + def __init__(self, binary=None, **kwargs): + if sys.platform == 'darwin' and binary and binary.endswith('.app'): + # Assume it's a Firefox app dir. + binary = os.path.join(binary, 'Contents/MacOS/firefox-bin') + + self.__app_ini = None + self.__real_binary = binary + + mozrunner.Runner.__init__(self, **kwargs) + + # See if we're using a genuine xulrunner-bin from the XULRunner SDK, + # or if we're being asked to use Firefox in XULRunner mode. + self.__is_xulrunner_sdk = 'xulrunner' in self.binary + + if sys.platform == 'linux2' and not self.env.get('LD_LIBRARY_PATH'): + self.env['LD_LIBRARY_PATH'] = os.path.dirname(self.binary) + + newargs = [] + for item in self.cmdargs: + if 'application.ini' in item: + self.__app_ini = item + else: + newargs.append(item) + self.cmdargs = newargs + + if not self.__app_ini: + raise ValueError('application.ini not found in cmdargs') + if not os.path.exists(self.__app_ini): + raise ValueError("file does not exist: '%s'" % self.__app_ini) + + if (sys.platform == 'darwin' and + self.binary == self.__DARWIN_PATH and + self.__app_ini.endswith(self.__DARWIN_APP_INI_SUFFIX)): + # If the application.ini is in an app bundle, then + # it could be inside an "installed" XULRunner app. + # If this is the case, use the app's actual + # binary instead of the XUL framework's, so we get + # a proper app icon, etc. + new_binary = '/'.join(self.__app_ini.split('/')[:-2] + + ['MacOS', 'xulrunner']) + if os.path.exists(new_binary): + self.binary = new_binary + + @property + def command(self): + """Returns the command list to run.""" + + if self.__is_xulrunner_sdk: + return [self.binary, self.__app_ini, '-profile', + self.profile.profile] + else: + return [self.binary, '-app', self.__app_ini, '-profile', + self.profile.profile] + + def __find_xulrunner_binary(self): + if sys.platform == 'darwin': + if os.path.exists(self.__DARWIN_PATH): + return self.__DARWIN_PATH + if sys.platform == 'linux2': + if os.path.exists(self.__LINUX_PATH): + return self.__LINUX_PATH + return None + + def find_binary(self): + # This gets called by the superclass constructor. It will + # always get called, even if a binary was passed into the + # constructor, because we want to have full control over + # what the exact setting of self.binary is. + + if not self.__real_binary: + self.__real_binary = self.__find_xulrunner_binary() + if not self.__real_binary: + dummy_profile = {} + runner = mozrunner.FirefoxRunner(profile=dummy_profile) + self.__real_binary = runner.find_binary() + self.names = runner.names + return self.__real_binary + +def run_app(harness_root_dir, manifest_rdf, harness_options, + app_type, binary=None, profiledir=None, verbose=False, + enforce_timeouts=False, + logfile=None, addons=None, args=None, extra_environment={}, + norun=None, + used_files=None, enable_mobile=False, + mobile_app_name=None): + if binary: + binary = os.path.expanduser(binary) + + if addons is None: + addons = [] + else: + addons = list(addons) + + cmdargs = [] + preferences = dict(DEFAULT_COMMON_PREFS) + + # For now, only allow running on Mobile with --force-mobile argument + if app_type in ["fennec", "fennec-on-device"] and not enable_mobile: + print """ + WARNING: Firefox Mobile support is still experimental. + If you would like to run an addon on this platform, use --force-mobile flag: + + cfx --force-mobile""" + return 0 + + if app_type == "fennec-on-device": + profile_class = FennecProfile + preferences.update(DEFAULT_FENNEC_PREFS) + runner_class = RemoteFennecRunner + # We pass the intent name through command arguments + cmdargs.append(mobile_app_name) + elif enable_mobile or app_type == "fennec": + profile_class = FennecProfile + preferences.update(DEFAULT_FENNEC_PREFS) + runner_class = FennecRunner + elif app_type == "xulrunner": + profile_class = XulrunnerAppProfile + runner_class = XulrunnerAppRunner + cmdargs.append(os.path.join(harness_root_dir, 'application.ini')) + elif app_type == "firefox": + profile_class = mozrunner.FirefoxProfile + preferences.update(DEFAULT_FIREFOX_PREFS) + runner_class = mozrunner.FirefoxRunner + elif app_type == "thunderbird": + profile_class = mozrunner.ThunderbirdProfile + preferences.update(DEFAULT_THUNDERBIRD_PREFS) + runner_class = mozrunner.ThunderbirdRunner + else: + raise ValueError("Unknown app: %s" % app_type) + if sys.platform == 'darwin' and app_type != 'xulrunner': + cmdargs.append('-foreground') + + if args: + cmdargs.extend(shlex.split(args)) + + # TODO: handle logs on remote device + if app_type != "fennec-on-device": + # tempfile.gettempdir() was constant, preventing two simultaneous "cfx + # run"/"cfx test" on the same host. On unix it points at /tmp (which is + # world-writeable), enabling a symlink attack (e.g. imagine some bad guy + # does 'ln -s ~/.ssh/id_rsa /tmp/harness_result'). NamedTemporaryFile + # gives us a unique filename that fixes both problems. We leave the + # (0-byte) file in place until the browser-side code starts writing to + # it, otherwise the symlink attack becomes possible again. + fileno,resultfile = tempfile.mkstemp(prefix="harness-result-") + os.close(fileno) + harness_options['resultFile'] = resultfile + + def maybe_remove_logfile(): + if os.path.exists(logfile): + os.remove(logfile) + + logfile_tail = None + + # We always buffer output through a logfile for two reasons: + # 1. On Windows, it's the only way to print console output to stdout/err. + # 2. It enables us to keep track of the last time output was emitted, + # so we can raise an exception if the test runner hangs. + if not logfile: + fileno,logfile = tempfile.mkstemp(prefix="harness-log-") + os.close(fileno) + logfile_tail = follow_file(logfile) + atexit.register(maybe_remove_logfile) + + logfile = os.path.abspath(os.path.expanduser(logfile)) + maybe_remove_logfile() + + if app_type != "fennec-on-device": + harness_options['logFile'] = logfile + + env = {} + env.update(os.environ) + env['MOZ_NO_REMOTE'] = '1' + env['XPCOM_DEBUG_BREAK'] = 'stack' + env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1' + env.update(extra_environment) + if norun: + cmdargs.append("-no-remote") + + # Create the addon XPI so mozrunner will copy it to the profile it creates. + # We delete it below after getting mozrunner to create the profile. + from cuddlefish.xpi import build_xpi + xpi_path = tempfile.mktemp(suffix='cfx-tmp.xpi') + build_xpi(template_root_dir=harness_root_dir, + manifest=manifest_rdf, + xpi_path=xpi_path, + harness_options=harness_options, + limit_to=used_files) + addons.append(xpi_path) + + starttime = last_output_time = time.time() + + # Redirect runner output to a file so we can catch output not generated + # by us. + # In theory, we could do this using simple redirection on all platforms + # other than Windows, but this way we only have a single codepath to + # maintain. + fileno,outfile = tempfile.mkstemp(prefix="harness-stdout-") + os.close(fileno) + outfile_tail = follow_file(outfile) + def maybe_remove_outfile(): + if os.path.exists(outfile): + os.remove(outfile) + atexit.register(maybe_remove_outfile) + outf = open(outfile, "w") + popen_kwargs = { 'stdout': outf, 'stderr': outf} + + profile = None + + if app_type == "fennec-on-device": + # Install a special addon when we run firefox on mobile device + # in order to be able to kill it + mydir = os.path.dirname(os.path.abspath(__file__)) + addon_dir = os.path.join(mydir, "mobile-utils") + addons.append(addon_dir) + + # the XPI file is copied into the profile here + profile = profile_class(addons=addons, + profile=profiledir, + preferences=preferences) + + # Delete the temporary xpi file + os.remove(xpi_path) + + runner = runner_class(profile=profile, + binary=binary, + env=env, + cmdargs=cmdargs, + kp_kwargs=popen_kwargs) + + sys.stdout.flush(); sys.stderr.flush() + + if app_type == "fennec-on-device": + if not enable_mobile: + print >>sys.stderr, """ + WARNING: Firefox Mobile support is still experimental. + If you would like to run an addon on this platform, use --force-mobile flag: + + cfx --force-mobile""" + return 0 + + # In case of mobile device, we need to get stdio from `adb logcat` cmd: + + # First flush logs in order to avoid catching previous ones + subprocess.call([binary, "logcat", "-c"]) + + # Launch adb command + runner.start() + + # We can immediatly remove temporary profile folder + # as it has been uploaded to the device + profile.cleanup() + # We are not going to use the output log file + outf.close() + + # Then we simply display stdout of `adb logcat` + p = subprocess.Popen([binary, "logcat", "stderr:V stdout:V GeckoConsole:V *:S"], stdout=subprocess.PIPE) + while True: + line = p.stdout.readline() + if line == '': + break + # mobile-utils addon contains an application quit event observer + # that will print this string: + if "APPLICATION-QUIT" in line: + break + + if verbose: + # if --verbose is given, we display everything: + # All JS Console messages, stdout and stderr. + m = CLEANUP_ADB.match(line) + if not m: + print line.rstrip() + continue + print m.group(3) + else: + # Otherwise, display addons messages dispatched through + # console.[info, log, debug, warning, error](msg) + m = FILTER_ONLY_CONSOLE_FROM_ADB.match(line) + if m: + print m.group(2) + + print >>sys.stderr, "Program terminated successfully." + return 0 + + + print >>sys.stderr, "Using binary at '%s'." % runner.binary + + # Ensure cfx is being used with Firefox 4.0+. + # TODO: instead of dying when Firefox is < 4, warn when Firefox is outside + # the minVersion/maxVersion boundaries. + version_output = check_output(runner.command + ["-v"]) + # Note: this regex doesn't handle all valid versions in the Toolkit Version + # Format , just the + # common subset that we expect Mozilla apps to use. + mo = re.search(r"Mozilla (Firefox|Iceweasel|Fennec) ((\d+)\.\S*)", + version_output) + if not mo: + # cfx may be used with Thunderbird, SeaMonkey or an exotic Firefox + # version. + print """ + WARNING: cannot determine Firefox version; please ensure you are running + a Mozilla application equivalent to Firefox 4.0 or greater. + """ + elif mo.group(1) == "Fennec": + # For now, only allow running on Mobile with --force-mobile argument + if not enable_mobile: + print """ + WARNING: Firefox Mobile support is still experimental. + If you would like to run an addon on this platform, use --force-mobile flag: + + cfx --force-mobile""" + return + else: + version = mo.group(3) + if int(version) < 4: + print """ + cfx requires Firefox 4 or greater and is unable to find a compatible + binary. Please install a newer version of Firefox or provide the path to + your existing compatible version with the --binary flag: + + cfx --binary=PATH_TO_FIREFOX_BINARY""" + return + + # Set the appropriate extensions.checkCompatibility preference to false, + # so the tests run even if the SDK is not marked as compatible with the + # version of Firefox on which they are running, and we don't have to + # ensure we update the maxVersion before the version of Firefox changes + # every six weeks. + # + # The regex we use here is effectively the same as BRANCH_REGEX from + # /toolkit/mozapps/extensions/content/extensions.js, which toolkit apps + # use to determine whether or not to load an incompatible addon. + # + br = re.search(r"^([^\.]+\.[0-9]+[a-z]*).*", mo.group(2), re.I) + if br: + prefname = 'extensions.checkCompatibility.' + br.group(1) + profile.preferences[prefname] = False + # Calling profile.set_preferences here duplicates the list of prefs + # in prefs.js, since the profile calls self.set_preferences in its + # constructor, but that is ok, because it doesn't change the set of + # preferences that are ultimately registered in Firefox. + profile.set_preferences(profile.preferences) + + print >>sys.stderr, "Using profile at '%s'." % profile.profile + sys.stderr.flush() + + if norun: + print "To launch the application, enter the following command:" + print " ".join(runner.command) + " " + (" ".join(runner.cmdargs)) + return 0 + + runner.start() + + done = False + result = None + try: + while not done: + time.sleep(0.05) + for tail in (logfile_tail, outfile_tail): + if tail: + new_chars = tail.next() + if new_chars: + last_output_time = time.time() + sys.stderr.write(new_chars) + sys.stderr.flush() + if os.path.exists(resultfile): + result = open(resultfile).read() + if result: + if result in ['OK', 'FAIL']: + done = True + else: + sys.stderr.write("Hrm, resultfile (%s) contained something weird (%d bytes)\n" % (resultfile, len(result))) + sys.stderr.write("'"+result+"'\n") + if enforce_timeouts: + if time.time() - last_output_time > OUTPUT_TIMEOUT: + raise Exception("Test output exceeded timeout (%ds)." % + OUTPUT_TIMEOUT) + if time.time() - starttime > RUN_TIMEOUT: + raise Exception("Test run exceeded timeout (%ds)." % + RUN_TIMEOUT) + except: + runner.stop() + raise + else: + runner.wait(10) + finally: + outf.close() + if profile: + profile.cleanup() + + print >>sys.stderr, "Total time: %f seconds" % (time.time() - starttime) + + if result == 'OK': + print >>sys.stderr, "Program terminated successfully." + return 0 + else: + print >>sys.stderr, "Program terminated unsuccessfully." + return -1 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/templates.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/templates.py new file mode 100644 index 0000000..a04bb9a --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/templates.py @@ -0,0 +1,83 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#Template used by main.js +MAIN_JS = '''\ +const widgets = require("widget"); +const tabs = require("tabs"); + +var widget = widgets.Widget({ + id: "mozilla-link", + label: "Mozilla website", + contentURL: "http://www.mozilla.org/favicon.ico", + onClick: function() { + tabs.open("http://www.mozilla.org/"); + } +}); + +console.log("The add-on is running."); +''' + +#Template used by test-main.js +TEST_MAIN_JS = '''\ +const main = require("main"); + +exports.test_test_run = function(test) { + test.pass("Unit test running!"); +}; + +exports.test_id = function(test) { + test.assert(require("self").id.length > 0); +}; + +exports.test_url = function(test) { + require("request").Request({ + url: "http://www.mozilla.org/", + onComplete: function(response) { + test.assertEqual(response.statusText, "OK"); + test.done(); + } + }).get(); + test.waitUntilDone(20000); +}; + +exports.test_open_tab = function(test) { + const tabs = require("tabs"); + tabs.open({ + url: "http://www.mozilla.org/", + onReady: function(tab) { + test.assertEqual(tab.url, "http://www.mozilla.org/"); + test.done(); + } + }); + test.waitUntilDone(20000); +}; +''' + +#Template used by main.md +MAIN_JS_DOC = '''\ +The main module is a program that creates a widget. When a user clicks on +the widget, the program loads the mozilla.org website in a new tab. +''' + +#Template used by README.md +README_DOC = '''\ +This is the %(name)s add-on. It contains: + +* A program (lib/main.js). +* A few tests. +* Some meager documentation. +''' + +#Template used by package.json +PACKAGE_JSON = '''\ +{ + "name": "%(name)s", + "fullName": "%(fullName)s", + "description": "a basic add-on", + "author": "", + "license": "MPL 2.0", + "version": "0.1" +} +''' diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/__init__.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/__init__.py new file mode 100644 index 0000000..c1a7fd2 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/__init__.py @@ -0,0 +1,65 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import unittest +import doctest +import glob + +env_root = os.environ['CUDDLEFISH_ROOT'] + +def get_tests(): + import cuddlefish + import cuddlefish.tests + + tests = [] + packages = [cuddlefish, cuddlefish.tests] + for package in packages: + path = os.path.abspath(package.__path__[0]) + pynames = glob.glob(os.path.join(path, '*.py')) + for filename in pynames: + basename = os.path.basename(filename) + module_name = os.path.splitext(basename)[0] + full_name = "%s.%s" % (package.__name__, module_name) + module = __import__(full_name, fromlist=[package.__name__]) + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(module) + for test in suite: + tests.append(test) + + finder = doctest.DocTestFinder() + doctests = finder.find(module) + for test in doctests: + if len(test.examples) > 0: + tests.append(doctest.DocTestCase(test)) + + md_dir = os.path.join(env_root, 'dev-guide') + doctest_opts = (doctest.NORMALIZE_WHITESPACE | + doctest.REPORT_UDIFF) + for dirpath, dirnames, filenames in os.walk(md_dir): + for filename in filenames: + if filename.endswith('.md'): + absname = os.path.join(dirpath, filename) + tests.append(doctest.DocFileTest( + absname, + module_relative=False, + optionflags=doctest_opts + )) + + return tests + +def run(verbose=False): + if verbose: + verbosity = 2 + else: + verbosity = 1 + + tests = get_tests() + suite = unittest.TestSuite(tests) + runner = unittest.TextTestRunner(verbosity=verbosity) + return runner.run(suite) + +if __name__ == '__main__': + run() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/main.js new file mode 100644 index 0000000..980ea88 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/main.js @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Cc, Ci } = require("chrome"); + +exports.main = function(options, callbacks) { + // Close Firefox window. Firefox should quit. + require("api-utils/window-utils").activeBrowserWindow.close(); + + // But not on Mac where it stay alive! We have to request application quit. + if (require("api-utils/runtime").OS == "Darwin") { + let appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. + getService(Ci.nsIAppStartup); + appStartup.quit(appStartup.eAttemptQuit); + } +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/package.json new file mode 100644 index 0000000..afbc158 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/package.json @@ -0,0 +1,6 @@ +{ + "id": "simplest-test", + "directories": { + "lib": "." + } +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js new file mode 100644 index 0000000..533cd34 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.minimalTest = function(test) { + test.assert(true); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon.png b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon.png new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon64.png b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/explicit-icon64.png new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/lib/main.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/lib/main.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/package.json new file mode 100644 index 0000000..8d56d74 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/explicit-icon/package.json @@ -0,0 +1,5 @@ +{ + "loader": "lib/main.js", + "icon": "explicit-icon.png", + "icon64": "explicit-icon64.png" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon.png b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon.png new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon64.png b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/icon64.png new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/lib/main.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/lib/main.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/package.json new file mode 100644 index 0000000..3f0e241 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/implicit-icon/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/lib/main.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/lib/main.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/package.json new file mode 100644 index 0000000..3f0e241 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588119-files/packages/no-icon/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/lib/bar-loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/lib/bar-loader.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/lib/bar-loader.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/package.json new file mode 100644 index 0000000..e83a9d4 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/bar/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/bar-loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/lib/foo-loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/lib/foo-loader.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/lib/foo-loader.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/package.json new file mode 100644 index 0000000..4648df6 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-588661-files/packages/foo/package.json @@ -0,0 +1,4 @@ +{ + "loader": "lib/foo-loader.js", + "dependencies": ["bar"] +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/docs/main.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/docs/main.md new file mode 100644 index 0000000..54518d3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/docs/main.md @@ -0,0 +1,5 @@ + + +minimal docs diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/lib/main.js new file mode 100644 index 0000000..aeda0e7 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = function(options, callbacks) { + console.log("minimal"); + callbacks.quit(); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/package.json new file mode 100644 index 0000000..45d409a --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-611495-files/jspath-one/package.json @@ -0,0 +1,5 @@ +{ + "name": "jspath-one", + "author": "Jon Smith", + "description": "A package w/ a main module; can be built into an extension." +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/doc/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/doc/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/doc/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/lib/foo-loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/lib/foo-loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/lib/foo-loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/package.json new file mode 100644 index 0000000..ccc61b2 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/foo-loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/test/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/test/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/commonjs-naming/test/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/docs/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/docs/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/docs/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/lib/foo-loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/lib/foo-loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/lib/foo-loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/package.json new file mode 100644 index 0000000..ccc61b2 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/foo-loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/tests/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/tests/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-614712-files/packages/original-naming/tests/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/doc/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/doc/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/doc/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/foo.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/foo.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/lib/loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/package.json new file mode 100644 index 0000000..c2d22aa --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/package.json @@ -0,0 +1,3 @@ +{ + "loader": "lib/loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/test/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/test/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-lib/test/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/locale/emptyFolder b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/locale/emptyFolder new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/package.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-locale/package.json @@ -0,0 +1 @@ +{} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/doc/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/doc/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/doc/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/foo.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/foo.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/package.json new file mode 100644 index 0000000..100249f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/package.json @@ -0,0 +1,3 @@ +{ + "loader": "loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/test/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/test/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/default-root/test/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/foo.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/foo.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/alt-lib/loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/doc/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/doc/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/doc/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/package.json new file mode 100644 index 0000000..f79250e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/package.json @@ -0,0 +1,4 @@ +{ + "directories": { "lib": "./alt-lib" }, + "loader": "alt-lib/loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/test/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/test/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-dir-lib/test/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/foo.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/foo.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/loader.js new file mode 100644 index 0000000..2daeb35 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/alt2-lib/loader.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/doc/foo.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/doc/foo.md new file mode 100644 index 0000000..c92ddb8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/doc/foo.md @@ -0,0 +1,5 @@ + + +I am documentation for foo. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/package.json new file mode 100644 index 0000000..b017baa --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/package.json @@ -0,0 +1,4 @@ +{ + "lib": "./alt2-lib", + "loader": "alt2-lib/loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/test/test-foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/test/test-foo.js new file mode 100644 index 0000000..bd0cfa9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-652227-files/packages/explicit-lib/test/test-foo.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.testThing = function(test) { + test.assertEqual(2, 1 + 1); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/docs/main.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/docs/main.md new file mode 100644 index 0000000..54518d3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/docs/main.md @@ -0,0 +1,5 @@ + + +minimal docs diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/lib/main.js new file mode 100644 index 0000000..aeda0e7 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = function(options, callbacks) { + console.log("minimal"); + callbacks.quit(); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/package.json new file mode 100644 index 0000000..de868f7 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-669274-files/packages/extra-options/package.json @@ -0,0 +1,6 @@ +{ + "name": "extra-options", + "author": "Jon Smith", + "description": "A package w/ a main module; can be built into an extension.", + "loader": "lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-1-pack/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-1-pack/package.json new file mode 100644 index 0000000..d18aa3d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-1-pack/package.json @@ -0,0 +1,10 @@ +{ + "name": "empty", + "license": "MPL 2.0", + "author": "", + "version": "0.1", + "fullName": "empty", + "id": "jid1-80fr8b6qeRlQSQ", + "unpack": false, + "description": "test unpack= support" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-2-unpack/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-2-unpack/package.json new file mode 100644 index 0000000..9bcf1eb --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-2-unpack/package.json @@ -0,0 +1,10 @@ +{ + "name": "empty", + "license": "MPL 2.0", + "author": "", + "version": "0.1", + "fullName": "empty", + "id": "jid1-80fr8b6qeRlQSQ", + "unpack": true, + "description": "test unpack= support" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-3-pack/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-3-pack/package.json new file mode 100644 index 0000000..45d1d91 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/bug-715340-files/pkg-3-pack/package.json @@ -0,0 +1,9 @@ +{ + "name": "empty", + "license": "MPL 2.0", + "author": "", + "version": "0.1", + "fullName": "empty", + "id": "jid1-80fr8b6qeRlQSQ", + "description": "test unpack= support" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar-e10s-adapter.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar-e10s-adapter.js new file mode 100644 index 0000000..ad54ae7 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar-e10s-adapter.js @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +if (this.sendMessage) { +} else { + require('bar'); + + exports.register = function(process) { + }; +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar.js new file mode 100644 index 0000000..fe9e4fb --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/bar.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +require('chrome'); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/foo.js new file mode 100644 index 0000000..55633d1 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/lib/foo.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +require('bar'); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/package.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/e10s-adapter-files/packages/foo/package.json @@ -0,0 +1 @@ +{} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/lib/main.js new file mode 100644 index 0000000..e32a30f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/lib/main.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = "'main' mainly reigns in main(.js)"; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/package.json new file mode 100644 index 0000000..98e4b85 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/five/package.json @@ -0,0 +1,3 @@ +{ "name": "five", + "main": "./lib/main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/lib/misc.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/lib/misc.js new file mode 100644 index 0000000..7e1ce7e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/lib/misc.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = 42; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/package.json new file mode 100644 index 0000000..3010fae --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/package.json @@ -0,0 +1,4 @@ +{ "name": "four-a", + "directories": {"lib": "lib"}, + "main": "./topfiles/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/topfiles/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/topfiles/main.js new file mode 100644 index 0000000..7e1ce7e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four-deps/four-a/topfiles/main.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = 42; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/lib/main.js new file mode 100644 index 0000000..b95f7bd --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/lib/main.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var a = require("four-a"); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/package.json new file mode 100644 index 0000000..53180b9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/four/package.json @@ -0,0 +1,3 @@ +{ "name": "four", + "main": "main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/main.js new file mode 100644 index 0000000..7b1f0de --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/main.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var panel = require("panel"); +var two = require("two.js"); +var a = require("./two"); +var b = require("addon-kit/tabs.js"); +var c = require("./subdir/three"); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/subdir/three.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/subdir/three.js new file mode 100644 index 0000000..b594f3c --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/subdir/three.js @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.foo = 1; +var main = require("../main"); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/two.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/two.js new file mode 100644 index 0000000..9765219 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/lib/two.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +// this ought to find our sibling, not packages/development-mode/lib/main.js +var main = require("main"); +exports.foo = 1; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/package.json new file mode 100644 index 0000000..edd2b17 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/one/package.json @@ -0,0 +1,4 @@ +{ "name": "one", + "id": "jid1@jetpack", + "main": "main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/data/text.data b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/data/text.data new file mode 100644 index 0000000..1269488 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/data/text.data @@ -0,0 +1 @@ +data diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/main.js new file mode 100644 index 0000000..b860821 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/main.js @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var self = require("self"); // trigger inclusion of data +exports.main = function () { console.log("main"); }; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/unused.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/unused.js new file mode 100644 index 0000000..a7b1c14 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/lib/unused.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.unused = "just pretend I'm not here"; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/package.json new file mode 100644 index 0000000..922c77d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/seven/package.json @@ -0,0 +1,4 @@ +{ + "name": "seven", + "id": "jid7" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/lib/unused.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/lib/unused.js new file mode 100644 index 0000000..ada31ef --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/lib/unused.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.unused = "I am."; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/package.json new file mode 100644 index 0000000..906b249 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/package.json @@ -0,0 +1,3 @@ +{ "name": "six", + "main": "./unreachable" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/unreachable.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/unreachable.js new file mode 100644 index 0000000..e8b229c --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/six/unreachable.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = "I am outside lib/ and cannot be reached, yet"; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/msg.txt b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/msg.txt new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/msg.txt @@ -0,0 +1 @@ +hello world diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/subdir/submsg.txt b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/subdir/submsg.txt new file mode 100644 index 0000000..d2cfe80 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/data/subdir/submsg.txt @@ -0,0 +1 @@ +hello subdir diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/main.js new file mode 100644 index 0000000..cee7380 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = 42; +require("./subdir/subfile"); +require("self"); // trigger inclusion of our data/ directory + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/subdir/subfile.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/subdir/subfile.js new file mode 100644 index 0000000..aec24d0 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/subdir/subfile.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = "I should be included in a subdir"; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/unused.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/unused.js new file mode 100644 index 0000000..36c4a4e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/lib/unused.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = "unused, linker should not include me in the XPI"; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/locale/fr-FR.properties b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/locale/fr-FR.properties new file mode 100644 index 0000000..980ac46 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/locale/fr-FR.properties @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Yes= Oui diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/package.json new file mode 100644 index 0000000..6b796fc --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-a/package.json @@ -0,0 +1,3 @@ +{ "name": "three-a", + "main": "./lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/lib/main.js new file mode 100644 index 0000000..7e1ce7e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/lib/main.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = 42; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/locale/fr-FR.properties b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/locale/fr-FR.properties new file mode 100644 index 0000000..c1bf146 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/locale/fr-FR.properties @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +No= Non +one= un diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/package.json new file mode 100644 index 0000000..c0ff5ee --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-b/package.json @@ -0,0 +1,3 @@ +{ "name": "three-b", + "main": "./lib/main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/main.js new file mode 100644 index 0000000..7e1ce7e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/main.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = 42; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/sub/foo.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/sub/foo.js new file mode 100644 index 0000000..5878496 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/lib/sub/foo.js @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.foo = "you found me down here"; + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/locale/fr-FR.properties b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/locale/fr-FR.properties new file mode 100644 index 0000000..dac3f13 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/locale/fr-FR.properties @@ -0,0 +1,9 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +No= Nein +What?= Quoi? +plural=other +plural[one]=one +uft8_value=é diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/package.json new file mode 100644 index 0000000..169c914 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three-deps/three-c/package.json @@ -0,0 +1,3 @@ +{ "name": "three-c", + "main": "lib/main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/lib/main.js new file mode 100644 index 0000000..4f59443 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var a = require("three-a"); +var b = require("three-b"); +var c = require("three-c"); +var c3 = require("three-c/sub/foo"); diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/package.json new file mode 100644 index 0000000..cbfbc5b --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/package.json @@ -0,0 +1,3 @@ +{ "name": "three", + "main": "main" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/nontest.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/nontest.js new file mode 100644 index 0000000..edbc08e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/nontest.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// dummy diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-one.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-one.js new file mode 100644 index 0000000..edbc08e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-one.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// dummy diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-two.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-two.js new file mode 100644 index 0000000..edbc08e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/linker-files/three/tests/test-two.js @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// dummy diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json new file mode 100644 index 0000000..f1d51b0 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json @@ -0,0 +1,6 @@ +{ + "id": "jid1-fZHqN9JfrDBa8A", + "fullName": "No Prefs Test", + "author": "Erik Vold", + "loader": "lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js new file mode 100644 index 0000000..b7e0a1d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json new file mode 100644 index 0000000..1b82728 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json @@ -0,0 +1,18 @@ +{ + "id": "jid1-fZHqN9JfrDBa8A", + "fullName": "Simple Prefs Test", + "author": "Erik Vold", + "preferences": [{ + "name": "test", + "type": "bool", + "title": "tëst", + "value": false + }, + { + "name": "test2", + "type": "string", + "title": "tëst", + "value": "ünicødé" + }], + "loader": "lib/main.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/index.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/index.md new file mode 100644 index 0000000..0f03259 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/index.md @@ -0,0 +1,7 @@ + + +# An Imposing Title # + +*Some words!* diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/no_h1.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/no_h1.md new file mode 100644 index 0000000..9859f33 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/dev-guide-source/no_h1.md @@ -0,0 +1,7 @@ + + +## A heading ## + +*Some words!* diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/another.html b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/another.html new file mode 100644 index 0000000..d40a2e8 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/another.html @@ -0,0 +1,5 @@ + + +another file \ No newline at end of file diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/base.html b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/base.html new file mode 100644 index 0000000..56c993d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/base.html @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+ + + +
+
+
+ + + + + + + + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/index.html b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/index.html new file mode 100644 index 0000000..1909a18 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/doc/static-files/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ + + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIreference.html b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIreference.html new file mode 100644 index 0000000..e302641 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIreference.html @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + Add-on SDK Documentation + + + + + + + + + + + + + +
+

APIsample

+
+ +

Title

+

Some text here

+

This text appears between the API blocks.

+

Wooo, more text.

+

Some more text here, at the end of the file.

+
+ +
+

API Reference

+ +
+

Classes

+ +
+

empty-class

+

This class contains nothing.

+
+ +
+

only-one-ctor

+

This class contains only one constructor.

+
+
Constructors
+ +
+
one-constructor(options)
+ +
+
+
[ options ]
+

An object-bag of goodies.

+
+ +
+ +
+ +
+ +
+ +
+

two-ctors

+

This class contains two constructors.

+
+
Constructors
+ +
+
one-constructor(options)
+

The first constructor.

+
+
+
[ options ]
+

An object-bag of goodies.

+
+ +
+ +
+ +
+
another-constructor(options)
+

The second constructor.

+
+
+
[ options ]
+

An object-bag of goodies.

+
+ +
+ +
+ +
+ +
+ +
+

ctor-and-method

+

This class contains one constructor and one method.

+
+
Constructors
+ +
+
one-constructor(options)
+

The first constructor.

+
+
+
[ options ]
+

An object-bag of goodies.

+
+ +
+ +
+ +
+ +
+
Methods
+ +
+
a-method(options)
+

Does things.

+
+
+
[ options ]
+

An argument.

+
+ +
+ +
+ +
+ +
+ +
+

ctor-method-prop-event

+

This class contains one constructor, one method, one property and an event.

+
+
Constructors
+ +
+
one-constructor(options)
+

The first constructor.

+
+
+
[ options ]
+

An object-bag of goodies.

+
+ +
+ +
+ +
+ +
+
Methods
+ +
+
a-method(options)
+

Does things.

+
+
+
[ options ]
+

An argument.

+
+ +
+ +
+ +
+ +
+
Properties
+ +
+
a-property : bool
+

Represents stuff.

+
+ +
+ +
+
Events
+ +
+
message
+

Event emitted when the content script sends a message to the add-on.

+
+
+
JSON
+

The message itself as a JSON-serialized object.

+
+ +
+ +
+ +
+ +
+ +
+ +
+

Functions

+ +
+

test(argOne, argTwo, argThree, options)

+

This is a function which does nothing in particular.

+
+
+
argOne : string
+

This is the first argument.

+
+ +
+
[ argTwo : bool ]
+

This is the second argument.

+
+ +
+
[ argThree = default : uri ]
+

This is the third and final argument. And this is + a test of the ability to do multiple lines of + text.

+
+ +
+
[ options ]
+

Options Bag

+
+
[ style : string ]
+

Some style information.

+
+ +
+
[ secondToLastOption = True : bool ]
+

The last property.

+
+ +
+
[ lastOption : uri ]
+

And this time we have + A multiline description + Written as haiku

+
+ +
+ +
+ +
Returns: object +
+ +
+ +
+

append(options)

+

This is a list of options to specify modifications to your slideBar instance.

+
+
+
options
+

Pass in all of your options here.

+
+
[ icon : uri ]
+

The HREF of an icon to show as the method of accessing your features slideBar

+
+ +
+
[ html : string/xml ]
+

The content of the feature, either as an HTML string, + or an E4X document fragment.

+
+ +
+
[ url : uri ]
+

The url to load into the content area of the feature

+
+ +
+
[ width : int ]
+

Width of the content area and the selected slide size

+
+ +
+
[ persist : bool ]
+

Default slide behavior when being selected as follows: + If true: blah; If false: double blah.

+
+ +
+
[ autoReload : bool ]
+

Automatically reload content on select

+
+ +
+
[ onClick : function ]
+

Callback when the icon is clicked

+
+ +
+
[ onSelect : function ]
+

Callback when the feature is selected

+
+ +
+
[ onReady : function ]
+

Callback when featured is loaded

+
+ +
+ +
+ +
+ +
+

cool-func.dot(howMuch, double, options, onemore, options2)

+ +
+
+
howMuch : string
+

How much cool it is.

+
+ +
+
[ double = true : bool ]
+

In case you just really need to double it.

+
+ +
+
[ options ]
+

An object-bag of goodies.

+
+
callback : function
+

The callback

+
+ +
+
[ random : bool ]
+

Do something random?

+
+ +
+ +
+
[ onemore : bool ]
+

One more paramater

+
+ +
+
[ options2 ]
+

This is a full description of something + that really sucks. Because I now have a multiline + description of this thingy.

+
+
monkey : string
+

You heard me right

+
+ +
+
[ freak = true : bool ]
+

Yes, you are a freak.

+
+ +
+ +
+ +
Returns: string

A value telling you just how cool you are. + A boa-constructor! + This description can go on for a while, and can even contain + some realy fancy things. Like code, or even + ~~~~{.javascript} + // Some code! + ~~~~

+
+ +
+ +
+

random()

+

A function that returns a random integer between 0 and 10.

+
Returns: int

The random number.

+
+ +
+ +
+ +
+

Events

+ +
+

open

+

A module-level event called open.

+
+
+
bool
+

Yes, it's open.

+
+ +
+ +
+ +
+ +
+ +
+ + + + + + + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIsample.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIsample.md new file mode 100644 index 0000000..c5090c3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/docs/APIsample.md @@ -0,0 +1,162 @@ + + +# Title # + +Some text here + + +@function +This is a function which does nothing in particular. +@returns {object} + @prop firststring {string} First string + @prop firsturl {url} First URL +@param argOne {string} This is the first argument. +@param [argTwo] {bool} This is the second argument. +@param [argThree=default] {uri} + This is the third and final argument. And this is + a test of the ability to do multiple lines of + text. +@param [options] Options Bag + @prop [style] {string} Some style information. + @prop [secondToLastOption=True] {bool} The last property. + @prop [lastOption] {uri} + And this time we have + A multiline description + Written as haiku + + +This text appears between the API blocks. + + +@function +This is a list of options to specify modifications to your slideBar instance. +@param options + Pass in all of your options here. + @prop [icon] {uri} The HREF of an icon to show as the method of accessing your features slideBar + @prop [html] {string/xml} + The content of the feature, either as an HTML string, + or an E4X document fragment. + @prop [url] {uri} The url to load into the content area of the feature + @prop [width] {int} Width of the content area and the selected slide size + @prop [persist] {bool} + Default slide behavior when being selected as follows: + If true: blah; If false: double blah. + @prop [autoReload] {bool} Automatically reload content on select + @prop [onClick] {function} Callback when the icon is clicked + @prop [onSelect] {function} Callback when the feature is selected + @prop [onReady] {function} Callback when featured is loaded + + +Wooo, more text. + + +@function +@returns {string} A value telling you just how cool you are. +A boa-constructor! +This description can go on for a while, and can even contain +some **realy** fancy things. Like `code`, or even +~~~~{.javascript} +// Some code! +~~~~ +@param howMuch {string} How much cool it is. +@param [double=true] {bool} + In case you just really need to double it. +@param [options] An object-bag of goodies. + @prop callback {function} The callback + @prop [random] {bool} Do something random? +@param [onemore] {bool} One more paramater +@param [options2] + This is a full description of something + that really sucks. Because I now have a multiline + description of this thingy. + @prop monkey {string} You heard me right + @prop [freak=true] {bool} + Yes, you are a freak. + + + +@function +A function that returns a random integer between 0 and 10. +@returns {int} The random number. + + + +@class +This class contains nothing. + + + +@class +This class contains only one constructor. + +@constructor +@param [options] An object-bag of goodies. + + + + +@class +This class contains two constructors. + +@constructor +The first constructor. +@param [options] An object-bag of goodies. + + +@constructor +The second constructor. +@param [options] An object-bag of goodies. + + + + +@class +This class contains one constructor and one method. + +@constructor +The first constructor. +@param [options] An object-bag of goodies. + + +@method +Does things. +@param [options] An argument. + + + + +@class +This class contains one constructor, one method, one property and an event. + +@constructor +The first constructor. +@param [options] An object-bag of goodies. + + +@method +Does things. +@param [options] An argument. + + +@property {bool} +Represents stuff. + + +@event +Event emitted when the content script sends a message to the add-on. +@argument {JSON} +The message itself as a JSON-serialized object. + + + + +@event +A module-level event called open. +@argument {bool} +Yes, it's open. + + +Some more text here, at the end of the file. + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/aardvark-feeder.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/aardvark-feeder.md new file mode 100644 index 0000000..3845955 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/aardvark-feeder.md @@ -0,0 +1,12 @@ + + +The `aardvark-feeder` module simplifies feeding aardvarks. + + +@function + Feed the aardvark. +@param food {string} + The food. Aardvarks will eat anything. + diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/main.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/doc/main.md new file mode 100644 index 0000000..e69de29 diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/ignore_me b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/ignore_me new file mode 100644 index 0000000..014242c --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/ignore_me @@ -0,0 +1,3 @@ +The docs processor should tolerate (by ignoring) random non-.js files in lib +directories, such as those left around by editors, version-control systems, +or OS metadata like .DS_Store . This file exercises that tolerance. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/main.js new file mode 100644 index 0000000..0264872 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = function(options, callbacks) { + console.log("1 + 1 =", require("bar-module").add(1, 1)); + callbacks.quit(); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/surprise.js/ignore_me_too b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/surprise.js/ignore_me_too new file mode 100644 index 0000000..066f9b5 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/lib/surprise.js/ignore_me_too @@ -0,0 +1,2 @@ +The docs processor should also ignore directories named *.js, and their +contents. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/package.json new file mode 100644 index 0000000..07eb9b9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/aardvark/package.json @@ -0,0 +1,7 @@ +{ + "author": "Jon Smith", + "description": "A package w/ a main module; can be built into an extension.", + "keywords": ["potato"], + "version": "1.0", + "dependencies": ["api-utils", "barbeque"] +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/lib/main.js new file mode 100644 index 0000000..0264872 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = function(options, callbacks) { + console.log("1 + 1 =", require("bar-module").add(1, 1)); + callbacks.quit(); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/package.json new file mode 100644 index 0000000..0e2b552 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/anteater_files/package.json @@ -0,0 +1,8 @@ +{ + "name": "anteater", + "author": "Jon Smith", + "description": "A package w/ a main module; can be built into an extension.", + "keywords": ["potato"], + "version": "1.0", + "dependencies": ["api-utils", "barbeque"] +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/lib/loader.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/lib/loader.js new file mode 100644 index 0000000..361846d --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/lib/loader.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This module will be imported by the XPCOM harness/boostrapper +// via Components.utils.import() and is responsible for creating a +// CommonJS module loader. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/package.json new file mode 100644 index 0000000..64eb065 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/api-utils/package.json @@ -0,0 +1,5 @@ +{ + "description": "A foundational package that provides a CommonJS module loader implementation.", + "keywords": ["potato", "jetpack-low-level"], + "loader": "lib/loader.js" +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/lib/bar-module.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/lib/bar-module.js new file mode 100644 index 0000000..ff982ae --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/lib/bar-module.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.add = function add(a, b) { + return a + b; +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/package.json new file mode 100644 index 0000000..62e3c12 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/barbeque/package.json @@ -0,0 +1,4 @@ +{ + "keywords": ["potato", "jetpack-low-level"], + "description": "A package used by 'aardvark' as a library." +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/docs/main.md b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/docs/main.md new file mode 100644 index 0000000..54518d3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/docs/main.md @@ -0,0 +1,5 @@ + + +minimal docs diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/lib/main.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/lib/main.js new file mode 100644 index 0000000..aeda0e7 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/lib/main.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +exports.main = function(options, callbacks) { + console.log("minimal"); + callbacks.quit(); +}; diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/package.json b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/package.json new file mode 100644 index 0000000..530f3c2 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/packages/minimal/package.json @@ -0,0 +1,4 @@ +{ + "author": "Jon Smith", + "description": "A package w/ a main module; can be built into an extension." +} diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/xpi-template/components/harness.js b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/xpi-template/components/harness.js new file mode 100644 index 0000000..a20bf3f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/static-files/xpi-template/components/harness.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains XPCOM code that bootstraps an SDK-based add-on +// by loading its harness-options.json, registering all its resource +// directories, executing its loader, and then executing its program's +// main() function. diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apiparser.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apiparser.py new file mode 100644 index 0000000..c24f5c3 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apiparser.py @@ -0,0 +1,538 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import os +import unittest +from cuddlefish.docs.apiparser import parse_hunks, ParseError + +tests_path = os.path.abspath(os.path.dirname(__file__)) +static_files_path = os.path.join(tests_path, "static-files") + +class ParserTests(unittest.TestCase): + def pathname(self, filename): + return os.path.join(static_files_path, "docs", filename) + + def parse_text(self, text): + return list(parse_hunks(text)) + + def parse(self, pathname): + return self.parse_text(open(pathname).read()) + + def test_parser(self): + parsed = self.parse(self.pathname("APIsample.md")) + #for i,h in enumerate(parsed): + # print i, h + self.assertEqual(parsed[0], + ("version", 4)) + self.assertEqual(parsed[1], + ("markdown", """\ + + +# Title # + +Some text here + +""")) + + self.assertEqual(parsed[2][0], "api-json") + p_test = parsed[2][1] + self.assertEqual(p_test["name"], "test") + self.assertEqual(p_test["type"], "function") + self.assertEqual(p_test["signature"], "test(argOne, argTwo, \ +argThree, options)") + self.assertEqual(p_test["description"], + "This is a function which does nothing in \ +particular.") + r = p_test["returns"] + self.assertEqual(r["datatype"], "object") + self.assertEqual(r["description"], "") + self.assertEqual(len(r["props"]), 2) + self.assertEqual(r["props"][0]["datatype"], "string") + self.assertEqual(r["props"][0]["description"], "First string") + self.assertEqual(r["props"][1]["datatype"], "url") + self.assertEqual(r["props"][1]["description"], "First URL") + + self.assertEqual(p_test["params"][0], + {"name": "argOne", + "required": True, + "datatype": "string", + "description": "This is the first argument.", + "line_number": 15, + }) + + self.assertEqual(p_test["params"][1], + {"name": "argTwo", + "required": False, + "datatype": "bool", + "description": "This is the second argument.", + "line_number": 16, + }) + + self.assertEqual(p_test["params"][2], + {"name": "argThree", + "required": False, + "default": "default", + "datatype": "uri", + "line_number": 17, + "description": """\ +This is the third and final argument. And this is +a test of the ability to do multiple lines of +text.""", + }) + p3 = p_test["params"][3] + self.assertEqual(p3["name"], "options") + self.assertEqual(p3["required"], False) + self.failIf("type" in p3) + self.assertEqual(p3["description"], "Options Bag") + self.assertEqual(p3["props"][0], + {"name": "style", + "required": False, + "datatype": "string", + "description": "Some style information.", + "line_number": 22, + }) + self.assertEqual(p3["props"][1], + {"name": "secondToLastOption", + "required": False, + "default": "True", + "datatype": "bool", + "description": "The last property.", + "line_number": 23, + }) + self.assertEqual(p3["props"][2]["name"], "lastOption") + self.assertEqual(p3["props"][2]["required"], False) + self.assertEqual(p3["props"][2]["datatype"], "uri") + self.assertEqual(p3["props"][2]["description"], """\ +And this time we have +A multiline description +Written as haiku""") + + self.assertEqual(parsed[3][0], "markdown") + self.assertEqual(parsed[3][1], "\n\nThis text appears between the \ +API blocks.\n\n") + + self.assertEqual(parsed[4][0], "api-json") + p_test = parsed[4][1] + + expected = {'line_number': 32, + 'name': 'append', + 'params': [{'props':[{'line_number': 37, + 'required': False, + 'datatype': 'uri', + 'name': 'icon', + 'description': 'The HREF of an icon to show as the \ +method of accessing your features slideBar'}, + {'line_number': 38, + 'required': False, + 'datatype': 'string/xml', + 'name': 'html', + 'description': 'The content of the feature, either \ +as an HTML string,\nor an E4X document fragment.'}, + {'line_number': 41, + 'required': False, + 'datatype': 'uri', + 'name': 'url', + 'description': 'The url to load into the content area \ +of the feature'}, + {'line_number': 42, + 'required': False, + 'datatype': 'int', + 'name': 'width', + 'description': 'Width of the content area and the \ +selected slide size'}, + {'line_number': 43, + 'required': False, + 'datatype': 'bool', + 'name': 'persist', + 'description': 'Default slide behavior when being \ +selected as follows:\nIf true: blah; If false: double blah.'}, + {'line_number': 46, + 'required': False, + 'datatype': 'bool', + 'name': 'autoReload', + 'description': 'Automatically reload content on \ +select'}, + {'line_number': 47, + 'required': False, + 'datatype': 'function', + 'name': 'onClick', + 'description': 'Callback when the icon is \ +clicked'}, + {'line_number': 48, + 'required': False, + 'datatype': 'function', + 'name': 'onSelect', + 'description': 'Callback when the feature is selected'}, + {'line_number': 49, + 'required': False, + 'datatype': 'function', + 'name': 'onReady', + 'description': + 'Callback when featured is loaded'}], + 'line_number': 35, + 'required': True, + 'name': 'options', + 'description': 'Pass in all of your options here.'}], + 'signature': 'append(options)', + 'type': 'function', + 'description': 'This is a list of options to specify modifications to your \ +slideBar instance.'} + self.assertEqual(p_test, expected) + + self.assertEqual(parsed[6][0], "api-json") + p_test = parsed[6][1] + self.assertEqual(p_test["name"], "cool-func.dot") + self.assertEqual(p_test["signature"], "cool-func.dot(howMuch, double, \ +options, onemore, options2)") + self.assertEqual(p_test["returns"]["description"], + """\ +A value telling you just how cool you are. +A boa-constructor! +This description can go on for a while, and can even contain +some **realy** fancy things. Like `code`, or even +~~~~{.javascript} +// Some code! +~~~~""") + self.assertEqual(p_test["params"][2]["props"][0], + {"name": "callback", + "required": True, + "datatype": "function", + "line_number": 67, + "description": "The callback", + }) + self.assertEqual(p_test["params"][2]["props"][1], + {"name": "random", + "required": False, + "datatype": "bool", + "line_number": 68, + "description": "Do something random?", + }) + + p_test = parsed[8][1] + self.assertEqual(p_test["signature"],"random()") + + # tests for classes + #1) empty class + p_test = parsed[10][1] + self.assertEqual(len(p_test), 4) + self.assertEqual(p_test["name"], "empty-class") + self.assertEqual(p_test["description"], "This class contains nothing.") + self.assertEqual(p_test["type"], "class") + # 2) class with just one ctor + p_test = parsed[12][1] + self.assertEqual(len(p_test), 5) + self.assertEqual(p_test["name"], "only-one-ctor") + self.assertEqual(p_test["description"], "This class contains only \ +one constructor.") + self.assertEqual(p_test["type"], "class") + constructors = p_test["constructors"] + self.assertEqual(len(constructors), 1) + self._test_class_constructor(constructors[0], "one-constructor") + # 3) class with 2 ctors + p_test = parsed[14][1] + self.assertEqual(len(p_test), 5) + self.assertEqual(p_test["name"], "two-ctors") + self.assertEqual(p_test["description"], "This class contains two \ +constructors.") + self.assertEqual(p_test["type"], "class") + constructors = p_test["constructors"] + self.assertEqual(len(constructors), 2) + self._test_class_constructor(constructors[0], "one-constructor") + self._test_class_constructor(constructors[1], "another-constructor") + # 4) class with ctor + method + p_test = parsed[16][1] + self.assertEqual(len(p_test), 6) + self.assertEqual(p_test["name"], "ctor-and-method") + self.assertEqual(p_test["description"], "This class contains one \ +constructor and one method.") + self.assertEqual(p_test["type"], "class") + constructors = p_test["constructors"] + self.assertEqual(len(constructors), 1) + self._test_class_constructor(constructors[0], "one-constructor") + methods = p_test["methods"] + self.assertEqual(len(methods), 1) + self._test_class_method(methods[0]) + # 5) class with ctor + method + property + p_test = parsed[18][1] + self.assertEqual(len(p_test), 8) + self.assertEqual(p_test["name"], "ctor-method-prop-event") + self.assertEqual(p_test["description"], "This class contains one \ +constructor, one method, one property and an event.") + self.assertEqual(p_test["type"], "class") + constructors = p_test["constructors"] + self.assertEqual(len(constructors), 1) + self._test_class_constructor(constructors[0], "one-constructor") + methods = p_test["methods"] + self.assertEqual(len(methods), 1) + self._test_class_method(methods[0]) + properties = p_test["properties"] + self.assertEqual(len(properties), 1) + self._test_class_property(properties[0]) + events = p_test["events"] + self.assertEqual(len(events), 1) + self._test_class_event(events[0]) + + self.assertEqual(parsed[-1][0], "markdown") + self.assertEqual(parsed[-1][1], "\n\nSome more text here, \ +at the end of the file.\n\n") + + def _test_class_constructor(self, constructor, name): + self.assertEqual(constructor["type"], "constructor") + self.assertEqual(constructor["name"], name) + params = constructor["params"] + self.assertEqual(len(params), 1) + self.assertEqual(params[0]["name"], "options") + self.assertEqual(params[0]["description"], "An object-bag of goodies.") + + def _test_class_method(self, method): + self.assertEqual(method["type"], "method") + self.assertEqual(method["name"], "a-method") + self.assertEqual(method["description"], "Does things.") + params = method["params"] + self.assertEqual(len(params), 1) + self.assertEqual(params[0]["name"], "options") + self.assertEqual(params[0]["description"], "An argument.") + + def _test_class_property(self, prop): + self.assertEqual(prop["type"], "property") + self.assertEqual(prop["name"], "a-property") + self.assertEqual(prop["description"], "Represents stuff.") + self.assertEqual(prop["datatype"], "bool") + + def _test_class_event(self, event): + self.assertEqual(event["type"], "event") + self.assertEqual(event["name"], "message") + self.assertEqual(event["description"], "Event emitted when the \ +content script sends a message to the add-on.") + arguments = event["arguments"] + self.assertEqual(len(arguments), 1) + argument = arguments[0] + self.assertEqual(argument["datatype"], "JSON") + self.assertEqual(argument["description"], "The message itself as a \ +JSON-serialized object.") + + def test_missing_return_propname(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns {object} + @prop {string} First string, but the property name is missing + @prop {url} First URL, same problem +@param argOne {string} This is the first argument. + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_missing_return_proptype(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns {object} + @prop untyped It is an error to omit the type of a return property. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_return_propnames(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns {object} + @prop firststring {string} First string. + @prop [firsturl] {url} First URL, not always provided. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + parsed = self.parse_text(md) + r = parsed[1][1]["returns"] + self.assertEqual(r["props"][0]["name"], "firststring") + self.assertEqual(r["props"][0], + {"name": "firststring", + "datatype": "string", + "description": "First string.", + "required": True, + "line_number": 5, # 1-indexed + }) + self.assertEqual(r["props"][1], + {"name": "firsturl", + "datatype": "url", + "description": "First URL, not always provided.", + "required": False, + "line_number": 6, + }) + + def test_return_description_1(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns {object} A one-line description. + @prop firststring {string} First string. + @prop [firsturl] {url} First URL, not always provided. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + parsed = self.parse_text(md) + r = parsed[1][1]["returns"] + self.assertEqual(r["description"], "A one-line description.") + + def test_return_description_2(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns {object} A six-line description + which is consistently indented by two spaces + except for this line + and preserves the following empty line + + from which a two-space indentation will be removed. + @prop firststring {string} First string. + @prop [firsturl] {url} First URL, not always provided. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + parsed = self.parse_text(md) + r = parsed[1][1]["returns"] + self.assertEqual(r["description"], + "A six-line description\n" + "which is consistently indented by two spaces\n" + " except for this line\n" + "and preserves the following empty line\n" + "\n" + "from which a two-space indentation will be removed.") + + def test_return_description_3(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns A one-line untyped description. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + parsed = self.parse_text(md) + r = parsed[1][1]["returns"] + self.assertEqual(r["description"], "A one-line untyped description.") + + # if the return value was supposed to be an array, the correct syntax + # would not have any @prop tags: + # @returns {array} + # Array consists of two elements, a string and a url... + + def test_return_array(self): + md = '''\ + +@method +This is a function which returns an array. +@returns {array} + Array consists of two elements, a string and a url. +@param argOne {string} This is the first argument. +@param [argTwo=True] {bool} This is the second argument. + +''' + parsed = self.parse_text(md) + r = parsed[1][1]["returns"] + self.assertEqual(r["description"], + "Array consists of two elements, a string and a url.") + + def test_bad_default_on_required_parameter(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@returns something +@param argOne=ILLEGAL {string} Mandatory parameters do not take defaults. +@param [argTwo=Chicago] {string} This is the second argument. + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_missing_apitype(self): + md = '''\ + +Sorry, you must have a @method or something before the description. +Putting it after the description is not good enough +@method +@returns something + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_missing_param_propname(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@param p1 {object} This is a parameter. + @prop {string} Oops, props must have a name. + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_missing_param_proptype(self): + md = '''\ + +@method +This is a function which does nothing in particular. +@param p1 {object} This is a parameter. + @prop name Oops, props must have a type. + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_property(self): + md = '''\ + +@property {foo} +An object property named test of type foo. + +''' + parsed = self.parse_text(md) + self.assertEqual(parsed[1][0], 'api-json') + actual_api_json_obj = parsed[1][1] + expected_api_json_obj = { + 'line_number': 1, + 'datatype': 'foo', + 'type': 'property', + 'name': 'test', + 'description': "An object property named test of type foo." + } + self.assertEqual(actual_api_json_obj, expected_api_json_obj) + + def test_property_no_type(self): + md = '''\ + +@property +This property needs to specify a type! + +''' + self.assertRaises(ParseError, self.parse_text, md) + + def test_missing_api_closing_tag(self): + md = '''\ + +@class +This is a class with a missing closing tag. + +''' + self.assertRaises(ParseError, self.parse_text, md) + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apirenderer.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apirenderer.py new file mode 100644 index 0000000..24a1c7c --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_apirenderer.py @@ -0,0 +1,31 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import os +import unittest +from cuddlefish.docs.apirenderer import md_to_html + +tests_path = os.path.abspath(os.path.dirname(__file__)) +static_files_path = os.path.join(tests_path, "static-files") + +class ParserTests(unittest.TestCase): + def pathname(self, filename): + return os.path.join(static_files_path, "docs", filename) + + def render_markdown(self, pathname): + return md_to_html(pathname) + + def test_renderer(self): + test = self.render_markdown(self.pathname("APIsample.md")) + reference = open(self.pathname("APIreference.html")).read() + test_lines = test.splitlines(True) + reference_lines = reference.splitlines(True) + for x in range(len(test_lines)): + self.assertEqual(test_lines[x], reference_lines[x], + "line %d: expected '%s', got '%s'" + % (x+1, reference_lines[x], test_lines[x])) + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_generate.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_generate.py new file mode 100644 index 0000000..ce5665e --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_generate.py @@ -0,0 +1,173 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import shutil +import unittest +import StringIO +import tarfile +import HTMLParser +import urlparse +import urllib + +from cuddlefish.docs import generate +from cuddlefish.tests import env_root + +INITIAL_FILESET = [ ["static-files", "base.html"], \ + ["dev-guide", "index.html"], \ + ["packages", "aardvark", "index.html"] ] + +EXTENDED_FILESET = [ ["static-files", "base.html"], \ + ["dev-guide", "extra.html"], \ + ["dev-guide", "index.html"], \ + ["packages", "aardvark", "index.html"] ] + +EXTRAFILE = ["dev-guide", "extra.html"] + +def get_test_root(): + return os.path.join(env_root, "python-lib", "cuddlefish", "tests", "static-files") + +def get_sdk_docs_root(): + return os.path.join(get_test_root(), "sdk-docs") + +def get_base_url_path(): + return os.path.join(get_sdk_docs_root(), "doc") + +def url_from_path(path): + path = path.lstrip("/") + return "file://"+"/"+"/".join(path.split(os.sep))+"/" + +def get_base_url(): + return url_from_path(get_base_url_path()) + +class Link_Checker(HTMLParser.HTMLParser): + def __init__(self, tester, filename, base_url): + HTMLParser.HTMLParser.__init__(self) + self.tester = tester + self.filename = filename + self.base_url = base_url + self.errors = [] + + def handle_starttag(self, tag, attrs): + link = self.find_link(attrs) + if link: + self.validate_link(link) + + def handle_startendtag(self, tag, attrs): + link = self.find_link(attrs) + if link: + self.validate_link(link) + + def find_link(self, attrs): + attrs = dict(attrs) + href = attrs.get('href', '') + if href: + parsed = urlparse.urlparse(href) + if not parsed.scheme: + return href + src = attrs.get('src', '') + if src: + parsed = urlparse.urlparse(src) + if not parsed.scheme: + return src + + def validate_link(self, link): + parsed = urlparse.urlparse(link) + # there should not be any file:// URLs + self.tester.assertNotEqual(parsed.scheme, "file") + # any other absolute URLs will not be checked + if parsed.scheme: + return + current_path_as_url = url_from_path(os.path.dirname(self.filename)) + # otherwise try to open the file at: baseurl + path + absolute_url = current_path_as_url + parsed.path + try: + urllib.urlopen(absolute_url) + except IOError: + self.errors.append(self.filename + "\n " + absolute_url) + +class Generate_Docs_Tests(unittest.TestCase): + + def test_generate_static_docs(self): + # make sure we start clean + if os.path.exists(get_base_url_path()): + shutil.rmtree(get_base_url_path()) + # generate a doc tarball, and extract it + base_url = get_base_url() + tar_filename = generate.generate_static_docs(env_root) + tgz = tarfile.open(tar_filename) + tgz.extractall(get_sdk_docs_root()) + broken_links = [] + # get each HTML file... + for root, subFolders, filenames in os.walk(get_sdk_docs_root()): + for filename in filenames: + if not filename.endswith(".html"): + continue + if root.endswith("static-files"): + continue + filename = os.path.join(root, filename) + # ...and feed it to the link checker + linkChecker = Link_Checker(self, filename, base_url) + linkChecker.feed(open(filename, "r").read()) + broken_links.extend(linkChecker.errors) + if broken_links: + print + print "The following links are broken:" + for broken_link in sorted(broken_links): + print " "+ broken_link + self.fail("%d links are broken" % len(broken_links)) + # clean up + shutil.rmtree(get_base_url_path()) + tgz.close() + os.remove(tar_filename) + generate.clean_generated_docs(os.path.join(env_root, "doc")) + + def test_generate_docs(self): + test_root = get_test_root() + docs_root = os.path.join(test_root, "doc") + generate.clean_generated_docs(docs_root) + new_digest = self.check_generate_regenerate_cycle(test_root, INITIAL_FILESET) + # touching an MD file under packages **does** cause a regenerate + os.utime(os.path.join(test_root, "packages", "aardvark", "doc", "main.md"), None) + new_digest = self.check_generate_regenerate_cycle(test_root, INITIAL_FILESET, new_digest) + # touching a non MD file under packages **does not** cause a regenerate + os.utime(os.path.join(test_root, "packages", "aardvark", "lib", "main.js"), None) + self.check_generate_is_skipped(test_root, INITIAL_FILESET, new_digest) + # touching a non MD file under static-files **does not** cause a regenerate + os.utime(os.path.join(docs_root, "static-files", "another.html"), None) + new_digest = self.check_generate_is_skipped(test_root, INITIAL_FILESET, new_digest) + # touching an MD file under dev-guide **does** cause a regenerate + os.utime(os.path.join(docs_root, "dev-guide-source", "index.md"), None) + new_digest = self.check_generate_regenerate_cycle(test_root, INITIAL_FILESET, new_digest) + # adding a file **does** cause a regenerate + open(os.path.join(docs_root, "dev-guide-source", "extra.md"), "w").write("some content") + new_digest = self.check_generate_regenerate_cycle(test_root, EXTENDED_FILESET, new_digest) + # deleting a file **does** cause a regenerate + os.remove(os.path.join(docs_root, "dev-guide-source", "extra.md")) + new_digest = self.check_generate_regenerate_cycle(test_root, INITIAL_FILESET, new_digest) + # remove the files + generate.clean_generated_docs(docs_root) + + def check_generate_is_skipped(self, test_root, files_to_expect, initial_digest): + generate.generate_docs(test_root, stdout=StringIO.StringIO()) + docs_root = os.path.join(test_root, "doc") + for file_to_expect in files_to_expect: + self.assertTrue(os.path.exists(os.path.join(docs_root, *file_to_expect))) + self.assertTrue(initial_digest == open(os.path.join(docs_root, "status.md5"), "r").read()) + + def check_generate_regenerate_cycle(self, test_root, files_to_expect, initial_digest = None): + # test that if we generate, files are getting generated + generate.generate_docs(test_root, stdout=StringIO.StringIO()) + docs_root = os.path.join(test_root, "doc") + for file_to_expect in files_to_expect: + self.assertTrue(os.path.exists(os.path.join(docs_root, *file_to_expect)), os.path.join(docs_root, *file_to_expect) + "not found") + if initial_digest: + self.assertTrue(initial_digest != open(os.path.join(docs_root, "status.md5"), "r").read()) + # and that if we regenerate, nothing changes... + new_digest = open(os.path.join(docs_root, "status.md5"), "r").read() + self.check_generate_is_skipped(test_root, files_to_expect, new_digest) + return new_digest + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_init.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_init.py new file mode 100644 index 0000000..33c0059 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_init.py @@ -0,0 +1,148 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os, unittest, shutil +from StringIO import StringIO +from cuddlefish import initializer +from cuddlefish.templates import MAIN_JS, TEST_MAIN_JS, PACKAGE_JSON + +tests_path = os.path.abspath(os.path.dirname(__file__)) + +class TestInit(unittest.TestCase): + + def run_init_in_subdir(self, dirname, f, *args, **kwargs): + top = os.path.abspath(os.getcwd()) + basedir = os.path.abspath(os.path.join(".test_tmp",self.id(),dirname)) + if os.path.isdir(basedir): + assert basedir.startswith(top) + shutil.rmtree(basedir) + os.makedirs(basedir) + try: + os.chdir(basedir) + return f(basedir, *args, **kwargs) + finally: + os.chdir(top) + + def do_test_init(self,basedir): + # Let's init the addon, no error admited + f = open(".ignoreme","w") + f.write("stuff") + f.close() + + out, err = StringIO(), StringIO() + init_run = initializer(None, ["init"], out, err) + out, err = out.getvalue(), err.getvalue() + self.assertEqual(init_run, 0) + self.assertTrue("* lib directory created" in out) + self.assertTrue("* data directory created" in out) + self.assertTrue("Have fun!" in out) + self.assertEqual(err,"") + self.assertTrue(len(os.listdir(basedir))>0) + main_js = os.path.join(basedir,"lib","main.js") + package_json = os.path.join(basedir,"package.json") + test_main_js = os.path.join(basedir,"test","test-main.js") + self.assertTrue(os.path.exists(main_js)) + self.assertTrue(os.path.exists(package_json)) + self.assertTrue(os.path.exists(test_main_js)) + self.assertEqual(open(main_js,"r").read(),MAIN_JS) + self.assertEqual(open(package_json,"r").read(), + PACKAGE_JSON % {"name":"tmp_addon_sample", + "fullName": "tmp_addon_SAMPLE" }) + self.assertEqual(open(test_main_js,"r").read(),TEST_MAIN_JS) + + # Let's check that the addon is initialized + out, err = StringIO(), StringIO() + init_run = initializer(None, ["init"], out, err) + out, err = out.getvalue(), err.getvalue() + self.failIfEqual(init_run,0) + self.assertTrue("This command must be run in an empty directory." in err) + + def test_initializer(self): + self.run_init_in_subdir("tmp_addon_SAMPLE",self.do_test_init) + + def do_test_args(self, basedir): + # check that running it with spurious arguments will fail + out,err = StringIO(), StringIO() + init_run = initializer(None, ["init", "ignored-dirname"], out, err) + out, err = out.getvalue(), err.getvalue() + self.failIfEqual(init_run, 0) + self.assertTrue("Too many arguments" in err) + + def test_args(self): + self.run_init_in_subdir("tmp_addon_sample", self.do_test_args) + + def _test_existing_files(self, basedir): + f = open("pay_attention_to_me","w") + f.write("stuff") + f.close() + out,err = StringIO(), StringIO() + rc = initializer(None, ["init"], out, err) + out, err = out.getvalue(), err.getvalue() + self.assertEqual(rc, 1) + self.failUnless("This command must be run in an empty directory" in err, + err) + self.failIf(os.path.exists("lib")) + + def test_existing_files(self): + self.run_init_in_subdir("existing_files", self._test_existing_files) + + + +class TestCfxQuits(unittest.TestCase): + + def run_cfx(self, addon_name, command): + old_cwd = os.getcwd() + addon_path = os.path.join(tests_path, + "addons", addon_name) + os.chdir(addon_path) + import sys + old_stdout = sys.stdout + old_stderr = sys.stderr + sys.stdout = out = StringIO() + sys.stderr = err = StringIO() + try: + import cuddlefish + args = list(command) + # Pass arguments given to cfx so that cfx can find firefox path + # if --binary option is given: + args.extend(sys.argv[1:]) + cuddlefish.run(arguments=args) + except SystemExit, e: + if "code" in e: + rc = e.code + elif "args" in e and len(e.args)>0: + rc = e.args[0] + else: + rc = 0 + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + os.chdir(old_cwd) + out.flush() + err.flush() + return rc, out.getvalue(), err.getvalue() + + # this method doesn't exists in python 2.5, + # implements our own + def assertIn(self, member, container): + """Just like self.assertTrue(a in b), but with a nicer default message.""" + if member not in container: + standardMsg = '"%s" not found in "%s"' % (member, + container) + self.fail(standardMsg) + + def test_run(self): + rc, out, err = self.run_cfx("simplest-test", ["run"]) + self.assertEqual(rc, 0) + self.assertIn("Program terminated successfully.", err) + + def test_test(self): + rc, out, err = self.run_cfx("simplest-test", ["test"]) + self.assertEqual(rc, 0) + self.assertIn("1 of 1 tests passed.", err) + self.assertIn("Program terminated successfully.", err) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_licenses.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_licenses.py new file mode 100644 index 0000000..60b5957 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_licenses.py @@ -0,0 +1,88 @@ + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest +import os.path + +parent = os.path.dirname +test_dir = parent(os.path.abspath(__file__)) +sdk_root = parent(parent(parent(test_dir))) + +def from_sdk_top(fn): + return os.path.abspath(os.path.join(sdk_root, fn)) + +MPL2_URL = "http://mozilla.org/MPL/2.0/" + +# These files all come with their own license headers +skip = [ + "python-lib/cuddlefish/_version.py", # generated, public domain + "doc/static-files/js/jquery.js", # MIT/GPL dual + "examples/annotator/data/jquery-1.4.2.min.js", # MIT/GPL dual + "examples/reddit-panel/data/jquery-1.4.4.min.js", # MIT/GPL dual + "examples/library-detector/data/library-detector.js", # MIT + "python-lib/mozrunner/killableprocess.py", # MIT? BSDish? + "python-lib/mozrunner/winprocess.py", # MIT + "packages/api-utils/tests/test-querystring.js", # MIT + "packages/api-utils/lib/promise.js", # MIT + "packages/api-utils/tests/test-promise.js", # MIT + ] +absskip = [from_sdk_top(os.path.join(*fn.split("/"))) for fn in skip] + +class Licenses(unittest.TestCase): + def test(self): + # Examine most SDK files to check if they've got an MPL2 license + # header. We exclude some files that are known to include different + # licenses. + self.missing = [] + self.scan_file(from_sdk_top(os.path.join("python-lib", "jetpack_sdk_env.py"))) + self.scan(os.path.join("python-lib", "cuddlefish"), [".js", ".py"], + skipdirs=["sdk-docs"], # test_generate.py makes this + ) + self.scan(os.path.join("python-lib", "mozrunner"), [".py"]) + + for sdk_package in ["addon-kit", "api-utils", "test-harness"]: + self.scan(os.path.join("packages", sdk_package), + [".js", ".py", ".md"]) + self.scan("examples", [".js", ".css", ".html", ".md"]) + self.scan("bin", [".bat", ".ps1"]) + for fn in [os.path.join("bin", "activate"), + os.path.join("bin", "cfx"), + os.path.join("bin", "integration-scripts", "buildbot-run-cfx-helper"), + os.path.join("bin", "integration-scripts", "integration-check"), + ]: + self.scan_file(from_sdk_top(fn)) + self.scan("doc", [".js", ".css", ".md"], skipdirs=["syntaxhighlighter"]) + + if self.missing: + print + print "The following files are missing an MPL2 header:" + for fn in sorted(self.missing): + print " "+fn + self.fail("%d files are missing an MPL2 header" % len(self.missing)) + + def scan(self, start, extensions=[], skipdirs=[]): + # scan a whole subdirectory + start = from_sdk_top(start) + for root, dirs, files in os.walk(start): + for d in skipdirs: + if d in dirs: + dirs.remove(d) + for fn in files: + ext = os.path.splitext(fn)[1] + if extensions and ext not in extensions: + continue + absfn = os.path.join(root, fn) + if absfn in absskip: + continue + self.scan_file(absfn) + + def scan_file(self, fn): + # scan a single file + if not MPL2_URL in open(fn, "r").read(): + relfile = fn[len(sdk_root)+1:] + self.missing.append(relfile) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_linker.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_linker.py new file mode 100755 index 0000000..84f6a09 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_linker.py @@ -0,0 +1,234 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os.path +import shutil +import zipfile +from StringIO import StringIO +import simplejson as json +import unittest +import cuddlefish +from cuddlefish import packaging, manifest + +def up(path, generations=1): + for i in range(generations): + path = os.path.dirname(path) + return path + +ROOT = up(os.path.abspath(__file__), 4) +def get_linker_files_dir(name): + return os.path.join(up(os.path.abspath(__file__)), "linker-files", name) + +class Basic(unittest.TestCase): + def get_pkg(self, name): + d = get_linker_files_dir(name) + return packaging.get_config_in_dir(d) + + def test_deps(self): + target_cfg = self.get_pkg("one") + pkg_cfg = packaging.build_config(ROOT, target_cfg) + deps = packaging.get_deps_for_targets(pkg_cfg, ["one"]) + self.failUnlessEqual(deps, ["one"]) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "one"]) + + def test_manifest(self): + target_cfg = self.get_pkg("one") + pkg_cfg = packaging.build_config(ROOT, target_cfg) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "one"]) + # target_cfg.dependencies is not provided, so we'll search through + # all known packages (everything in 'deps'). + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False) + m = m.get_harness_options_manifest() + + def assertReqIs(modname, reqname, path): + reqs = m["one/lib/%s.js" % modname]["requirements"] + self.failUnlessEqual(reqs[reqname]["path"], path) + assertReqIs("main", "panel", "addon-kit/lib/panel.js") + assertReqIs("main", "two.js", "one/lib/two.js") + assertReqIs("main", "./two", "one/lib/two.js") + assertReqIs("main", "addon-kit/tabs.js", "addon-kit/lib/tabs.js") + assertReqIs("main", "./subdir/three", "one/lib/subdir/three.js") + assertReqIs("two", "main", "one/lib/main.js") + assertReqIs("subdir/three", "../main", "one/lib/main.js") + + target_cfg.dependencies = [] + # now, because .dependencies *is* provided, we won't search 'deps', + # so we'll get a link error + self.assertRaises(manifest.ModuleNotFoundError, + manifest.build_manifest, + target_cfg, pkg_cfg, deps, scan_tests=False) + + def test_main_in_deps(self): + target_cfg = self.get_pkg("three") + package_path = [get_linker_files_dir("three-deps")] + pkg_cfg = packaging.build_config(ROOT, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "three"]) + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False) + m = m.get_harness_options_manifest() + def assertReqIs(modname, reqname, path): + reqs = m["three/lib/%s.js" % modname]["requirements"] + self.failUnlessEqual(reqs[reqname]["path"], path) + assertReqIs("main", "three-a", "three-a/lib/main.js") + assertReqIs("main", "three-b", "three-b/lib/main.js") + assertReqIs("main", "three-c", "three-c/lib/main.js") + + def test_relative_main_in_top(self): + target_cfg = self.get_pkg("five") + package_path = [] + pkg_cfg = packaging.build_config(ROOT, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "five"]) + # all we care about is that this next call doesn't raise an exception + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False) + m = m.get_harness_options_manifest() + reqs = m["five/lib/main.js"]["requirements"] + self.failUnlessEqual(reqs, {}); + + def test_unreachable_relative_main_in_top(self): + target_cfg = self.get_pkg("six") + package_path = [] + pkg_cfg = packaging.build_config(ROOT, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "six"]) + self.assertRaises(manifest.UnreachablePrefixError, + manifest.build_manifest, + target_cfg, pkg_cfg, deps, scan_tests=False) + + def test_unreachable_in_deps(self): + target_cfg = self.get_pkg("four") + package_path = [get_linker_files_dir("four-deps")] + pkg_cfg = packaging.build_config(ROOT, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + self.failUnlessEqual(deps, ["addon-kit", "api-utils", "four"]) + self.assertRaises(manifest.UnreachablePrefixError, + manifest.build_manifest, + target_cfg, pkg_cfg, deps, scan_tests=False) + +class Contents(unittest.TestCase): + + def run_in_subdir(self, dirname, f, *args, **kwargs): + top = os.path.abspath(os.getcwd()) + basedir = os.path.abspath(os.path.join(".test_tmp",self.id(),dirname)) + if os.path.isdir(basedir): + assert basedir.startswith(top) + shutil.rmtree(basedir) + os.makedirs(basedir) + try: + os.chdir(basedir) + return f(basedir, *args, **kwargs) + finally: + os.chdir(top) + + def assertIn(self, what, inside_what): + self.failUnless(what in inside_what, inside_what) + + def test_jetpackID(self): + # this uses "id": "jid7", to which a @jetpack should be appended + seven = get_linker_files_dir("seven") + def _test(basedir): + stdout = StringIO() + shutil.copytree(seven, "seven") + os.chdir("seven") + try: + # regrettably, run() always finishes with sys.exit() + cuddlefish.run(["xpi", "--no-strip-xpi"], + stdout=stdout) + except SystemExit, e: + self.failUnlessEqual(e.args[0], 0) + zf = zipfile.ZipFile("seven.xpi", "r") + hopts = json.loads(zf.read("harness-options.json")) + self.failUnlessEqual(hopts["jetpackID"], "jid7@jetpack") + self.run_in_subdir("x", _test) + + def test_jetpackID_suffix(self): + # this uses "id": "jid1@jetpack", so no suffix should be appended + one = get_linker_files_dir("one") + def _test(basedir): + stdout = StringIO() + shutil.copytree(one, "one") + os.chdir("one") + try: + # regrettably, run() always finishes with sys.exit() + cuddlefish.run(["xpi", "--no-strip-xpi"], + stdout=stdout) + except SystemExit, e: + self.failUnlessEqual(e.args[0], 0) + zf = zipfile.ZipFile("one.xpi", "r") + hopts = json.loads(zf.read("harness-options.json")) + self.failUnlessEqual(hopts["jetpackID"], "jid1@jetpack") + self.run_in_subdir("x", _test) + + def test_strip_default(self): + seven = get_linker_files_dir("seven") + # now run 'cfx xpi' in that directory, except put the generated .xpi + # elsewhere + def _test(basedir): + stdout = StringIO() + shutil.copytree(seven, "seven") + os.chdir("seven") + try: + # regrettably, run() always finishes with sys.exit() + cuddlefish.run(["xpi"], # --strip-xpi is now the default + stdout=stdout) + except SystemExit, e: + self.failUnlessEqual(e.args[0], 0) + zf = zipfile.ZipFile("seven.xpi", "r") + names = zf.namelist() + # the first problem found in bug 664840 was that cuddlefish.js + # (the loader) was stripped out on windows, due to a /-vs-\ bug + self.assertIn("resources/api-utils/lib/cuddlefish.js", names) + # the second problem found in bug 664840 was that an addon + # without an explicit tests/ directory would copy all files from + # the package into a bogus JID-PKGNAME-tests/ directory, so check + # for that + testfiles = [fn for fn in names if "seven/tests" in fn] + self.failUnlessEqual([], testfiles) + # the third problem was that data files were being stripped from + # the XPI. Note that data/ is only supposed to be included if a + # module that actually gets used does a require("self") . + self.assertIn("resources/seven/data/text.data", + names) + self.failIf("seven/lib/unused.js" + in names, names) + self.run_in_subdir("x", _test) + + def test_no_strip(self): + seven = get_linker_files_dir("seven") + def _test(basedir): + stdout = StringIO() + shutil.copytree(seven, "seven") + os.chdir("seven") + try: + # regrettably, run() always finishes with sys.exit() + cuddlefish.run(["xpi", "--no-strip-xpi"], + stdout=stdout) + except SystemExit, e: + self.failUnlessEqual(e.args[0], 0) + zf = zipfile.ZipFile("seven.xpi", "r") + names = zf.namelist() + self.assertIn("resources/api-utils/lib/cuddlefish.js", names) + testfiles = [fn for fn in names if "seven/tests" in fn] + self.failUnlessEqual([], testfiles) + self.assertIn("resources/seven/data/text.data", + names) + self.failUnless("resources/seven/lib/unused.js" + in names, names) + self.run_in_subdir("x", _test) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_manifest.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_manifest.py new file mode 100644 index 0000000..77ee86f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_manifest.py @@ -0,0 +1,254 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import unittest +from StringIO import StringIO +from cuddlefish.manifest import scan_module + +class Extra: + def failUnlessKeysAre(self, d, keys): + self.failUnlessEqual(sorted(d.keys()), sorted(keys)) + +class Require(unittest.TestCase, Extra): + def scan(self, text): + lines = StringIO(text).readlines() + requires, problems, locations = scan_module("fake.js", lines) + self.failUnlessEqual(problems, False) + return requires + + def scan_locations(self, text): + lines = StringIO(text).readlines() + requires, problems, locations = scan_module("fake.js", lines) + self.failUnlessEqual(problems, False) + return requires, locations + + def test_modules(self): + mod = """var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + mod = """var foo = require(\"one\");""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + mod = """var foo=require( 'one' ) ; """ + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + mod = """var foo = require('o'+'ne'); // tricky, denied""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, []) + + mod = """require('one').immediately.do().stuff();""" + requires, locations = self.scan_locations(mod) + self.failUnlessKeysAre(requires, ["one"]) + self.failUnlessEqual(locations, {"one": 1}) + + # these forms are commented out, and thus ignored + + mod = """// var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, []) + + mod = """/* var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, []) + + mod = """ * var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, []) + + mod = """ ' var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + mod = """ \" var foo = require('one');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + # multiple requires + + mod = """const foo = require('one'); + const foo = require('two');""" + requires, locations = self.scan_locations(mod) + self.failUnlessKeysAre(requires, ["one", "two"]) + self.failUnlessEqual(locations["one"], 1) + self.failUnlessEqual(locations["two"], 2) + + mod = """const foo = require('repeated'); + const bar = require('repeated'); + const baz = require('repeated');""" + requires, locations = self.scan_locations(mod) + self.failUnlessKeysAre(requires, ["repeated"]) + self.failUnlessEqual(locations["repeated"], 1) # first occurrence + + mod = """const foo = require('one'); const foo = require('two');""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one", "two"]) + + # define calls + + mod = """define('one', ['two', 'numbers/three'], function(t, th) {});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["two", "numbers/three"]) + + mod = """define( + ['odd', + "numbers/four"], function() {});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["odd", "numbers/four"]) + + mod = """define(function(require, exports, module) { + var a = require("some/module/a"), + b = require('b/v1'); + exports.a = a; + //This is a fakeout: require('bad'); + /* And another var bad = require('bad2'); */ + require('foo').goFoo(); + });""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["some/module/a", "b/v1", "foo"]) + + mod = """define ( + "foo", + ["bar"], function (bar) { + var me = require("me"); + } + )""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["bar", "me"]) + + mod = """define(['se' + 'ven', 'eight', nine], function () {});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["eight"]) + + # async require calls + + mod = """require(['one'], function(one) {var o = require("one");});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one"]) + + mod = """require([ 'one' ], function(one) {var t = require("two");});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["one", "two"]) + + mod = """require ( ['two', 'numbers/three'], function(t, th) {});""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["two", "numbers/three"]) + + mod = """require ( + ["bar", "fa" + 'ke' ], function (bar) { + var me = require("me"); + // require("bad").doBad(); + } + )""" + requires = self.scan(mod) + self.failUnlessKeysAre(requires, ["bar", "me"]) + +def scan2(text, fn="fake.js"): + stderr = StringIO() + lines = StringIO(text).readlines() + requires, problems, locations = scan_module(fn, lines, stderr) + stderr.seek(0) + return requires, problems, stderr.readlines() + +class Chrome(unittest.TestCase, Extra): + + def test_ignore_loader(self): + # we specifically ignore the loader itself + mod = """let {Cc,Ci} = require('chrome');""" + requires, problems, err = scan2(mod, "blah/cuddlefish.js") + self.failUnlessKeysAre(requires, ["chrome"]) + self.failUnlessEqual(problems, False) + self.failUnlessEqual(err, []) + + def test_chrome(self): + mod = """let {Cc,Ci} = require('chrome');""" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, ["chrome"]) + self.failUnlessEqual(problems, False) + self.failUnlessEqual(err, []) + + mod = """var foo = require('foo'); + let {Cc,Ci} = require('chrome');""" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, ["foo", "chrome"]) + self.failUnlessEqual(problems, False) + self.failUnlessEqual(err, []) + + mod = """let c = require('chrome');""" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, ["chrome"]) + self.failUnlessEqual(problems, False) + self.failUnlessEqual(err, []) + + mod = """var foo = require('foo'); + let c = require('chrome');""" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, ["foo", "chrome"]) + self.failUnlessEqual(problems, False) + self.failUnlessEqual(err, []) + + def test_chrome_components(self): + # Bug 663541: tolerate "Components" if you're marked with + # require("chrome"), to avoid requiring module authors to rewrite a + # lot of code. Once bug 636145 is fixed, such code will break. To fix + # it, add {Components}=require("chrome"), but that won't work until + # after 636145 is fixed. + mod = """require("chrome"); + var ios = Components.classes['@mozilla.org/network/io-service;1'];""" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, ["chrome"]) + self.failUnlessEqual((problems, err), (False, [])) + + def test_not_chrome(self): + # from bug 596595 + mod = r'soughtLines: new RegExp("^\\s*(\\[[0-9 .]*\\])?\\s*\\(\\((EE|WW)\\)|.* [Cc]hipsets?: \\)|\\s*Backtrace")' + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, []) + self.failUnlessEqual((problems,err), (False, [])) + + def test_not_chrome2(self): + # from bug 655788 + mod = r"var foo = 'some stuff Cr';" + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, []) + self.failUnlessEqual((problems,err), (False, [])) + +class BadChrome(unittest.TestCase, Extra): + def test_bad_alias(self): + # using Components.* gets you an error, with a message that teaches + # you the correct approach. + mod = """let Cc = Components.classes; + let Cu = Components.utils; + """ + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, []) + self.failUnlessEqual(problems, True) + self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") + self.failUnlessEqual(err[2], " 1: let Cc = Components.classes;\n") + self.failUnlessEqual(err[3], " 2: let Cu = Components.utils;\n") + self.failUnlessEqual(err[4], "use 'Components' to access chrome authority. To do so, you need to add a\n") + self.failUnlessEqual(err[5], "line somewhat like the following:\n") + self.failUnlessEqual(err[7], ' const {Cc,Cu} = require("chrome");\n') + self.failUnlessEqual(err[9], "Then you can use 'Components' as well as any shortcuts to its properties\n") + + def test_bad_misc(self): + # If it looks like you're using something that doesn't have an alias, + # the warning also suggests a better way. + mod = """if (Components.isSuccessCode(foo)) + """ + requires, problems, err = scan2(mod) + self.failUnlessKeysAre(requires, []) + self.failUnlessEqual(problems, True) + self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") + self.failUnlessEqual(err[2], " 1: if (Components.isSuccessCode(foo))\n") + self.failUnlessEqual(err[3], "use 'Components' to access chrome authority. To do so, you need to add a\n") + self.failUnlessEqual(err[4], "line somewhat like the following:\n") + self.failUnlessEqual(err[6], ' const {components} = require("chrome");\n') + self.failUnlessEqual(err[8], "Then you can use 'Components' as well as any shortcuts to its properties\n") + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_packaging.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_packaging.py new file mode 100644 index 0000000..ff3d851 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_packaging.py @@ -0,0 +1,116 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import unittest + +from cuddlefish import packaging +from cuddlefish.bunch import Bunch + +tests_path = os.path.abspath(os.path.dirname(__file__)) +static_files_path = os.path.join(tests_path, 'static-files') + +def get_configs(pkg_name, dirname='static-files'): + root_path = os.path.join(tests_path, dirname) + pkg_path = os.path.join(root_path, 'packages', pkg_name) + if not (os.path.exists(pkg_path) and os.path.isdir(pkg_path)): + raise Exception('path does not exist: %s' % pkg_path) + target_cfg = packaging.get_config_in_dir(pkg_path) + pkg_cfg = packaging.build_config(root_path, target_cfg) + deps = packaging.get_deps_for_targets(pkg_cfg, [pkg_name]) + build = packaging.generate_build_for_target( + pkg_cfg=pkg_cfg, + target=pkg_name, + deps=deps + ) + return Bunch(target_cfg=target_cfg, pkg_cfg=pkg_cfg, build=build) + +class PackagingTests(unittest.TestCase): + def test_bug_588661(self): + configs = get_configs('foo', 'bug-588661-files') + self.assertEqual(configs.build.loader, + 'foo/lib/foo-loader.js') + + def test_bug_614712(self): + configs = get_configs('commonjs-naming', 'bug-614712-files') + packages = configs.pkg_cfg.packages + base = os.path.join(tests_path, 'bug-614712-files', 'packages') + self.assertEqual(packages['original-naming'].tests, + [os.path.join(base, 'original-naming', 'tests')]) + self.assertEqual(packages['commonjs-naming'].tests, + [os.path.join(base, 'commonjs-naming', 'test')]) + + def test_basic(self): + configs = get_configs('aardvark') + packages = configs.pkg_cfg.packages + + self.assertTrue('api-utils' in packages) + self.assertTrue('aardvark' in packages) + self.assertTrue('api-utils' in packages.aardvark.dependencies) + self.assertEqual(packages['api-utils'].loader, 'lib/loader.js') + self.assertTrue(packages.aardvark.main == 'main') + self.assertTrue(packages.aardvark.version == "1.0") + +class PackagePath(unittest.TestCase): + def test_packagepath(self): + root_path = os.path.join(tests_path, 'static-files') + pkg_path = os.path.join(root_path, 'packages', 'minimal') + target_cfg = packaging.get_config_in_dir(pkg_path) + pkg_cfg = packaging.build_config(root_path, target_cfg) + base_packages = set(pkg_cfg.packages.keys()) + ppath = [os.path.join(tests_path, 'bug-611495-files')] + pkg_cfg2 = packaging.build_config(root_path, target_cfg, packagepath=ppath) + all_packages = set(pkg_cfg2.packages.keys()) + self.assertEqual(sorted(["jspath-one"]), + sorted(all_packages - base_packages)) + +class Directories(unittest.TestCase): + # for bug 652227 + packages_path = os.path.join(tests_path, "bug-652227-files", "packages") + def get_config(self, pkg_name): + pkg_path = os.path.join(tests_path, "bug-652227-files", "packages", + pkg_name) + return packaging.get_config_in_dir(pkg_path) + + def test_explicit_lib(self): + # package.json provides .lib + p = self.get_config('explicit-lib') + self.assertEqual(os.path.abspath(p.lib[0]), + os.path.abspath(os.path.join(self.packages_path, + "explicit-lib", + "alt2-lib"))) + + def test_directories_lib(self): + # package.json provides .directories.lib + p = self.get_config('explicit-dir-lib') + self.assertEqual(os.path.abspath(p.lib[0]), + os.path.abspath(os.path.join(self.packages_path, + "explicit-dir-lib", + "alt-lib"))) + + def test_lib(self): + # package.json is empty, but lib/ exists + p = self.get_config("default-lib") + self.assertEqual(os.path.abspath(p.lib[0]), + os.path.abspath(os.path.join(self.packages_path, + "default-lib", + "lib"))) + + def test_root(self): + # package.json is empty, no lib/, so files are in root + p = self.get_config('default-root') + self.assertEqual(os.path.abspath(p.lib[0]), + os.path.abspath(os.path.join(self.packages_path, + "default-root"))) + + def test_locale(self): + # package.json is empty, but locale/ exists and should be used + p = self.get_config("default-locale") + self.assertEqual(os.path.abspath(p.locale), + os.path.abspath(os.path.join(self.packages_path, + "default-locale", + "locale"))) + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_preflight.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_preflight.py new file mode 100644 index 0000000..571b791 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_preflight.py @@ -0,0 +1,147 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import os, shutil +import simplejson as json +import unittest +import hashlib +import base64 +from cuddlefish import preflight +from StringIO import StringIO + +class Util(unittest.TestCase): + def get_basedir(self): + return os.path.join(".test_tmp", self.id()) + def make_basedir(self): + basedir = self.get_basedir() + if os.path.isdir(basedir): + here = os.path.abspath(os.getcwd()) + assert os.path.abspath(basedir).startswith(here) # safety + shutil.rmtree(basedir) + os.makedirs(basedir) + return basedir + + def test_base62(self): + for i in range(1000): + h = hashlib.sha1(str(i)).digest() + s1 = base64.b64encode(h, "AB").strip("=") + s2 = base64.b64encode(h).strip("=").replace("+","A").replace("/","B") + self.failUnlessEqual(s1, s2) + + def write(self, config): + basedir = self.get_basedir() + fn = os.path.join(basedir, "package.json") + open(fn,"w").write(config) + def read(self): + basedir = self.get_basedir() + fn = os.path.join(basedir, "package.json") + return open(fn,"r").read() + + def get_cfg(self): + cfg = json.loads(self.read()) + if "name" not in cfg: + # the cfx parser always provides a name, even if package.json + # doesn't contain one + cfg["name"] = "pretend name" + return cfg + + def parse(self, keydata): + fields = {} + fieldnames = [] + for line in keydata.split("\n"): + if line.strip(): + k,v = line.split(":", 1) + k = k.strip() ; v = v.strip() + fields[k] = v + fieldnames.append(k) + return fields, fieldnames + + def test_preflight(self): + basedir = self.make_basedir() + fn = os.path.join(basedir, "package.json") + + # empty config is not ok: need id (name is automatically supplied) + config_orig = "{}" + self.write(config_orig) + out = StringIO() + cfg = self.get_cfg() + config_was_ok, modified = preflight.preflight_config(cfg, fn, + stderr=out) + self.failUnlessEqual(config_was_ok, False) + self.failUnlessEqual(modified, True) + backup_fn = os.path.join(basedir, "package.json.backup") + config_backup = open(backup_fn,"r").read() + self.failUnlessEqual(config_backup, config_orig) + config = json.loads(self.read()) + self.failIf("name" in config) + self.failUnless("id" in config) + self.failUnless(config["id"].startswith("jid1-"), config["id"]) + self.failUnlessEqual(out.getvalue().strip(), + "No 'id' in package.json: creating a new ID for you.") + os.unlink(backup_fn) + + # just a name? we add the id + config_orig = '{"name": "my-awesome-package"}' + self.write(config_orig) + out = StringIO() + cfg = self.get_cfg() + config_was_ok, modified = preflight.preflight_config(cfg, fn, + stderr=out) + self.failUnlessEqual(config_was_ok, False) + self.failUnlessEqual(modified, True) + backup_fn = os.path.join(basedir, "package.json.backup") + config_backup = open(backup_fn,"r").read() + self.failUnlessEqual(config_backup, config_orig) + config = json.loads(self.read()) + self.failUnlessEqual(config["name"], "my-awesome-package") + self.failUnless("id" in config) + self.failUnless(config["id"].startswith("jid1-"), config["id"]) + jid = str(config["id"]) + self.failUnlessEqual(out.getvalue().strip(), + "No 'id' in package.json: creating a new ID for you.") + os.unlink(backup_fn) + + # name and valid id? great! ship it! + config2 = '{"name": "my-awesome-package", "id": "%s"}' % jid + self.write(config2) + out = StringIO() + cfg = self.get_cfg() + config_was_ok, modified = preflight.preflight_config(cfg, fn, + stderr=out) + self.failUnlessEqual(config_was_ok, True) + self.failUnlessEqual(modified, False) + config2a = self.read() + self.failUnlessEqual(config2a, config2) + self.failUnlessEqual(out.getvalue().strip(), "") + + # name and anonymous ID? without asking to see its papers, ship it + config3 = '{"name": "my-old-skool-package", "id": "anonid0-deadbeef"}' + self.write(config3) + out = StringIO() + cfg = self.get_cfg() + config_was_ok, modified = preflight.preflight_config(cfg, fn, + stderr=out) + self.failUnlessEqual(config_was_ok, True) + self.failUnlessEqual(modified, False) + config3a = self.read() + self.failUnlessEqual(config3a, config3) + self.failUnlessEqual(out.getvalue().strip(), "") + + # name and old-style ID? with nostalgic trepidation, ship it + config4 = '{"name": "my-old-skool-package", "id": "foo@bar.baz"}' + self.write(config4) + out = StringIO() + cfg = self.get_cfg() + config_was_ok, modified = preflight.preflight_config(cfg, fn, + stderr=out) + self.failUnlessEqual(config_was_ok, True) + self.failUnlessEqual(modified, False) + config4a = self.read() + self.failUnlessEqual(config4a, config4) + self.failUnlessEqual(out.getvalue().strip(), "") + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_property_parser.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_property_parser.py new file mode 100644 index 0000000..f037f07 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_property_parser.py @@ -0,0 +1,75 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest + +from cuddlefish.property_parser import parse, MalformedLocaleFileError + +class TestParser(unittest.TestCase): + + def test_parse(self): + lines = [ + # Comments are striped only if `#` is the first non-space character + "sharp=#can be in value", + "# comment", + "#key=value", + " # comment2", + + "keyWithNoValue=", + "valueWithSpaces= ", + "valueWithMultilineSpaces= \\", + " \\", + " ", + + # All spaces before/after are striped + " key = value ", + "key2=value2", + # Keys can contain '%' + "%s key=%s value", + + # Accept empty lines + "", + " ", + + # Multiline string must use backslash at end of lines + "multi=line\\", "value", + # With multiline string, left spaces are stripped ... + "some= spaces\\", " are\\ ", " stripped ", + # ... but not right spaces, except the last line! + "but=not \\", "all of \\", " them " + ] + # Ensure that lines end with a `\n` + lines = [l + "\n" for l in lines] + pairs = parse(lines) + expected = { + "sharp": "#can be in value", + + "key": "value", + "key2": "value2", + "%s key": "%s value", + + "keyWithNoValue": "", + "valueWithSpaces": "", + "valueWithMultilineSpaces": "", + + "multi": "linevalue", + "some": "spacesarestripped", + "but": "not all of them" + } + self.assertEqual(pairs, expected) + + def test_exceptions(self): + self.failUnlessRaises(MalformedLocaleFileError, parse, + ["invalid line with no key value"]) + self.failUnlessRaises(MalformedLocaleFileError, parse, + ["plural[one]=plural with no generic value"]) + self.failUnlessRaises(MalformedLocaleFileError, parse, + ["multiline with no last empty line=\\"]) + self.failUnlessRaises(MalformedLocaleFileError, parse, + ["=no key"]) + self.failUnlessRaises(MalformedLocaleFileError, parse, + [" =only spaces in key"]) + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_rdf.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_rdf.py new file mode 100644 index 0000000..128289f --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_rdf.py @@ -0,0 +1,45 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import unittest +import xml.dom.minidom +import os.path + +from cuddlefish import rdf, packaging + +parent = os.path.dirname +test_dir = parent(os.path.abspath(__file__)) +template_dir = os.path.join(parent(test_dir), "app-extension") + +class RDFTests(unittest.TestCase): + def testBug567660(self): + obj = rdf.RDF() + data = u'\u2026'.encode('utf-8') + x = '%s' % data + obj.dom = xml.dom.minidom.parseString(x) + self.assertEqual(obj.dom.documentElement.firstChild.nodeValue, + u'\u2026') + self.assertEqual(str(obj).replace("\n",""), x.replace("\n","")) + + def failUnlessIn(self, substring, s, msg=""): + if substring not in s: + self.fail("(%s) substring '%s' not in string '%s'" + % (msg, substring, s)) + + def testUnpack(self): + basedir = os.path.join(test_dir, "bug-715340-files") + for n in ["pkg-1-pack", "pkg-2-unpack", "pkg-3-pack"]: + cfg = packaging.get_config_in_dir(os.path.join(basedir, n)) + m = rdf.gen_manifest(template_dir, cfg, jid="JID") + if n.endswith("-pack"): + # these ones should remain packed + self.failUnlessEqual(m.get("em:unpack"), "false") + self.failUnlessIn("false", str(m), n) + else: + # and these should be unpacked + self.failUnlessEqual(m.get("em:unpack"), "true") + self.failUnlessIn("true", str(m), n) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_runner.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_runner.py new file mode 100644 index 0000000..26583ab --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_runner.py @@ -0,0 +1,27 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +def xulrunner_app_runner_doctests(): + """ + >>> import sys + >>> from cuddlefish import runner + >>> runner.XulrunnerAppRunner(binary='foo') + Traceback (most recent call last): + ... + Exception: Binary path does not exist foo + + >>> runner.XulrunnerAppRunner(binary=sys.executable) + Traceback (most recent call last): + ... + ValueError: application.ini not found in cmdargs + + >>> runner.XulrunnerAppRunner(binary=sys.executable, + ... cmdargs=['application.ini']) + Traceback (most recent call last): + ... + ValueError: file does not exist: 'application.ini' + """ + + pass diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_util.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_util.py new file mode 100644 index 0000000..aa636a4 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_util.py @@ -0,0 +1,22 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import unittest +from cuddlefish.manifest import filter_filenames, filter_dirnames + +class Filter(unittest.TestCase): + def test_filter_filenames(self): + names = ["foo", "bar.js", "image.png", + ".hidden", "foo~", ".foo.swp", "bar.js.swp"] + self.failUnlessEqual(sorted(filter_filenames(names)), + sorted(["foo", "bar.js", "image.png"])) + + def test_filter_dirnames(self): + names = ["subdir", "data", ".git", ".hg", ".svn", "defaults"] + self.failUnlessEqual(sorted(filter_dirnames(names)), + sorted(["subdir", "data", "defaults"])) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_version.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_version.py new file mode 100644 index 0000000..814c57c --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_version.py @@ -0,0 +1,28 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import unittest +import shutil + +from cuddlefish._version import get_versions + +class Version(unittest.TestCase): + def get_basedir(self): + return os.path.join(".test_tmp", self.id()) + def make_basedir(self): + basedir = self.get_basedir() + if os.path.isdir(basedir): + here = os.path.abspath(os.getcwd()) + assert os.path.abspath(basedir).startswith(here) # safety + shutil.rmtree(basedir) + os.makedirs(basedir) + return basedir + + def test_current_version(self): + # the SDK should be able to determine its own version. We don't care + # what it is, merely that it can be computed. + version = get_versions()["version"] + self.failUnless(isinstance(version, str), (version, type(version))) + self.failUnless(len(version) > 0, version) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_webdocs.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_webdocs.py new file mode 100644 index 0000000..d9d4eab --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_webdocs.py @@ -0,0 +1,97 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import unittest + +from cuddlefish.docs import webdocs + +class WebDocTests(unittest.TestCase): + def test_create_package_doc(self): + root = os.path.join(os.getcwd() + \ + '/python-lib/cuddlefish/tests/static-files') + web_docs = webdocs.WebDocs(root) + aarvark_package = web_docs.create_package_page('aardvark') + self._test_common_contents(aarvark_package) + self.assertTrue('

aardvark

'\ + in aarvark_package) + self.assertTrue(\ + 'Author'\ + in aarvark_package) + self.assertTrue(\ + 'Jon Smith'\ + in aarvark_package) + self.assertTrue(\ + 'aardvark - Add-on SDK Documentation'\ + in aarvark_package) + + def test_create_guide1_doc(self): + root = os.path.join(os.getcwd() + \ + '/python-lib/cuddlefish/tests/static-files') + web_docs = webdocs.WebDocs(root) + guide = web_docs.create_guide_page(os.path.join(\ + root + '/doc/dev-guide-source/index.blah')) + self._test_common_contents(guide) + self.assertTrue(\ + 'An Imposing Title - Add-on SDK Documentation'\ + in guide) + self.assertTrue('

Some words!

'\ + in guide) + self.assertTrue('
Version '\ + in guide) + + def test_create_guide2_doc(self): + root = os.path.join(os.getcwd() + \ + '/python-lib/cuddlefish/tests/static-files') + web_docs = webdocs.WebDocs(root) + guide = web_docs.create_guide_page(os.path.join(\ + root + '/doc/dev-guide-source/no_h1.blah')) + self._test_common_contents(guide) + self.assertTrue('Add-on SDK Documentation'\ + in guide) + self.assertTrue('

A heading

'\ + in guide) + + def test_create_module_doc(self): + root = os.path.join(os.getcwd() + \ + '/python-lib/cuddlefish/tests/static-files') + web_docs = webdocs.WebDocs(root) + module = web_docs.create_module_page(os.path.join(\ + root + '/packages/aardvark/doc/aardvark-feeder.blah')) + self._test_common_contents(module) + self.assertTrue(\ + 'aardvark-feeder - Add-on SDK Documentation'\ + in module) + self.assertTrue(\ + '

aardvark-feeder

'\ + in module) + self.assertTrue(\ + '
'\ + in module) + self.assertTrue(\ + '

The aardvark-feeder module simplifies feeding aardvarks.

'\ + in module) + self.assertTrue(\ + '

API Reference

'\ + in module) + self.assertTrue(\ + '

Functions

'\ + in module) + self.assertTrue(\ + '

feed(food)

'\ + in module) + self.assertTrue( + '

Feed the aardvark.

'\ + in module) + + def _test_common_contents(self, doc): + self.assertTrue(\ + 'main' in doc) + +if __name__ == "__main__": + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_xpi.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_xpi.py new file mode 100644 index 0000000..7d638bb --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/tests/test_xpi.py @@ -0,0 +1,412 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import unittest +import zipfile +import pprint +import shutil + +import simplejson as json +from cuddlefish import xpi, packaging, manifest, buildJID +from cuddlefish.tests import test_packaging +from test_linker import up + +xpi_template_path = os.path.join(test_packaging.static_files_path, + 'xpi-template') + +fake_manifest = '' + +class PrefsTests(unittest.TestCase): + def makexpi(self, pkg_name): + self.xpiname = "%s.xpi" % pkg_name + create_xpi(self.xpiname, pkg_name, 'preferences-files') + self.xpi = zipfile.ZipFile(self.xpiname, 'r') + options = self.xpi.read('harness-options.json') + self.xpi_harness_options = json.loads(options) + + def setUp(self): + self.xpiname = None + self.xpi = None + + def tearDown(self): + if self.xpi: + self.xpi.close() + if self.xpiname and os.path.exists(self.xpiname): + os.remove(self.xpiname) + + def testPackageWithSimplePrefs(self): + self.makexpi('simple-prefs') + self.failUnless('options.xul' in self.xpi.namelist()) + optsxul = self.xpi.read('options.xul').decode("utf-8") + self.failUnless('pref="extensions.jid1-fZHqN9JfrDBa8A@jetpack.test"' + in optsxul, optsxul) + self.failUnless('type="bool"' in optsxul, optsxul) + self.failUnless(u'title="t\u00EBst"' in optsxul, repr(optsxul)) + self.failUnlessEqual(self.xpi_harness_options["jetpackID"], + "jid1-fZHqN9JfrDBa8A@jetpack") + prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8") + exp = [u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test", false);', + u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test2", "\u00FCnic\u00F8d\u00E9");', + ] + self.failUnlessEqual(prefsjs, "\n".join(exp)+"\n") + + def testPackageWithNoPrefs(self): + self.makexpi('no-prefs') + self.failIf('options.xul' in self.xpi.namelist()) + self.failUnlessEqual(self.xpi_harness_options["jetpackID"], + "jid1-fZHqN9JfrDBa8A@jetpack") + prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8") + self.failUnlessEqual(prefsjs, "") + + +class Bug588119Tests(unittest.TestCase): + def makexpi(self, pkg_name): + self.xpiname = "%s.xpi" % pkg_name + create_xpi(self.xpiname, pkg_name, 'bug-588119-files') + self.xpi = zipfile.ZipFile(self.xpiname, 'r') + options = self.xpi.read('harness-options.json') + self.xpi_harness_options = json.loads(options) + + def setUp(self): + self.xpiname = None + self.xpi = None + + def tearDown(self): + if self.xpi: + self.xpi.close() + if self.xpiname and os.path.exists(self.xpiname): + os.remove(self.xpiname) + + def testPackageWithImplicitIcon(self): + self.makexpi('implicit-icon') + assert 'icon.png' in self.xpi.namelist() + + def testPackageWithImplicitIcon64(self): + self.makexpi('implicit-icon') + assert 'icon64.png' in self.xpi.namelist() + + def testPackageWithExplicitIcon(self): + self.makexpi('explicit-icon') + assert 'icon.png' in self.xpi.namelist() + + def testPackageWithExplicitIcon64(self): + self.makexpi('explicit-icon') + assert 'icon64.png' in self.xpi.namelist() + + def testPackageWithNoIcon(self): + self.makexpi('no-icon') + assert 'icon.png' not in self.xpi.namelist() + + def testIconPathNotInHarnessOptions(self): + self.makexpi('implicit-icon') + assert 'icon' not in self.xpi_harness_options + + def testIcon64PathNotInHarnessOptions(self): + self.makexpi('implicit-icon') + assert 'icon64' not in self.xpi_harness_options + +class ExtraHarnessOptions(unittest.TestCase): + def setUp(self): + self.xpiname = None + self.xpi = None + + def tearDown(self): + if self.xpi: + self.xpi.close() + if self.xpiname and os.path.exists(self.xpiname): + os.remove(self.xpiname) + + def testOptions(self): + pkg_name = "extra-options" + self.xpiname = "%s.xpi" % pkg_name + create_xpi(self.xpiname, pkg_name, "bug-669274-files", + extra_harness_options={"builderVersion": "futuristic"}) + self.xpi = zipfile.ZipFile(self.xpiname, 'r') + options = self.xpi.read('harness-options.json') + hopts = json.loads(options) + self.failUnless("builderVersion" in hopts) + self.failUnlessEqual(hopts["builderVersion"], "futuristic") + + def testBadOptionName(self): + pkg_name = "extra-options" + self.xpiname = "%s.xpi" % pkg_name + self.failUnlessRaises(xpi.HarnessOptionAlreadyDefinedError, + create_xpi, + self.xpiname, pkg_name, "bug-669274-files", + extra_harness_options={"main": "already in use"}) + +class SmallXPI(unittest.TestCase): + def setUp(self): + self.root = up(os.path.abspath(__file__), 4) + def get_linker_files_dir(self, name): + return os.path.join(up(os.path.abspath(__file__)), "linker-files", name) + def get_pkg(self, name): + d = self.get_linker_files_dir(name) + return packaging.get_config_in_dir(d) + + def get_basedir(self): + return os.path.join(".test_tmp", self.id()) + def make_basedir(self): + basedir = self.get_basedir() + if os.path.isdir(basedir): + here = os.path.abspath(os.getcwd()) + assert os.path.abspath(basedir).startswith(here) # safety + shutil.rmtree(basedir) + os.makedirs(basedir) + return basedir + + def test_contents(self): + target_cfg = self.get_pkg("three") + package_path = [self.get_linker_files_dir("three-deps")] + pkg_cfg = packaging.build_config(self.root, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False) + used_files = list(m.get_used_files()) + here = up(os.path.abspath(__file__)) + def absify(*parts): + fn = os.path.join(here, "linker-files", *parts) + return os.path.abspath(fn) + expected = [absify(*parts) for parts in + [("three", "lib", "main.js"), + ("three-deps", "three-a", "lib", "main.js"), + ("three-deps", "three-a", "lib", "subdir", "subfile.js"), + ("three-deps", "three-a", "data", "msg.txt"), + ("three-deps", "three-a", "data", "subdir", "submsg.txt"), + ("three-deps", "three-b", "lib", "main.js"), + ("three-deps", "three-c", "lib", "main.js"), + ("three-deps", "three-c", "lib", "sub", "foo.js"), + ]] + missing = set(expected) - set(used_files) + extra = set(used_files) - set(expected) + self.failUnlessEqual((list(missing), list(extra)), ([], [])) + used_deps = m.get_used_packages() + + build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name, + used_deps, + include_tests=False) + options = {'main': target_cfg.main} + options.update(build) + basedir = self.make_basedir() + xpi_name = os.path.join(basedir, "contents.xpi") + xpi.build_xpi(template_root_dir=xpi_template_path, + manifest=fake_manifest, + xpi_path=xpi_name, + harness_options=options, + limit_to=used_files) + x = zipfile.ZipFile(xpi_name, "r") + names = x.namelist() + expected = ["components/", + "components/harness.js", + # the real template also has 'bootstrap.js', but the fake + # one in tests/static-files/xpi-template doesn't + "harness-options.json", + "install.rdf", + "defaults/preferences/prefs.js", + "resources/", + "resources/api-utils/", + "resources/api-utils/data/", + "resources/api-utils/lib/", + "resources/three/", + "resources/three/lib/", + "resources/three/lib/main.js", + "resources/three-a/", + "resources/three-a/data/", + "resources/three-a/data/msg.txt", + "resources/three-a/data/subdir/", + "resources/three-a/data/subdir/submsg.txt", + "resources/three-a/lib/", + "resources/three-a/lib/main.js", + "resources/three-a/lib/subdir/", + "resources/three-a/lib/subdir/subfile.js", + "resources/three-b/", + "resources/three-b/lib/", + "resources/three-b/lib/main.js", + "resources/three-c/", + "resources/three-c/lib/", + "resources/three-c/lib/main.js", + "resources/three-c/lib/sub/", + "resources/three-c/lib/sub/foo.js", + # notably absent: three-a/lib/unused.js + "locale/", + "locale/fr-FR.json", + "locales.json", + ] + # showing deltas makes failures easier to investigate + missing = set(expected) - set(names) + extra = set(names) - set(expected) + self.failUnlessEqual((list(missing), list(extra)), ([], [])) + self.failUnlessEqual(sorted(names), sorted(expected)) + + # check locale files + localedata = json.loads(x.read("locales.json")) + self.failUnlessEqual(sorted(localedata["locales"]), sorted(["fr-FR"])) + content = x.read("locale/fr-FR.json") + locales = json.loads(content) + # Locale files are merged into one. + # Conflicts are silently resolved by taking last package translation, + # so that we get "No" translation from three-c instead of three-b one. + self.failUnlessEqual(locales, json.loads(u''' + { + "No": "Nein", + "one": "un", + "What?": "Quoi?", + "Yes": "Oui", + "plural": { + "other": "other", + "one": "one" + }, + "uft8_value": "\u00e9" + }''')) + + def test_scantests(self): + target_cfg = self.get_pkg("three") + package_path = [self.get_linker_files_dir("three-deps")] + pkg_cfg = packaging.build_config(self.root, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True) + self.failUnlessEqual(sorted(m.get_all_test_modules()), + sorted(["test-one", "test-two"])) + # the current __init__.py code omits limit_to=used_files for 'cfx + # test', so all test files are included in the XPI. But the test + # runner will only execute the tests that m.get_all_test_modules() + # tells us about (which are put into the .allTestModules property of + # harness-options.json). + used_deps = m.get_used_packages() + + build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name, + used_deps, + include_tests=True) + options = {'main': target_cfg.main} + options.update(build) + basedir = self.make_basedir() + xpi_name = os.path.join(basedir, "contents.xpi") + xpi.build_xpi(template_root_dir=xpi_template_path, + manifest=fake_manifest, + xpi_path=xpi_name, + harness_options=options, + limit_to=None) + x = zipfile.ZipFile(xpi_name, "r") + names = x.namelist() + self.failUnless("resources/api-utils/lib/unit-test.js" in names, names) + self.failUnless("resources/api-utils/lib/unit-test-finder.js" in names, names) + self.failUnless("resources/test-harness/lib/harness.js" in names, names) + self.failUnless("resources/test-harness/lib/run-tests.js" in names, names) + # all files are copied into the XPI, even the things that don't look + # like tests. + self.failUnless("resources/three/tests/test-one.js" in names, names) + self.failUnless("resources/three/tests/test-two.js" in names, names) + self.failUnless("resources/three/tests/nontest.js" in names, names) + + def test_scantests_filter(self): + target_cfg = self.get_pkg("three") + package_path = [self.get_linker_files_dir("three-deps")] + pkg_cfg = packaging.build_config(self.root, target_cfg, + packagepath=package_path) + deps = packaging.get_deps_for_targets(pkg_cfg, + [target_cfg.name, "addon-kit"]) + FILTER = ".*one.*" + m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True, + test_filter_re=FILTER) + self.failUnlessEqual(sorted(m.get_all_test_modules()), + sorted(["test-one"])) + # the current __init__.py code omits limit_to=used_files for 'cfx + # test', so all test files are included in the XPI. But the test + # runner will only execute the tests that m.get_all_test_modules() + # tells us about (which are put into the .allTestModules property of + # harness-options.json). + used_deps = m.get_used_packages() + + build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name, + used_deps, + include_tests=True) + options = {'main': target_cfg.main} + options.update(build) + basedir = self.make_basedir() + xpi_name = os.path.join(basedir, "contents.xpi") + xpi.build_xpi(template_root_dir=xpi_template_path, + manifest=fake_manifest, + xpi_path=xpi_name, + harness_options=options, + limit_to=None) + x = zipfile.ZipFile(xpi_name, "r") + names = x.namelist() + self.failUnless("resources/api-utils/lib/unit-test.js" in names, names) + self.failUnless("resources/api-utils/lib/unit-test-finder.js" in names, names) + self.failUnless("resources/test-harness/lib/harness.js" in names, names) + self.failUnless("resources/test-harness/lib/run-tests.js" in names, names) + # get_all_test_modules() respects the filter. But all files are still + # copied into the XPI. + self.failUnless("resources/three/tests/test-one.js" in names, names) + self.failUnless("resources/three/tests/test-two.js" in names, names) + self.failUnless("resources/three/tests/nontest.js" in names, names) + + +def document_dir(name): + if name in ['packages', 'xpi-template']: + dirname = os.path.join(test_packaging.static_files_path, name) + document_dir_files(dirname) + elif name == 'xpi-output': + create_xpi('test-xpi.xpi') + document_zip_file('test-xpi.xpi') + os.remove('test-xpi.xpi') + else: + raise Exception('unknown dir: %s' % name) + +def normpath(path): + """ + Make a platform-specific relative path use '/' as a separator. + """ + + return path.replace(os.path.sep, '/') + +def document_zip_file(path): + zip = zipfile.ZipFile(path, 'r') + for name in sorted(zip.namelist()): + contents = zip.read(name) + lines = contents.splitlines() + if len(lines) == 1 and name.endswith('.json') and len(lines[0]) > 75: + # Ideally we would json-decode this, but it results + # in an annoying 'u' before every string literal, + # since json decoding makes all strings unicode. + contents = eval(contents) + contents = pprint.pformat(contents) + lines = contents.splitlines() + contents = "\n ".join(lines) + print "%s:\n %s" % (normpath(name), contents) + zip.close() + +def document_dir_files(path): + filename_contents_tuples = [] + for dirpath, dirnames, filenames in os.walk(path): + relpath = dirpath[len(path)+1:] + for filename in filenames: + abspath = os.path.join(dirpath, filename) + contents = open(abspath, 'r').read() + contents = "\n ".join(contents.splitlines()) + relfilename = os.path.join(relpath, filename) + filename_contents_tuples.append((normpath(relfilename), contents)) + filename_contents_tuples.sort() + for filename, contents in filename_contents_tuples: + print "%s:" % filename + print " %s" % contents + +def create_xpi(xpiname, pkg_name='aardvark', dirname='static-files', + extra_harness_options={}): + configs = test_packaging.get_configs(pkg_name, dirname) + options = {'main': configs.target_cfg.main, + 'jetpackID': buildJID(configs.target_cfg), } + options.update(configs.build) + xpi.build_xpi(template_root_dir=xpi_template_path, + manifest=fake_manifest, + xpi_path=xpiname, + harness_options=options, + extra_harness_options=extra_harness_options) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/util.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/util.py new file mode 100644 index 0000000..513495a --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/util.py @@ -0,0 +1,23 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +IGNORED_FILE_PREFIXES = ["."] +IGNORED_FILE_SUFFIXES = ["~", ".swp"] +IGNORED_DIRS = [".git", ".svn", ".hg"] + +def filter_filenames(filenames, ignored_files=[".hgignore"]): + for filename in filenames: + if filename in ignored_files: + continue + if any([filename.startswith(suffix) + for suffix in IGNORED_FILE_PREFIXES]): + continue + if any([filename.endswith(suffix) + for suffix in IGNORED_FILE_SUFFIXES]): + continue + yield filename + +def filter_dirnames(dirnames): + return [dirname for dirname in dirnames if dirname not in IGNORED_DIRS] diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/version_comparator.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/version_comparator.py new file mode 100644 index 0000000..3999e71 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/version_comparator.py @@ -0,0 +1,206 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +''' + This is a really crummy, slow Python implementation of the Mozilla + platform's nsIVersionComparator interface: + + https://developer.mozilla.org/En/NsIVersionComparator + + For more information, also see: + + http://mxr.mozilla.org/mozilla/source/xpcom/glue/nsVersionComparator.cpp +''' + +import re +import sys + +class VersionPart(object): + ''' + Examples: + + >>> VersionPart('1') + (1, None, 0, None) + + >>> VersionPart('1pre') + (1, 'pre', 0, None) + + >>> VersionPart('1pre10') + (1, 'pre', 10, None) + + >>> VersionPart('1pre10a') + (1, 'pre', 10, 'a') + + >>> VersionPart('1+') + (2, 'pre', 0, None) + + >>> VersionPart('*').numA == sys.maxint + True + + >>> VersionPart('1') < VersionPart('2') + True + + >>> VersionPart('2') > VersionPart('1') + True + + >>> VersionPart('1') == VersionPart('1') + True + + >>> VersionPart('1pre') > VersionPart('1') + False + + >>> VersionPart('1') < VersionPart('1pre') + False + + >>> VersionPart('1pre1') < VersionPart('1pre2') + True + + >>> VersionPart('1pre10b') > VersionPart('1pre10a') + True + + >>> VersionPart('1pre10b') == VersionPart('1pre10b') + True + + >>> VersionPart('1pre10a') < VersionPart('1pre10b') + True + + >>> VersionPart('1') > VersionPart('') + True + ''' + + _int_part = re.compile('[+-]?(\d*)(.*)') + _num_chars = '0123456789+-' + + def __init__(self, part): + self.numA = 0 + self.strB = None + self.numC = 0 + self.extraD = None + + if not part: + return + + if part == '*': + self.numA = sys.maxint + else: + match = self._int_part.match(part) + self.numA = int(match.group(1)) + self.strB = match.group(2) or None + if self.strB == '+': + self.strB = 'pre' + self.numA += 1 + elif self.strB: + i = 0 + num_found = -1 + for char in self.strB: + if char in self._num_chars: + num_found = i + break + i += 1 + if num_found != -1: + match = self._int_part.match(self.strB[num_found:]) + self.numC = int(match.group(1)) + self.extraD = match.group(2) or None + self.strB = self.strB[:num_found] + + def _strcmp(self, str1, str2): + # Any string is *before* no string. + if str1 is None: + if str2 is None: + return 0 + else: + return 1 + + if str2 is None: + return -1 + + return cmp(str1, str2) + + def __cmp__(self, other): + r = cmp(self.numA, other.numA) + if r: + return r + + r = self._strcmp(self.strB, other.strB) + if r: + return r + + r = cmp(self.numC, other.numC) + if r: + return r + + return self._strcmp(self.extraD, other.extraD) + + def __repr__(self): + return repr((self.numA, self.strB, self.numC, self.extraD)) + +def compare(a, b): + ''' + Examples: + + >>> compare('1', '2') + -1 + + >>> compare('1', '1') + 0 + + >>> compare('2', '1') + 1 + + >>> compare('1.0pre1', '1.0pre2') + -1 + + >>> compare('1.0pre2', '1.0') + -1 + + >>> compare('1.0', '1.0.0') + 0 + + >>> compare('1.0.0', '1.0.0.0') + 0 + + >>> compare('1.0.0.0', '1.1pre') + -1 + + >>> compare('1.1pre', '1.1pre0') + 0 + + >>> compare('1.1pre0', '1.0+') + 0 + + >>> compare('1.0+', '1.1pre1a') + -1 + + >>> compare('1.1pre1a', '1.1pre1') + -1 + + >>> compare('1.1pre1', '1.1pre10a') + -1 + + >>> compare('1.1pre10a', '1.1pre10') + -1 + + >>> compare('1.1pre10a', '1.*') + -1 + ''' + + a_parts = a.split('.') + b_parts = b.split('.') + + if len(a_parts) < len(b_parts): + a_parts.extend([''] * (len(b_parts) - len(a_parts))) + else: + b_parts.extend([''] * (len(a_parts) - len(b_parts))) + + for a_part, b_part in zip(a_parts, b_parts): + r = cmp(VersionPart(a_part), VersionPart(b_part)) + if r: + return r + + return 0 + +if __name__ == '__main__': + import doctest + + doctest.testmod(verbose=True) diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py new file mode 100644 index 0000000..72b8477 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/xpi.py @@ -0,0 +1,155 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import zipfile +import simplejson as json +from cuddlefish.util import filter_filenames, filter_dirnames + +class HarnessOptionAlreadyDefinedError(Exception): + """You cannot use --harness-option on keys that already exist in + harness-options.json""" + +ZIPSEP = "/" # always use "/" in zipfiles + +def make_zipfile_path(localroot, localpath): + return ZIPSEP.join(localpath[len(localroot)+1:].split(os.sep)) + +def mkzipdir(zf, path): + dirinfo = zipfile.ZipInfo(path) + dirinfo.external_attr = int("040755", 8) << 16L + zf.writestr(dirinfo, "") + +def build_xpi(template_root_dir, manifest, xpi_path, + harness_options, limit_to=None, extra_harness_options={}): + zf = zipfile.ZipFile(xpi_path, "w", zipfile.ZIP_DEFLATED) + + open('.install.rdf', 'w').write(str(manifest)) + zf.write('.install.rdf', 'install.rdf') + os.remove('.install.rdf') + + if 'icon' in harness_options: + zf.write(str(harness_options['icon']), 'icon.png') + del harness_options['icon'] + + if 'icon64' in harness_options: + zf.write(str(harness_options['icon64']), 'icon64.png') + del harness_options['icon64'] + + if 'preferences' in harness_options: + from options_xul import parse_options, validate_prefs + + validate_prefs(harness_options["preferences"]) + + opts_xul = parse_options(harness_options["preferences"], + harness_options["jetpackID"]) + open('.options.xul', 'wb').write(opts_xul.encode("utf-8")) + zf.write('.options.xul', 'options.xul') + os.remove('.options.xul') + + from options_defaults import parse_options_defaults + prefs_js = parse_options_defaults(harness_options["preferences"], + harness_options["jetpackID"]) + open('.prefs.js', 'wb').write(prefs_js.encode("utf-8")) + + else: + open('.prefs.js', 'wb').write("") + + zf.write('.prefs.js', 'defaults/preferences/prefs.js') + os.remove('.prefs.js') + + + IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf", + "application.ini", xpi_path] + + files_to_copy = {} # maps zipfile path to local-disk abspath + dirs_to_create = set() # zipfile paths, no trailing slash + + for dirpath, dirnames, filenames in os.walk(template_root_dir): + filenames = list(filter_filenames(filenames, IGNORED_FILES)) + dirnames[:] = filter_dirnames(dirnames) + for dirname in dirnames: + arcpath = make_zipfile_path(template_root_dir, + os.path.join(dirpath, dirname)) + dirs_to_create.add(arcpath) + for filename in filenames: + abspath = os.path.join(dirpath, filename) + arcpath = make_zipfile_path(template_root_dir, abspath) + files_to_copy[arcpath] = abspath + + # `packages` attribute contains a dictionnary of dictionnary + # of all packages sections directories + for packageName in harness_options['packages']: + base_arcpath = ZIPSEP.join(['resources', packageName]) + # Always write the top directory, even if it contains no files, since + # the harness will try to access it. + dirs_to_create.add(base_arcpath) + for sectionName in harness_options['packages'][packageName]: + abs_dirname = harness_options['packages'][packageName][sectionName] + base_arcpath = ZIPSEP.join(['resources', packageName, sectionName]) + # Always write the top directory, even if it contains no files, since + # the harness will try to access it. + dirs_to_create.add(base_arcpath) + # cp -r stuff from abs_dirname/ into ZIP/resources/RESOURCEBASE/ + for dirpath, dirnames, filenames in os.walk(abs_dirname): + goodfiles = list(filter_filenames(filenames, IGNORED_FILES)) + dirnames[:] = filter_dirnames(dirnames) + for filename in goodfiles: + abspath = os.path.join(dirpath, filename) + if limit_to is not None and abspath not in limit_to: + continue # strip unused files + arcpath = ZIPSEP.join( + ['resources', + packageName, + sectionName, + make_zipfile_path(abs_dirname, + os.path.join(dirpath, filename)), + ]) + files_to_copy[str(arcpath)] = str(abspath) + del harness_options['packages'] + + locales_json_data = {"locales": []} + mkzipdir(zf, "locale/") + for language in sorted(harness_options['locale']): + locales_json_data["locales"].append(language) + locale = harness_options['locale'][language] + # Be carefull about strings, we need to always ensure working with UTF-8 + jsonStr = json.dumps(locale, indent=1, sort_keys=True, ensure_ascii=False) + info = zipfile.ZipInfo('locale/' + language + '.json') + info.external_attr = 0444 << 16L + zf.writestr(info, jsonStr.encode( "utf-8" )) + del harness_options['locale'] + + jsonStr = json.dumps(locales_json_data, ensure_ascii=True) +"\n" + info = zipfile.ZipInfo('locales.json') + info.external_attr = 0444 << 16L + zf.writestr(info, jsonStr.encode("utf-8")) + + # now figure out which directories we need: all retained files parents + for arcpath in files_to_copy: + bits = arcpath.split("/") + for i in range(1,len(bits)): + parentpath = ZIPSEP.join(bits[0:i]) + dirs_to_create.add(parentpath) + + # create zipfile in alphabetical order, with each directory before its + # files + for name in sorted(dirs_to_create.union(set(files_to_copy))): + if name in dirs_to_create: + mkzipdir(zf, name+"/") + if name in files_to_copy: + zf.write(files_to_copy[name], name) + + harness_options = harness_options.copy() + for key,value in extra_harness_options.items(): + if key in harness_options: + msg = "Can't use --harness-option for existing key '%s'" % key + raise HarnessOptionAlreadyDefinedError(msg) + harness_options[key] = value + open('.options.json', 'w').write(json.dumps(harness_options, indent=1, + sort_keys=True)) + zf.write('.options.json', 'harness-options.json') + os.remove('.options.json') + + zf.close() -- cgit v1.2.3