changeset 0:7180966f48bf

Origination.
author Atul Varma <varmaa@toolness.com>
date Thu, 16 Apr 2009 15:23:22 -0700
parents
children 496cd9ab2298
files JSWeakRef/chrome.manifest JSWeakRef/content/test.html JSWeakRef/install.rdf JSWeakRef/modules/memory_tracking.js JSWeakRef/platform/Darwin_x86-gcc3/components/JSWeakRef.xpt JSWeakRef/platform/Darwin_x86-gcc3/components/libJSWeakRef.dylib components/Makefile.in components/install.rdf components/public/Makefile.in components/public/nsIJSWeakRef.idl components/src/JSWeakRefModule.cpp components/src/Makefile.in components/src/nsJSWeakRef.cpp components/src/nsJSWeakRef.h get_xpcom_info.js manage.py
diffstat 16 files changed, 727 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JSWeakRef/chrome.manifest	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,2 @@
+resource JSWeakRef ./
+content JSWeakRef content/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JSWeakRef/content/test.html	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,23 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+  <title>Memory Tracker</title>
+</head>
+<body>
+</body>
+<script>
+Components.utils.import("resource://JSWeakRef/modules/memory_tracking.js");
+
+function showLiveObjects() {
+  var liveObjs = MemoryTracking.getLiveObjects();
+  document.body.innerHTML = liveObjs.join("<br/>");
+}
+
+var blah = new Object();
+MemoryTracking.track(blah);
+
+window.setInterval(showLiveObjects, 250);
+</script>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JSWeakRef/install.rdf	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>JSWeakRef@labs.mozilla.com</em:id>
+    <em:version>0.1</em:version>
+    <em:type>2</em:type>
+
+    <!-- Target Application this extension can install into, 
+         with minimum and maximum supported versions. --> 
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>3.0</em:minVersion>
+        <em:maxVersion>3.0.9</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+   
+    <!-- Front End MetaData -->
+    <em:name>JSWeakRef</em:name>
+    <em:description>Weak References in JavaScript.</em:description>
+    <em:creator>Mozilla Corporation</em:creator>
+    <em:homepageURL>http://wiki.mozilla.org/Labs/JSWeakRef</em:homepageURL>
+  </Description>
+</RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JSWeakRef/modules/memory_tracking.js	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,75 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is JSWeakRef.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ["MemoryTracking"];
+
+var classIds = {};
+var trackedItems = {};
+
+var MemoryTracking = {
+  track: function track(obj, name) {
+    var weakref;
+    try {
+      weakref = Components.classes["@labs.mozilla.com/jsweakrefdi;1"]
+                .createInstance(Components.interfaces.nsIJSWeakRef);
+    } catch (e) {
+      // Weakrefs aren't available, do nothing.
+      return;
+    }
+    weakref.set(obj);
+
+    var className = obj.constructor.name;
+    if (name)
+      className += "_" + name;
+    if (typeof(classIds[className]) == "undefined")
+      classIds[className] = 0;
+    var itemName = className + "_" + classIds[className];
+    classIds[className]++;
+    trackedItems[itemName] = weakref;
+  },
+
+  getLiveObjects: function getLiveObjects() {
+    var liveObjects = [];
+
+    for (name in trackedItems) {
+      if (trackedItems[name].get())
+        liveObjects.push(name);
+      else
+        delete trackedItems[name];
+    }
+    return liveObjects;
+  }
+};
Binary file JSWeakRef/platform/Darwin_x86-gcc3/components/JSWeakRef.xpt has changed
Binary file JSWeakRef/platform/Darwin_x86-gcc3/components/libJSWeakRef.dylib has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/Makefile.in	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,16 @@
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = public src
+
+XPI_NAME = JSWeakRef-components
+INSTALL_EXTENSION_ID = JSWeakRef-components@labs.mozilla.com
+XPI_PKGNAME = JSWeakRef-components
+
+DIST_FILES = install.rdf
+
+include $(topsrcdir)/config/rules.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/install.rdf	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!-- This isn't the install.rdf for a 'real' extension; it's just
+     a placeholder so that the Mozilla build system will generate
+     an XPI that we can pull binary XPCOM components out of.  --> 
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>JSWeakRef-components@labs.mozilla.com</em:id>
+    <em:version>0.1</em:version>
+    <em:type>2</em:type>
+
+    <!-- Target Application this extension can install into, 
+         with minimum and maximum supported versions. --> 
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>3.0</em:minVersion>
+        <em:maxVersion>3.0.9</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+   
+    <!-- Front End MetaData -->
+    <em:name>JSWeakRef Components</em:name>
+    <em:description>Binary XPCOM components for JSWeakRef</em:description>
+    <em:creator>Mozilla Corporation</em:creator>
+  </Description>
+</RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/public/Makefile.in	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,16 @@
+DEPTH   = ../../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH   = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = JSWeakRef
+XPIDL_MODULE  = JSWeakRef
+
+XPI_NAME = JSWeakRef-components
+
+XPIDLSRCS = nsIJSWeakRef.idl \
+            $(NULL)
+
+include $(topsrcdir)/config/rules.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/public/nsIJSWeakRef.idl	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,8 @@
+#include "nsISupports.idl"
+
+[scriptable, uuid(fc04ea60-17df-11de-8c30-0800200c9a66)]
+interface nsIJSWeakRef : nsISupports
+{
+  void set(/* JSObject param */);
+  /* JSObject param */ void get();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/src/JSWeakRefModule.cpp	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,16 @@
+#include "nsIGenericFactory.h"
+#include "nsJSWeakRef.h"
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSWeakRef)
+
+static nsModuleComponentInfo components[] =
+{
+    {
+        NSJSWEAKREFDI_CLASSNAME,
+        NSJSWEAKREFDI_CID,
+        NSJSWEAKREFDI_CONTRACTID,
+        nsJSWeakRefConstructor,
+    }
+};
+
+NS_IMPL_NSGETMODULE("JSWeakRefModule", components)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/src/Makefile.in	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,39 @@
+DEPTH   = ../../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH   = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+IS_COMPONENT = 1
+MODULE = JSWeakRef
+LIBRARY_NAME = JSWeakRef
+USE_STATIC_LIBS = 1
+#FORCE_SHARED_LIB = 1
+#FORCE_USE_PIC = 1
+
+XPI_NAME = JSWeakRef-components
+
+REQUIRES	= \
+		  xpcom \
+		  string \
+		  js \
+		  xpconnect \
+		  caps \
+		  dom \
+		  $(NULL)
+
+CPPSRCS = nsJSWeakRef.cpp \
+          JSWeakRefModule.cpp \
+          $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+EXTRA_DSO_LDOPTS += \
+    $(MOZ_JS_LIBS) \
+    $(XPCOM_GLUE_LDOPTS) \
+    $(NSPR_LIBS) \
+    $(NULL)
+
+clobber::
+	rm -f $(DIST)/lib/$(LIBRARY_NAME).lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/src/nsJSWeakRef.cpp	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,178 @@
+#include "nsJSWeakRef.h"
+
+#include "jsapi.h"
+#include "nsIXPConnect.h"
+#include "nsAXPCNativeCallContext.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+
+class nsJSWeakRefListNode {
+public:
+  nsJSWeakRef *data;
+  nsJSWeakRefListNode *next;
+};
+
+class nsJSWeakRefImpl {
+public:
+  JSObject *weakRef;
+  JSContext *weakCx;
+  nsJSWeakRefListNode *node;
+};
+
+static nsJSWeakRefListNode *gList;
+static JSGCCallback gOldJSGCCallback;
+
+void processGarbage() {
+  nsJSWeakRefListNode *node = gList;
+  nsJSWeakRefListNode *prevNode = nsnull;
+  nsJSWeakRefListNode *nextNode = nsnull;
+  while (node) {
+    nextNode = node->next;
+    if (node->data) {
+      if (JS_IsAboutToBeFinalized(node->data->impl->weakCx,
+                                  node->data->impl->weakRef)) {
+        // Tell the weak reference holder that its target no longer exists.
+        node->data->impl->weakRef = nsnull;
+        node->data->impl->weakCx = nsnull;
+        node->data->impl->node = nsnull;
+
+        // Delete this node.
+        if (prevNode)
+          prevNode->next = nextNode;
+        else
+          gList = nextNode;
+        delete node;
+      } else
+        // This is our general case; just move on to the next node.
+        prevNode = node;
+    } else {
+      // The weak reference holder went away, so just delete this node.
+      if (prevNode)
+        prevNode->next = nextNode;
+      else
+        gList = nextNode;
+      delete node;
+    }
+    node = nextNode;
+  }
+}
+
+static JSBool XPCCycleCollectGCCallback(JSContext *cx, JSGCStatus status) {
+  if (status == JSGC_MARK_END)
+    processGarbage();
+  return gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;
+}
+
+nsJSWeakRef::nsJSWeakRef()
+{
+  this->impl = new nsJSWeakRefImpl();
+  this->impl->weakRef = nsnull;
+  this->impl->weakCx = nsnull;
+  this->impl->node = nsnull;
+}
+
+nsJSWeakRef::~nsJSWeakRef()
+{
+  if (this->impl->node)
+    // Tell the GC callback to remove our node from the list next time around.
+    this->impl->node->data = nsnull;
+
+  delete this->impl;
+  this->impl = nsnull;
+}
+
+NS_IMETHODIMP nsJSWeakRef::Set()
+{
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIXPConnect> xpc = do_GetService(
+    "@mozilla.org/js/xpc/XPConnect;1",
+    &rv
+  );
+  if (NS_FAILED(rv))
+    return NS_ERROR_FAILURE;
+
+  // get the xpconnect native call context
+  nsAXPCNativeCallContext *cc = nsnull;
+  xpc->GetCurrentNativeCallContext(&cc);
+  if(!cc)
+    return NS_ERROR_FAILURE;
+
+  // Get JSContext of current call
+  JSContext* cx;
+  rv = cc->GetJSContext(&cx);
+  if(NS_FAILED(rv) || !cx)
+    return NS_ERROR_FAILURE;
+
+  // get place for return value
+  jsval *rval = nsnull;
+  rv = cc->GetRetValPtr(&rval);
+  if(NS_FAILED(rv) || !rval)
+    return NS_ERROR_FAILURE;
+
+  // get argc and argv and verify arg count
+  PRUint32 argc;
+  rv = cc->GetArgc(&argc);
+  if(NS_FAILED(rv))
+    return rv;
+
+  if (argc < 1)
+    return NS_ERROR_XPC_NOT_ENOUGH_ARGS;
+
+  jsval *argv;
+  rv = cc->GetArgvPtr(&argv);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!JSVAL_IS_OBJECT(argv[0]))
+    return NS_ERROR_ILLEGAL_VALUE;
+
+  this->impl->weakRef = JSVAL_TO_OBJECT(argv[0]);
+  this->impl->weakCx = cx;
+
+  // Insert a new node at the head of the global list.
+  nsJSWeakRefListNode *newNode = new nsJSWeakRefListNode();
+  newNode->data = this;
+  newNode->next = gList;
+  this->impl->node = newNode;
+  gList = newNode;
+
+  // TODO: Note that this is never removed.
+  if (!gOldJSGCCallback)
+    gOldJSGCCallback = JS_SetGCCallback(cx, XPCCycleCollectGCCallback);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsJSWeakRef::Get()
+{
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIXPConnect> xpc = do_GetService(
+    "@mozilla.org/js/xpc/XPConnect;1",
+    &rv
+  );
+  if (NS_FAILED(rv))
+    return NS_ERROR_FAILURE;
+
+  // get the xpconnect native call context
+  nsAXPCNativeCallContext *cc = nsnull;
+  xpc->GetCurrentNativeCallContext(&cc);
+  if(!cc)
+    return NS_ERROR_FAILURE;
+
+  // get place for return value
+  jsval *rval = nsnull;
+  rv = cc->GetRetValPtr(&rval);
+  if(NS_FAILED(rv) || !rval)
+    return NS_ERROR_FAILURE;
+
+  // TODO: Do we have to increase the reference count of the object
+  // or anything?
+
+  // This automatically is set to JSVAL_NULL if weakRef is nsnull.
+  *rval = OBJECT_TO_JSVAL(this->impl->weakRef);
+  cc->SetReturnValueWasSet(PR_TRUE);
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(nsJSWeakRef, nsIJSWeakRef);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/src/nsJSWeakRef.h	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,28 @@
+#include "nsIJSWeakRef.h"
+
+#define NSJSWEAKREFDI_CONTRACTID "@labs.mozilla.com/jsweakrefdi;1"
+#define NSJSWEAKREFDI_CLASSNAME "nsJSWeakRef"
+#define NSJSWEAKREFDI_CID \
+  {0x32665020, 0x17e1, 0x11de, \
+    { 0x8c, 0x30, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 }}
+
+class nsJSWeakRefImpl;
+
+void processGarbage();
+
+class nsJSWeakRef : public nsIJSWeakRef
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIJSWEAKREF
+
+  nsJSWeakRef();
+
+private:
+  virtual ~nsJSWeakRef();
+  nsJSWeakRefImpl *impl;
+  friend void processGarbage();
+
+protected:
+  /* additional members */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/get_xpcom_info.js	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,5 @@
+var xulr = Components.classes["@mozilla.org/xre/app-info;1"]
+                     .getService(Components.interfaces.nsIXULRuntime);
+
+dump(xulr.OS + "\n");
+dump(xulr.XPCOMABI + "\n");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/manage.py	Thu Apr 16 15:23:22 2009 -0700
@@ -0,0 +1,266 @@
+import os
+import sys
+import xml.dom.minidom
+import subprocess
+import shutil
+import zipfile
+import shutil
+import distutils.dir_util
+from ConfigParser import ConfigParser
+
+# Path to the root of the extension, relative to where this script is
+# located.
+EXT_SUBDIR = "JSWeakRef"
+
+# Full path to xpcshell; if it's not an absolute path, it's assumed
+# to be on the user's PATH.
+g_xpcshell_path = "xpcshell"
+
+g_mydir = os.path.abspath(os.path.split(__import__("__main__").__file__)[0])
+
+def clear_dir(dirname):
+    if os.path.exists(dirname) and os.path.isdir(dirname):
+        shutil.rmtree(dirname)
+
+def find_profile_dir(name):
+    """
+    Given the name of a Firefox profile, attempts to find the absolute
+    path to its directory.  If it can't be found, None is returned.
+    """
+
+    base_path = None
+    if sys.platform == "darwin":
+        base_path = os.path.expanduser(
+            "~/Library/Application Support/Firefox/"
+            )
+    elif sys.platform.startswith("win"):
+        # TODO: This only works on 2000/XP/Vista, not 98/Me.
+        appdata = os.environ["APPDATA"]
+        base_path = os.path.join(appdata, "Mozilla\\Firefox")
+    elif sys.platform == "cygwin":
+        appdata = os.environ["APPDATA"]
+        base_path = os.path.join(appdata, "Mozilla\\Firefox")
+    else:
+        base_path = os.path.expanduser("~/.mozilla/firefox/")
+    inifile = os.path.join(base_path, "profiles.ini")
+    config = ConfigParser()
+    config.read(inifile)
+    profiles = [section for section in config.sections()
+                if section.startswith("Profile")]
+    for profile in profiles:
+        if config.get(profile, "Name") == name:
+            # TODO: Look at IsRelative?
+            path = config.get(profile, "Path")
+            if not os.path.isabs(path):
+                path = os.path.join(base_path, path)
+            print "Found profile '%s' at %s." % (name, path)
+            return path
+    print "Couldn't find a profile called '%s'." % name
+    return None
+
+def get_install_rdf_dom(path_to_extension_root):
+    rdf_path = os.path.join(path_to_extension_root, "install.rdf")
+    rdf = xml.dom.minidom.parse(rdf_path)
+    return rdf
+
+def get_install_rdf_property(path_to_extension_root, property):
+    rdf = get_install_rdf_dom(path_to_extension_root)
+    element = rdf.documentElement.getElementsByTagName(property)[0]
+    return element.firstChild.nodeValue
+
+def run_program(args, **kwargs):
+    retval = subprocess.call(args, **kwargs)
+    if retval:
+        print "Process failed with exit code %d." % retval
+        sys.exit(retval)
+
+def run_python_script(args):
+    run_program([sys.executable] + args)
+
+def get_xpcom_info():
+    cmdline = [
+        os.path.join(os.path.dirname(g_xpcshell_path),
+	             "run-mozilla.sh"),
+        g_xpcshell_path,
+        os.path.join(g_mydir, "get_xpcom_info.js")
+        ]
+    if not os.path.exists(cmdline[0]):
+        cmdline = cmdline[1:]
+    popen = subprocess.Popen(
+        cmdline,
+        stdout = subprocess.PIPE
+        )
+    retval = popen.wait()
+    assert retval == 0
+    os_target, xpcomabi = popen.stdout.read().splitlines()
+    comsd = os.path.join(os.path.dirname(g_xpcshell_path),
+                         "components")
+    return dict(comsd = comsd,
+                os_target = os_target,
+                xpcomabi = xpcomabi)
+
+if __name__ == "__main__":
+    args = sys.argv[1:]
+    if not args:
+        print "usage: %s <command>" % sys.argv[0]
+        print
+        print "'command' can be one of the following:"
+        print
+        print "    try - run Firefox w/ new profile and extension installed"
+        print "    install - install to the given profile"
+        print "    uninstall - uninstall from the given profile"
+        print "    build-xpi - build an xpi of the addon"
+        print "    build-components - build C++ XPCOM components"
+        print
+        sys.exit(1)
+
+    if os.environ.get("OBJDIR"):
+        g_xpcshell_path = os.path.join(os.environ["OBJDIR"],
+                                       "dist", "bin", g_xpcshell_path)
+
+    path_to_extension_root = os.path.join(g_mydir, EXT_SUBDIR)
+
+    cmd = args[0]
+
+    if cmd == "try":
+        import systemtests
+        import jsbridge
+        print ("Starting Firefox with a new profile and "
+               "the extension installed...")
+        moz = jsbridge.start_from_settings(systemtests.settings)
+        print "Firefox started, quit it or press CTRL-C to exit."
+        try:
+            moz.wait()
+        except KeyboardInterrupt:
+            moz.stop()
+        print "Farewell."
+        sys.exit(0)
+    if cmd in ["install", "uninstall"]:
+        if len(args) != 2:
+            print "Attempting to find location of default profile..."
+
+            profile_dir = find_profile_dir("default")
+        else:
+            profile_dir = args[1]
+            if not os.path.exists(profile_dir):
+                print "Attempting to find a profile with the name '%s'." % (
+                    profile_dir
+                    )
+                profile_dir = find_profile_dir(profile_dir)
+
+        if not (profile_dir and os.path.exists(profile_dir) and
+                os.path.isdir(profile_dir)):
+            print "Can't resolve profile directory; aborting."
+            sys.exit(1)
+
+        extension_id = get_install_rdf_property(path_to_extension_root,
+                                                "em:id")
+
+        extension_file = os.path.join(profile_dir,
+                                      "extensions",
+                                      extension_id)
+        files_to_remove = ["compreg.dat",
+                           "xpti.dat"]
+        for filename in files_to_remove:
+            abspath = os.path.join(profile_dir, filename)
+            if os.path.exists(abspath):
+                os.remove(abspath)
+        if os.path.exists(extension_file):
+            if os.path.isdir(extension_file):
+                shutil.rmtree(extension_file)
+            else:
+                os.remove(extension_file)
+        if cmd == "install":
+            #if cygwin, change the path to windows format so firefox can understand it
+            if sys.platform == "cygwin":
+                file = 'cygpath.exe -w ' + path_to_extension_root
+                path_to_extension_root = "".join(os.popen(file).readlines()).replace("\n", " ").rstrip()
+
+            extdir = os.path.dirname(extension_file)
+            if not os.path.exists(extdir):
+                distutils.dir_util.mkpath(extdir)
+            fileobj = open(extension_file, "w")
+            fileobj.write(path_to_extension_root)
+            fileobj.close()
+            print "Extension '%s' installed." % extension_id
+        else:
+            print "Extension '%s' uninstalled." % extension_id
+    elif cmd == "build-xpi":
+        version = get_install_rdf_property(path_to_extension_root,
+                                           "em:version")
+        extname = get_install_rdf_property(path_to_extension_root,
+                                           "em:name").lower()
+        zfname = "%s-%s.xpi" % (extname, version)
+        zf = zipfile.ZipFile(zfname,
+                             "w",
+                             zipfile.ZIP_DEFLATED)
+        for dirpath, dirnames, filenames in os.walk(path_to_extension_root):
+            for filename in filenames:
+                abspath = os.path.join(dirpath, filename)
+                arcpath = abspath[len(path_to_extension_root)+1:]
+                zf.write(abspath, arcpath)
+        print "Created %s." % zfname
+    elif cmd == "build-components":
+        if "TOPSRCDIR" not in os.environ:
+            print ("Please set the TOPSRCDIR environment variable "
+                   "to the root of your mozilla-central checkout. "
+                   "If you're on Windows, this should be a standard "
+                   "Windows-style path, NOT a unix-style path.")
+            sys.exit(1)
+        if "OBJDIR" not in os.environ:
+            print ("Please set the OBJDIR envirionment variable "
+                   "to the root of your objdir. "
+                   "If you're on Windows, this should be a standard "
+                   "Windows-style path, NOT a unix-style path.")
+            sys.exit(1)
+        xpcominfo = get_xpcom_info()
+        topsrcdir = os.environ["TOPSRCDIR"]
+        objdir = os.environ["OBJDIR"]
+        comp_src_dir = os.path.join(g_mydir, "components")
+        rel_dest_dir = os.path.join("browser", "components", "JSWeakRef")
+        comp_dest_dir = os.path.join(topsrcdir, rel_dest_dir)
+        comp_xpi_dir = os.path.join(objdir, "dist", "xpi-stage",
+                                    "JSWeakRef-components", "components")
+        comp_plat_dir = os.path.join(
+            g_mydir, "JSWeakRef", "platform",
+            "%(os_target)s_%(xpcomabi)s" % xpcominfo,
+            "components",
+            )
+
+        clear_dir(comp_dest_dir)
+        clear_dir(comp_xpi_dir)
+        clear_dir(comp_plat_dir)
+
+        shutil.copytree(comp_src_dir, comp_dest_dir)
+
+        # Ensure that these paths are unix-like on Windows.
+	sh_pwd = subprocess.Popen(["sh", "-c", "pwd"],
+                                  cwd=topsrcdir,
+                                  stdout=subprocess.PIPE)
+        sh_pwd.wait()
+        unix_topsrcdir = sh_pwd.stdout.read().strip()
+        unix_rel_dest_dir = rel_dest_dir.replace("\\", "/")
+
+        # We're specifying 'perl' here because we have to for this
+        # to work on Windows.
+        run_program(["perl",
+                     os.path.join(topsrcdir, "build", "autoconf",
+                                  "make-makefile"),
+                     "-t", unix_topsrcdir,
+                     unix_rel_dest_dir],
+                    cwd=objdir)
+        run_program(["make"],
+                    cwd=os.path.join(objdir, rel_dest_dir))
+
+        shutil.copytree(comp_xpi_dir, comp_plat_dir)
+        for filename in os.listdir(comp_xpi_dir):
+            shutil.copy(os.path.join(comp_xpi_dir, filename),
+                        xpcominfo["comsd"])
+
+        for filename in ["compreg.dat", "xpti.dat"]:
+            fullpath = os.path.join(xpcominfo["comsd"], filename)
+            if os.path.exists(fullpath):
+                os.unlink(fullpath)
+    else:
+        print "Unknown command '%s'" % cmd
+        sys.exit(1)