Bug 844183: Uplift Add-on SDK changeset 2bee189e1cb87f5fbe38ce862c8ff35ee0978480
authorDave Townsend <dtownsend@oxymoronical.com>
Fri, 22 Feb 2013 10:22:25 -0800
changeset 129117 ed177b1f7196a62433afaac801fb324ff2644f22
parent 129116 c46476d3892a8669c4e3085c411b61c29c3f8862
child 129118 5c28fd3fd03063829c3f8c1fd74471e5c9917715
push id3582
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 20:50:56 +0000
treeherdermozilla-aurora@400370bbc9fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs844183
milestone22.0a1
Bug 844183: Uplift Add-on SDK changeset 2bee189e1cb87f5fbe38ce862c8ff35ee0978480 https://github.com/mozilla/addon-sdk/compare/bf2c2f609babcea412a2349a431ae6bdbedcf05d...2bee189e1cb87f5fbe38ce862c8ff35ee0978480
addon-sdk/source/LICENSE
addon-sdk/source/README
addon-sdk/source/app-extension/bootstrap.js
addon-sdk/source/bin/integration-scripts/integration-check
addon-sdk/source/data/mofo_logo.SVG
addon-sdk/source/doc/module-source/sdk/tabs.md
addon-sdk/source/doc/module-source/sdk/windows.md
addon-sdk/source/lib/sdk/tabs/common.js
addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
addon-sdk/source/lib/sdk/tabs/utils.js
addon-sdk/source/lib/sdk/windows/firefox.js
addon-sdk/source/lib/sdk/windows/loader.js
addon-sdk/source/lib/sdk/windows/tabs-fennec.js
addon-sdk/source/lib/sdk/windows/tabs-firefox.js
addon-sdk/source/python-lib/cuddlefish/__init__.py
addon-sdk/source/python-lib/cuddlefish/manifest.py
addon-sdk/source/python-lib/cuddlefish/runner.py
addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
addon-sdk/source/python-lib/cuddlefish/xpi.py
addon-sdk/source/test/addons/private-browsing-supported/main.js
addon-sdk/source/test/private-browsing/tabs.js
addon-sdk/source/test/private-browsing/windows.js
addon-sdk/source/test/test-deprecate.js
addon-sdk/source/test/test-private-browsing.js
addon-sdk/source/test/test-tabs-common.js
addon-sdk/source/test/windows/test-firefox-windows.js
--- a/addon-sdk/source/LICENSE
+++ b/addon-sdk/source/LICENSE
@@ -1,30 +1,30 @@
-The files which make up the SDK are developed by Mozilla and licensed
-under the MPL 2.0 (http://mozilla.org/MPL/2.0/), with the exception of the
-components listed below, which are made available by their authors under
-the licenses listed alongside.
-
-syntaxhighlighter
-------------------
-doc/static-files/syntaxhighlighter
-Made available under the MIT license.
-
-jQuery
-------
-examples/reddit-panel/data/jquery-1.4.4.min.js
-examples/annotator/data/jquery-1.4.2.min.js
-Made available under the MIT license.
-
-simplejson
-----------
-python-lib/simplejson
-Made available under the MIT license.
-
-Python Markdown
----------------
-python-lib/markdown
-Made available under the BSD license.
-
-LibraryDetector
----------------
-examples/library-detector/data/library-detector.js
-Made available under the MIT license.
+The files which make up the SDK are developed by Mozilla and licensed
+under the MPL 2.0 (http://mozilla.org/MPL/2.0/), with the exception of the
+components listed below, which are made available by their authors under
+the licenses listed alongside.
+
+syntaxhighlighter
+------------------
+doc/static-files/syntaxhighlighter
+Made available under the MIT license.
+
+jQuery
+------
+examples/reddit-panel/data/jquery-1.4.4.min.js
+examples/annotator/data/jquery-1.4.2.min.js
+Made available under the MIT license.
+
+simplejson
+----------
+python-lib/simplejson
+Made available under the MIT license.
+
+Python Markdown
+---------------
+python-lib/markdown
+Made available under the BSD license.
+
+LibraryDetector
+---------------
+examples/library-detector/data/library-detector.js
+Made available under the MIT license.
--- a/addon-sdk/source/README
+++ b/addon-sdk/source/README
@@ -1,45 +1,45 @@
-Add-on SDK README
-==================
-
-Before proceeding, please make sure you've installed Python 2.5,
-2.6, or 2.7 (if it's not already on your system):
-
-  http://python.org/download/
-
-Note that Python 3.0 and 3.1 are not supported in this release.
-
-For Windows users, MozillaBuild (https://wiki.mozilla.org/MozillaBuild)
-will install the correct version of Python and the MSYS package, which
-will make it easier to work with the SDK.
-
-To get started, first enter the same directory that this README file
-is in (the SDK's root directory) using a shell program. On Unix systems
-or on Windows with MSYS, you can execute the following command:
-
-  source bin/activate
-
-Windows users using cmd.exe should instead run:
-
-  bin\activate.bat
-
-Then run:
-
-  cfx docs
-
-This should start a documentation server and open a web browser
-with further instructions.
-
-If you get an error when running cfx or have any other problems getting
-started, see the "Troubleshooting" guide at:
-https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/tutorials/troubleshooting.html
-
-Bugs
--------
-
-* file a bug: https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK
-
-
-Style Guidelines
---------------------
-
+Add-on SDK README
+==================
+
+Before proceeding, please make sure you've installed Python 2.5,
+2.6, or 2.7 (if it's not already on your system):
+
+  http://python.org/download/
+
+Note that Python 3.0 and 3.1 are not supported in this release.
+
+For Windows users, MozillaBuild (https://wiki.mozilla.org/MozillaBuild)
+will install the correct version of Python and the MSYS package, which
+will make it easier to work with the SDK.
+
+To get started, first enter the same directory that this README file
+is in (the SDK's root directory) using a shell program. On Unix systems
+or on Windows with MSYS, you can execute the following command:
+
+  source bin/activate
+
+Windows users using cmd.exe should instead run:
+
+  bin\activate.bat
+
+Then run:
+
+  cfx docs
+
+This should start a documentation server and open a web browser
+with further instructions.
+
+If you get an error when running cfx or have any other problems getting
+started, see the "Troubleshooting" guide at:
+https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/tutorials/troubleshooting.html
+
+Bugs
+-------
+
+* file a bug: https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK
+
+
+Style Guidelines
+--------------------
+
 * https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -14,16 +14,23 @@ const { classes: Cc, Constructor: CC, in
         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 systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
 const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
                      getService(Ci.mozIJSSubScriptLoader);
+const prefService = Cc['@mozilla.org/preferences-service;1'].
+                    getService(Ci.nsIPrefService);
+const appInfo = Cc["@mozilla.org/xre/app-info;1"].
+                getService(Ci.nsIXULAppInfo);
+const vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
+           getService(Ci.nsIVersionComparator);
+
 
 const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
                  'install', 'uninstall', 'upgrade', 'downgrade' ];
 
 const bind = Function.call.bind(Function.bind);
 
 let loader = null;
 let unload = null;
@@ -115,29 +122,64 @@ function startup(data, reasonCode) {
       return result;
     }, paths);
 
     // We need to map tests folder when we run sdk tests whose package name
     // is stripped
     if (name == 'addon-sdk')
       paths['tests/'] = prefixURI + name + '/tests/';
 
-    // Maps sdk module folders to their resource folder
-    paths['sdk/'] = prefixURI + 'addon-sdk/lib/sdk/';
-    paths['toolkit/'] = prefixURI + 'addon-sdk/lib/toolkit/';
-    // test.js is usually found in root commonjs or SDK_ROOT/lib/ folder,
-    // so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder
-    // until we no longer support SDK modules in XPI:
-    paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js';
+    // Starting with Firefox 21.0a1, we start using modules shipped into firefox
+    // Still allow using modules from the xpi if the manifest tell us to do so.
+    // And only try to look for sdk modules in xpi if the xpi actually ship them
+    if (options['is-sdk-bundled'] &&
+        (vc.compare(appInfo.version, '21.0a1') < 0 ||
+         options['force-use-bundled-sdk'])) {
+      // Maps sdk module folders to their resource folder
+      paths[''] = prefixURI + 'addon-sdk/lib/';
+      // test.js is usually found in root commonjs or SDK_ROOT/lib/ folder,
+      // so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder
+      // until we no longer support SDK modules in XPI:
+      paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js';
+    }
+
+    // Retrieve list of module folder overloads based on preferences in order to
+    // eventually used a local modules instead of files shipped into Firefox.
+    let branch = prefService.getBranch('extensions.modules.' + id + '.path');
+    paths = branch.getChildList('', {}).reduce(function (result, name) {
+      // Allows overloading of any sub folder by replacing . by / in pref name
+      let path = name.substr(1).split('.').join('/');
+      // Only accept overloading folder by ensuring always ending with `/`
+      if (path) path += '/';
+      let fileURI = branch.getCharPref(name);
+
+      // Maps the given file:// URI to a resource:// in order to avoid various
+      // failure that happens with file:// URI and be close to production env
+      let resourcesURI = ioService.newURI(fileURI, null, null);
+      let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
+      resourceHandler.setSubstitution(resName, resourcesURI);
+
+      result[path] = 'resource://' + resName + '/';
+      return result;
+    }, paths);
 
     // Make version 2 of the manifest
     let manifest = options.manifest;
 
     // Import `cuddlefish.js` module using a Sandbox and bootstrap loader.
-    let cuddlefishURI = prefixURI + options.loader;
+    let cuddlefishPath = 'loader/cuddlefish.js';
+    let cuddlefishURI = 'resource://gre/modules/commonjs/sdk/' + cuddlefishPath;
+    if (paths['sdk/']) { // sdk folder has been overloaded
+                         // (from pref, or cuddlefish is still in the xpi)
+      cuddlefishURI = paths['sdk/'] + cuddlefishPath;
+    }
+    else if (paths['']) { // root modules folder has been overloaded
+      cuddlefishURI = paths[''] + 'sdk/' + cuddlefishPath;
+    }
+
     cuddlefishSandbox = loadSandbox(cuddlefishURI);
     let cuddlefish = cuddlefishSandbox.exports;
 
     // Normalize `options.mainPath` so that it looks like one that will come
     // in a new version of linker.
     let main = options.mainPath;
 
     unload = cuddlefish.unload;
--- a/addon-sdk/source/bin/integration-scripts/integration-check
+++ b/addon-sdk/source/bin/integration-scripts/integration-check
@@ -1,364 +1,364 @@
-#!/usr/bin/env python
-# 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 signal
-import threading
-import urllib2, urllib
-import zipfile
-import tarfile
-import subprocess
-import optparse
-import sys, re
-#import win32api
-
-
-class SDK:
-    def __init__(self):
-        try:
-            # Take the current working directory
-            self.default_path = os.getcwd()
-            if sys.platform == "win32":
-                self.mswindows = True
-            else:
-                self.mswindows = False
-            # Take the default home path of the user.
-            home = os.path.expanduser('~')
-
-            # The following are the parameters that can be used to pass a dynamic URL, a specific path or a binry. The binary is not used yet. It will be used in version 2.0
-            # If a dynamic path is to be mentioned, it should start with a '/'. For eg. "/Desktop"
-            parser = optparse.OptionParser()
-            parser.add_option('-u', '--url', dest = 'url', default = 'https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/addon-sdk-latest.zip')
-            parser.add_option('-p', '--path', dest = 'path', default = self.default_path)
-            parser.add_option('-b', '--binary', dest = 'binary')#, default='/Applications/Firefox.app')
-            (options, args) = parser.parse_args()
-      
-            # Get the URL from the parameter
-            self.link = options.url
-            # Set the base path for the user. If the user supplies the path, use the home variable as well. Else, take the default path of this script as the installation directory.
-            if options.path!=self.default_path:
-                if self.mswindows:
-                    self.base_path = home + str(options.path).strip() + '\\'
-                else:
-                    self.base_path = home + str(options.path).strip() + '/'
-            else:
-                if self.mswindows:
-                    self.base_path = str(options.path).strip() + '\\'
-                else:
-                    self.base_path = str(options.path).strip() + '/'
-            assert ' ' not in self.base_path, "You cannot have a space in your home path. Please remove the space before you continue."
-            print('Your Base path is =' + self.base_path)
-            
-            # This assignment is not used in this program. It will be used in version 2 of this script.
-            self.bin = options.binary
-            # if app or bin is empty, dont pass anything
-    
-            # Search for the .zip file or tarball file in the URL.
-            i = self.link.rfind('/')
-
-            self.fname = self.link[i+1:]
-            z = re.search('zip',self.fname,re.I)
-            g = re.search('gz',self.fname,re.I)
-            if z:
-                print 'zip file present in the URL.'
-                self.zip = True
-                self.gz = False
-            elif g:
-                print 'gz file present in the URL'
-                self.gz = True
-                self.zip = False
-            else:
-                print 'zip/gz file not present. Check the URL.'
-                return
-            print("File name is =" + self.fname)
-    
-            # Join the base path and the zip/tar file name to crate a complete Local file path.
-            self.fpath = self.base_path + self.fname
-            print('Your local file path will be=' + self.fpath)
-        except AssertionError, e:
-            print e.args[0] 
-            sys.exit(1)
-
-    # Download function - to download the SDK from the URL to the local machine.
-    def download(self,url,fpath,fname):
-        try:
-            # Start the download
-            print("Downloading...Please be patient!")
-            urllib.urlretrieve(url,filename = fname)
-            print('Download was successful.')
-        except ValueError: # Handles broken URL errors.
-            print 'The URL is ether broken or the file does not exist. Please enter the correct URL.'
-            raise
-        except urllib2.URLError: # Handles URL errors
-            print '\nURL not correct. Check again!'
-            raise
-
-    # Function to extract the downloaded zipfile.
-    def extract(self, zipfilepath, extfile):
-        try:
-            # Timeout is set to 30 seconds. 
-            timeout = 30
-            # Change the directory to the location of the zip file.
-            try:
-                os.chdir(zipfilepath)
-            except OSError:
-             # Will reach here if zip file doesnt exist
-                 print 'O/S Error:' + zipfilepath + 'does not exist'
-                 raise
-
-            # Get the folder name of Jetpack to get the exact version number.
-            if self.zip:
-                try:
-                    f = zipfile.ZipFile(extfile, "r")
-                except IOError as (errno, strerror): # Handles file errors
-                    print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
-                    raise
-                list = f.namelist()[0]
-                temp_name = list.split('/')
-                print('Folder Name= ' +temp_name[0])
-                self.folder_name = temp_name[0]
-            elif self.gz:
-                try:
-                    f = tarfile.open(extfile,'r')
-                except IOError as (errno, strerror): # Handles file errors
-                    print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
-                    raise
-                list = f.getnames()[0]
-                temp_name = list.split('/')
-                print('Folder Name= ' +temp_name[0])
-                self.folder_name = temp_name[0]
-
-            print ('Starting to Extract...')
-
-            # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
-            # timeout, the process is killed.
-            kill_check = threading.Event()
-            
-            if self.zip:
-            # Call the command to unzip the file.
-                if self.mswindows:
-                    zipfile.ZipFile.extractall(f)
-                else:
-                    p = subprocess.Popen('unzip '+extfile, stdout=subprocess.PIPE, shell=True)
-                    pid = p.pid
-            elif self.gz:
-            # Call the command to untar the file.
-                if self.mswindows:
-                    tarfile.TarFile.extractall(f)
-                else:
-                    p = subprocess.Popen('tar -xf '+extfile, stdout=subprocess.PIPE, shell=True)
-                    pid = p.pid
-            
-            #No need to handle for windows because windows automatically replaces old files with new files. It does not ask the user(as it does in Mac/Unix)
-            if self.mswindows==False:
-                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows ))
-                watch.start()
-                (stdout, stderr) = p.communicate()
-                watch.cancel() # if it's still waiting to run
-                success = not kill_check.isSet()
-    
-                # Abort process if process fails.
-                if not success:
-                    raise RuntimeError
-                kill_check.clear()
-            print('Extraction Successful.')
-        except RuntimeError:
-            print "Ending the program"
-            sys.exit(1)
-        except:
-            print "Error during file extraction: ", sys.exc_info()[0]
-            raise
-
-    # Function to run the cfx testall comands and to make sure the SDK is not broken.
-    def run_testall(self, home_path, folder_name):
-        try:
-            timeout = 500
-
-            self.new_dir = home_path + folder_name
-            try:
-                os.chdir(self.new_dir)
-            except OSError:
-             # Will reach here if the jetpack 0.X directory doesnt exist
-                print 'O/S Error: Jetpack directory does not exist at ' + self.new_dir
-                raise
-            print '\nStarting tests...'
-            # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
-            # timeout, the process is killed.
-            kill_check = threading.Event()
-
-            # Set the path for the logs. They will be in the parent directory of the Jetpack SDK.
-            log_path = home_path + 'tests.log'
-
-            # Subprocess call to set up the jetpack environment and to start the tests. Also sends the output to a log file.
-            if self.bin != None:
-                if self.mswindows:
-                    p = subprocess.Popen("bin\\activate && cfx testall -a firefox -b \"" + self.bin + "\"" , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    proc_handle = p._handle
-                    (stdout,stderr) = p.communicate()
-                else:
-                    p = subprocess.Popen('. bin/activate; cfx testall -a firefox -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    pid = p.pid
-                    (stdout,stderr) = p.communicate()
-            elif self.bin == None:
-                if self.mswindows:
-                    p=subprocess.Popen('bin\\activate && cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    proc_handle = p._handle
-                    (stdout,stderr) = p.communicate()
-                else:
-                    p = subprocess.Popen('. bin/activate; cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    pid = p.pid
-                    (stdout,stderr) = p.communicate()
-                    
-            #Write the output to log file
-            f=open(log_path,"w")
-            f.write(stdout+stderr)
-            f.close()
-
-            #Watchdog for timeout process
-            if self.mswindows:
-                watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
-            else:
-                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
-            watch.start()
-            watch.cancel() # if it's still waiting to run
-            success = not kill_check.isSet()
-            if not success:
-                raise RuntimeError
-            kill_check.clear()
-        
-            if p.returncode!=0:
-                print('\nAll tests were not successful. Check the test-logs in the jetpack directory.')
-                result_sdk(home_path)
-                #sys.exit(1)
-                raise RuntimeError
-            else:
-                ret_code=result_sdk(home_path)
-                if ret_code==0:
-                    print('\nAll tests were successful. Yay \o/ . Running a sample package test now...')
-                else:
-                    print ('\nThere were errors during the tests.Take a look at logs')
-                    raise RuntimeError
-        except RuntimeError:
-            print "Ending the program"
-            sys.exit(1)
-        except:
-            print "Error during the testall command execution:", sys.exc_info()[0]
-            raise
-        
-    def package(self, example_dir):
-        try:
-            timeout = 30
-    
-            print '\nNow Running packaging tests...'
-    
-            kill_check = threading.Event()
-
-            # Set the path for the example logs. They will be in the parent directory of the Jetpack SDK.
-            exlog_path = example_dir + 'test-example.log'
-            # Subprocess call to test the sample example for packaging.
-            if self.bin!=None:
-                if self.mswindows:
-                    p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data  --static-args="{\\"quitWhenDone\\":true}" -b \"" + self.bin + "\"' , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    proc_handle = p._handle
-                    (stdout, stderr) = p.communicate()
-                else:
-                    p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data  --static-args=\'{\"quitWhenDone\":true}\' -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    pid = p.pid
-                    (stdout, stderr) = p.communicate()
-            elif self.bin==None:
-                if self.mswindows:
-                    p = subprocess.Popen('bin\\activate && cfx run  --pkgdir examples\\reading-data --static-args="{\\"quitWhenDone\\":true}"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    proc_handle = p._handle
-                    (stdout, stderr) = p.communicate()
-                else:
-                    p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' ', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
-                    pid = p.pid
-                    (stdout, stderr) = p.communicate()
-            
-            #Write the output to log file
-            f=open(exlog_path,"w")
-            f.write(stdout+stderr)
-            f.close()
-            
-            #Watch dog for timeout process
-            if self.mswindows:
-                watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
-            else:
-                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
-            watch.start()
-            watch.cancel() # if it's still waiting to run
-            success = not kill_check.isSet()
-            if not success:
-                raise RuntimeError
-            kill_check.clear()
-
-            if p.returncode != 0:
-                print('\nSample tests were not executed correctly. Check the test-example log in jetpack diretory.')
-                result_example(example_dir)
-                raise RuntimeError
-            else:
-                ret_code=result_example(example_dir)
-                if ret_code==0:
-                    print('\nAll tests pass. The SDK is working! Yay \o/')
-                else:
-                    print ('\nTests passed with warning.Take a look at logs')
-                    sys.exit(1)
-        
-        except RuntimeError:
-            print "Ending program"
-            sys.exit(1)
-        except:
-            print "Error during running sample tests:", sys.exc_info()[0]
-            raise
-    
-def result_sdk(sdk_dir):
-    log_path = sdk_dir + 'tests.log'
-    print 'Results are logged at:' + log_path
-    try:
-        f = open(log_path,'r')
-    # Handles file errors
-    except IOError : 
-        print 'I/O error - Cannot open test log at ' + log_path
-        raise
-
-    for line in reversed(open(log_path).readlines()):
-        if line.strip()=='FAIL':
-            print ('\nOverall result - FAIL. Look at the test log at '+log_path)
-            return 1
-    return 0
-    
-
-def result_example(sdk_dir):
-    exlog_path = sdk_dir + 'test-example.log'
-    print 'Sample test results are logged at:' + exlog_path
-    try:
-        f = open(exlog_path,'r')
-    # Handles file errors
-    except IOError : 
-        print 'I/O error - Cannot open sample test log at ' + exlog_path
-        raise
-    
-    #Read the file in reverse and check for the keyword 'FAIL'.
-    for line in reversed(open(exlog_path).readlines()):
-        if line.strip()=='FAIL':
-            print ('\nOverall result for Sample tests - FAIL. Look at the test log at '+exlog_path)
-            return 1
-    return 0
-
-def kill_process(process, kill_check, mswindows):
-    print '\nProcess Timedout. Killing the process. Please Rerun this script.'
-    if mswindows:
-        win32api.TerminateProcess(process, -1)
-    else:
-        os.kill(process, signal.SIGKILL)
-    kill_check.set()# tell the main routine to kill. Used SIGKILL to hard kill the process.
-    return
-
-if __name__ == "__main__":
-    obj = SDK()
-    obj.download(obj.link,obj.fpath,obj.fname)
-    obj.extract(obj.base_path,obj.fname)
-    obj.run_testall(obj.base_path,obj.folder_name)
-    obj.package(obj.base_path)
+#!/usr/bin/env python
+# 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 signal
+import threading
+import urllib2, urllib
+import zipfile
+import tarfile
+import subprocess
+import optparse
+import sys, re
+#import win32api
+
+
+class SDK:
+    def __init__(self):
+        try:
+            # Take the current working directory
+            self.default_path = os.getcwd()
+            if sys.platform == "win32":
+                self.mswindows = True
+            else:
+                self.mswindows = False
+            # Take the default home path of the user.
+            home = os.path.expanduser('~')
+
+            # The following are the parameters that can be used to pass a dynamic URL, a specific path or a binry. The binary is not used yet. It will be used in version 2.0
+            # If a dynamic path is to be mentioned, it should start with a '/'. For eg. "/Desktop"
+            parser = optparse.OptionParser()
+            parser.add_option('-u', '--url', dest = 'url', default = 'https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/addon-sdk-latest.zip')
+            parser.add_option('-p', '--path', dest = 'path', default = self.default_path)
+            parser.add_option('-b', '--binary', dest = 'binary')#, default='/Applications/Firefox.app')
+            (options, args) = parser.parse_args()
+      
+            # Get the URL from the parameter
+            self.link = options.url
+            # Set the base path for the user. If the user supplies the path, use the home variable as well. Else, take the default path of this script as the installation directory.
+            if options.path!=self.default_path:
+                if self.mswindows:
+                    self.base_path = home + str(options.path).strip() + '\\'
+                else:
+                    self.base_path = home + str(options.path).strip() + '/'
+            else:
+                if self.mswindows:
+                    self.base_path = str(options.path).strip() + '\\'
+                else:
+                    self.base_path = str(options.path).strip() + '/'
+            assert ' ' not in self.base_path, "You cannot have a space in your home path. Please remove the space before you continue."
+            print('Your Base path is =' + self.base_path)
+            
+            # This assignment is not used in this program. It will be used in version 2 of this script.
+            self.bin = options.binary
+            # if app or bin is empty, dont pass anything
+    
+            # Search for the .zip file or tarball file in the URL.
+            i = self.link.rfind('/')
+
+            self.fname = self.link[i+1:]
+            z = re.search('zip',self.fname,re.I)
+            g = re.search('gz',self.fname,re.I)
+            if z:
+                print 'zip file present in the URL.'
+                self.zip = True
+                self.gz = False
+            elif g:
+                print 'gz file present in the URL'
+                self.gz = True
+                self.zip = False
+            else:
+                print 'zip/gz file not present. Check the URL.'
+                return
+            print("File name is =" + self.fname)
+    
+            # Join the base path and the zip/tar file name to crate a complete Local file path.
+            self.fpath = self.base_path + self.fname
+            print('Your local file path will be=' + self.fpath)
+        except AssertionError, e:
+            print e.args[0] 
+            sys.exit(1)
+
+    # Download function - to download the SDK from the URL to the local machine.
+    def download(self,url,fpath,fname):
+        try:
+            # Start the download
+            print("Downloading...Please be patient!")
+            urllib.urlretrieve(url,filename = fname)
+            print('Download was successful.')
+        except ValueError: # Handles broken URL errors.
+            print 'The URL is ether broken or the file does not exist. Please enter the correct URL.'
+            raise
+        except urllib2.URLError: # Handles URL errors
+            print '\nURL not correct. Check again!'
+            raise
+
+    # Function to extract the downloaded zipfile.
+    def extract(self, zipfilepath, extfile):
+        try:
+            # Timeout is set to 30 seconds. 
+            timeout = 30
+            # Change the directory to the location of the zip file.
+            try:
+                os.chdir(zipfilepath)
+            except OSError:
+             # Will reach here if zip file doesnt exist
+                 print 'O/S Error:' + zipfilepath + 'does not exist'
+                 raise
+
+            # Get the folder name of Jetpack to get the exact version number.
+            if self.zip:
+                try:
+                    f = zipfile.ZipFile(extfile, "r")
+                except IOError as (errno, strerror): # Handles file errors
+                    print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
+                    raise
+                list = f.namelist()[0]
+                temp_name = list.split('/')
+                print('Folder Name= ' +temp_name[0])
+                self.folder_name = temp_name[0]
+            elif self.gz:
+                try:
+                    f = tarfile.open(extfile,'r')
+                except IOError as (errno, strerror): # Handles file errors
+                    print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
+                    raise
+                list = f.getnames()[0]
+                temp_name = list.split('/')
+                print('Folder Name= ' +temp_name[0])
+                self.folder_name = temp_name[0]
+
+            print ('Starting to Extract...')
+
+            # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
+            # timeout, the process is killed.
+            kill_check = threading.Event()
+            
+            if self.zip:
+            # Call the command to unzip the file.
+                if self.mswindows:
+                    zipfile.ZipFile.extractall(f)
+                else:
+                    p = subprocess.Popen('unzip '+extfile, stdout=subprocess.PIPE, shell=True)
+                    pid = p.pid
+            elif self.gz:
+            # Call the command to untar the file.
+                if self.mswindows:
+                    tarfile.TarFile.extractall(f)
+                else:
+                    p = subprocess.Popen('tar -xf '+extfile, stdout=subprocess.PIPE, shell=True)
+                    pid = p.pid
+            
+            #No need to handle for windows because windows automatically replaces old files with new files. It does not ask the user(as it does in Mac/Unix)
+            if self.mswindows==False:
+                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows ))
+                watch.start()
+                (stdout, stderr) = p.communicate()
+                watch.cancel() # if it's still waiting to run
+                success = not kill_check.isSet()
+    
+                # Abort process if process fails.
+                if not success:
+                    raise RuntimeError
+                kill_check.clear()
+            print('Extraction Successful.')
+        except RuntimeError:
+            print "Ending the program"
+            sys.exit(1)
+        except:
+            print "Error during file extraction: ", sys.exc_info()[0]
+            raise
+
+    # Function to run the cfx testall comands and to make sure the SDK is not broken.
+    def run_testall(self, home_path, folder_name):
+        try:
+            timeout = 500
+
+            self.new_dir = home_path + folder_name
+            try:
+                os.chdir(self.new_dir)
+            except OSError:
+             # Will reach here if the jetpack 0.X directory doesnt exist
+                print 'O/S Error: Jetpack directory does not exist at ' + self.new_dir
+                raise
+            print '\nStarting tests...'
+            # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
+            # timeout, the process is killed.
+            kill_check = threading.Event()
+
+            # Set the path for the logs. They will be in the parent directory of the Jetpack SDK.
+            log_path = home_path + 'tests.log'
+
+            # Subprocess call to set up the jetpack environment and to start the tests. Also sends the output to a log file.
+            if self.bin != None:
+                if self.mswindows:
+                    p = subprocess.Popen("bin\\activate && cfx testall -a firefox -b \"" + self.bin + "\"" , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    proc_handle = p._handle
+                    (stdout,stderr) = p.communicate()
+                else:
+                    p = subprocess.Popen('. bin/activate; cfx testall -a firefox -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    pid = p.pid
+                    (stdout,stderr) = p.communicate()
+            elif self.bin == None:
+                if self.mswindows:
+                    p=subprocess.Popen('bin\\activate && cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    proc_handle = p._handle
+                    (stdout,stderr) = p.communicate()
+                else:
+                    p = subprocess.Popen('. bin/activate; cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    pid = p.pid
+                    (stdout,stderr) = p.communicate()
+                    
+            #Write the output to log file
+            f=open(log_path,"w")
+            f.write(stdout+stderr)
+            f.close()
+
+            #Watchdog for timeout process
+            if self.mswindows:
+                watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
+            else:
+                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
+            watch.start()
+            watch.cancel() # if it's still waiting to run
+            success = not kill_check.isSet()
+            if not success:
+                raise RuntimeError
+            kill_check.clear()
+        
+            if p.returncode!=0:
+                print('\nAll tests were not successful. Check the test-logs in the jetpack directory.')
+                result_sdk(home_path)
+                #sys.exit(1)
+                raise RuntimeError
+            else:
+                ret_code=result_sdk(home_path)
+                if ret_code==0:
+                    print('\nAll tests were successful. Yay \o/ . Running a sample package test now...')
+                else:
+                    print ('\nThere were errors during the tests.Take a look at logs')
+                    raise RuntimeError
+        except RuntimeError:
+            print "Ending the program"
+            sys.exit(1)
+        except:
+            print "Error during the testall command execution:", sys.exc_info()[0]
+            raise
+        
+    def package(self, example_dir):
+        try:
+            timeout = 30
+    
+            print '\nNow Running packaging tests...'
+    
+            kill_check = threading.Event()
+
+            # Set the path for the example logs. They will be in the parent directory of the Jetpack SDK.
+            exlog_path = example_dir + 'test-example.log'
+            # Subprocess call to test the sample example for packaging.
+            if self.bin!=None:
+                if self.mswindows:
+                    p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data  --static-args="{\\"quitWhenDone\\":true}" -b \"" + self.bin + "\"' , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    proc_handle = p._handle
+                    (stdout, stderr) = p.communicate()
+                else:
+                    p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data  --static-args=\'{\"quitWhenDone\":true}\' -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    pid = p.pid
+                    (stdout, stderr) = p.communicate()
+            elif self.bin==None:
+                if self.mswindows:
+                    p = subprocess.Popen('bin\\activate && cfx run  --pkgdir examples\\reading-data --static-args="{\\"quitWhenDone\\":true}"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    proc_handle = p._handle
+                    (stdout, stderr) = p.communicate()
+                else:
+                    p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' ', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+                    pid = p.pid
+                    (stdout, stderr) = p.communicate()
+            
+            #Write the output to log file
+            f=open(exlog_path,"w")
+            f.write(stdout+stderr)
+            f.close()
+            
+            #Watch dog for timeout process
+            if self.mswindows:
+                watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
+            else:
+                watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
+            watch.start()
+            watch.cancel() # if it's still waiting to run
+            success = not kill_check.isSet()
+            if not success:
+                raise RuntimeError
+            kill_check.clear()
+
+            if p.returncode != 0:
+                print('\nSample tests were not executed correctly. Check the test-example log in jetpack diretory.')
+                result_example(example_dir)
+                raise RuntimeError
+            else:
+                ret_code=result_example(example_dir)
+                if ret_code==0:
+                    print('\nAll tests pass. The SDK is working! Yay \o/')
+                else:
+                    print ('\nTests passed with warning.Take a look at logs')
+                    sys.exit(1)
+        
+        except RuntimeError:
+            print "Ending program"
+            sys.exit(1)
+        except:
+            print "Error during running sample tests:", sys.exc_info()[0]
+            raise
+    
+def result_sdk(sdk_dir):
+    log_path = sdk_dir + 'tests.log'
+    print 'Results are logged at:' + log_path
+    try:
+        f = open(log_path,'r')
+    # Handles file errors
+    except IOError : 
+        print 'I/O error - Cannot open test log at ' + log_path
+        raise
+
+    for line in reversed(open(log_path).readlines()):
+        if line.strip()=='FAIL':
+            print ('\nOverall result - FAIL. Look at the test log at '+log_path)
+            return 1
+    return 0
+    
+
+def result_example(sdk_dir):
+    exlog_path = sdk_dir + 'test-example.log'
+    print 'Sample test results are logged at:' + exlog_path
+    try:
+        f = open(exlog_path,'r')
+    # Handles file errors
+    except IOError : 
+        print 'I/O error - Cannot open sample test log at ' + exlog_path
+        raise
+    
+    #Read the file in reverse and check for the keyword 'FAIL'.
+    for line in reversed(open(exlog_path).readlines()):
+        if line.strip()=='FAIL':
+            print ('\nOverall result for Sample tests - FAIL. Look at the test log at '+exlog_path)
+            return 1
+    return 0
+
+def kill_process(process, kill_check, mswindows):
+    print '\nProcess Timedout. Killing the process. Please Rerun this script.'
+    if mswindows:
+        win32api.TerminateProcess(process, -1)
+    else:
+        os.kill(process, signal.SIGKILL)
+    kill_check.set()# tell the main routine to kill. Used SIGKILL to hard kill the process.
+    return
+
+if __name__ == "__main__":
+    obj = SDK()
+    obj.download(obj.link,obj.fpath,obj.fname)
+    obj.extract(obj.base_path,obj.fname)
+    obj.run_testall(obj.base_path,obj.folder_name)
+    obj.package(obj.base_path)
--- a/addon-sdk/source/data/mofo_logo.SVG
+++ b/addon-sdk/source/data/mofo_logo.SVG
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
-	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
-	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
+	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
 ]>
 <svg version="1.1" id="svg2997" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="-0.5 -0.5 200 200" overflow="visible" enable-background="new -0.5 -0.5 200 200" xml:space="preserve">
 <path id="path85" fill="#FFFFFF" d="M-2559.936,6359.65c19.127,26.489,46.371,47.744,80.988,44.707  C-2479.339,6371.648-2523.898,6352.641-2559.936,6359.65z"/>
 <path id="path93" fill="#FFFFFF" d="M-2634.014,6073.506c4.082-7.232,2.571-17.81,3.831-26.684  c-9.019,4.635-15.506,14.72-24.551,18.641C-2652.134,6070.818-2640.447,6070.829-2634.014,6073.506z"/>
 <path id="path95" fill="#FFFFFF" d="M-2687.179,6018.109l-18.654,18.212c4.158,3.301,9.676,8.132,17.11,6.36L-2687.179,6018.109z"/>
 <path id="path97" fill="#FFFFFF" d="M-2731.117,5998.391c-4.356-0.363-14.41,20.156-18.785,19.857l14.762,8.728  C-2730.055,6027.281-2732.816,6001.961-2731.117,5998.391L-2731.117,5998.391z"/>
 <path id="path99" fill="#FFFFFF" d="M-2776.505,5989.09l4.736-11.668c-10.245,0.813-15.511,20.68-21.719,26.244  C-2776.37,6007.109-2775.727,6011.81-2776.505,5989.09z"/>
 <path id="path101" fill="#FFFFFF" d="M-2825.16,5962.186l-18.405,31.539l17.091,3.962L-2825.16,5962.186L-2825.16,5962.186z"/>
--- a/addon-sdk/source/doc/module-source/sdk/tabs.md
+++ b/addon-sdk/source/doc/module-source/sdk/tabs.md
@@ -134,16 +134,21 @@ This is a required property.
 @prop [inNewWindow] {boolean}
 If present and true, a new browser window will be opened and the URL will be
 opened in the first tab in that window. This is an optional property.
 
 @prop [inBackground] {boolean}
 If present and true, the new tab will be opened to the right of the active tab
 and will not be active. This is an optional property.
 
+@prop isPrivate {boolean}
+Boolean which will determine if a private tab should be opened.
+Private browsing mode must be supported in order to do this.
+See the [private-browsing](modules/sdk/private-browsing.html) documentation for more information.
+
 @prop [isPinned] {boolean}
 If present and true, then the new tab will be pinned as an
 [app tab](http://support.mozilla.com/en-US/kb/what-are-app-tabs).
 
 @prop [onOpen] {function}
 A callback function that will be registered for 'open' event.
 This is an optional property.
 @prop [onClose] {function}
--- a/addon-sdk/source/doc/module-source/sdk/windows.md
+++ b/addon-sdk/source/doc/module-source/sdk/windows.md
@@ -113,16 +113,21 @@ as well as a callback for being notified
 
 If the only option being used is `url`, then a bare string URL can be passed to
 `open` instead of specifying it as a property of the `options` object.
 
 @prop url {string}
 String URL to be opened in the new window.
 This is a required property.
 
+@prop isPrivate {boolean}
+Boolean which will determine if a private window should be opened.
+Private browsing mode must be supported in order to do this.
+See the [private-browsing](modules/sdk/private-browsing.html) documentation for more information.
+
 @prop [onOpen] {function}
 A callback function that is called when the window has opened. This does not
 mean that the URL content has loaded, only that the window itself is fully
 functional and its properties can be accessed. This is an optional property.
 
 @prop [onClose] {function}
 A callback function that is called when the window will be called.
 This is an optional property.
--- a/addon-sdk/source/lib/sdk/tabs/common.js
+++ b/addon-sdk/source/lib/sdk/tabs/common.js
@@ -8,16 +8,17 @@ const { validateOptions } = require('../
 function Options(options) {
   if ('string' === typeof options)
     options = { url: options };
 
   return validateOptions(options, {
     url: { is: ["string"] },
     inBackground: { is: ["undefined", "boolean"] },
     isPinned: { is: ["undefined", "boolean"] },
+    isPrivate: { is: ["undefined", "boolean"] },
     onOpen: { is: ["undefined", "function"] },
     onClose: { is: ["undefined", "function"] },
     onReady: { is: ["undefined", "function"] },
     onActivate: { is: ["undefined", "function"] },
     onDeactivate: { is: ["undefined", "function"] }
   });
 }
 exports.Options = Options;
--- a/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
+++ b/addon-sdk/source/lib/sdk/tabs/tabs-firefox.js
@@ -1,26 +1,68 @@
 /* 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';
 
 // TODO: BUG 792670 - remove dependency below
-const { browserWindows } = require('../windows');
+const { browserWindows: windows } = require('../windows');
 const { tabs } = require('../windows/tabs-firefox');
+const { isPrivate } = require('../private-browsing');
+const { isWindowPBSupported } = require('../private-browsing/utils')
+const { isPrivateBrowsingSupported } = require('sdk/self');
+
+const supportPrivateTabs = isPrivateBrowsingSupported && isWindowPBSupported;
 
 Object.defineProperties(tabs, {
   open: { value: function open(options) {
-    if (options.inNewWindow)
+    if (options.inNewWindow) {
         // `tabs` option is under review and may be removed.
-        return browserWindows.open({ tabs: [ options ] });
-    // Open in active window if new window was not required.
-    return browserWindows.activeWindow.tabs.open(options);
+        windows.open({
+          tabs: [ options ],
+          isPrivate: options.isPrivate
+        });
+        return undefined;
+    }
+    // Open in active window if new window was not required..
+
+
+    let activeWindow = windows.activeWindow;
+    let privateState = !!options.isPrivate;
+    // if the active window is in the state that we need then use it
+    if (!supportPrivateTabs || privateState === isPrivate(activeWindow)) {
+      activeWindow.tabs.open(options);
+    }
+    else {
+      // find a window in the state that we need
+      let window = getWindow(privateState);
+      if (window) {
+      	window.tabs.open(options);
+      }
+      // open a window in the state that we need
+      else {
+        windows.open({
+          tabs: [ options ],
+          isPrivate: options.isPrivate
+        });
+      }
+    }
+
+    return undefined;
   }}
 });
 
+function getWindow(privateState) {
+  for each (let window in windows) {
+  	if (privateState === isPrivate(window)) {
+  	  return window;
+  	}
+  }
+  return null;
+}
+
 // Workaround for bug 674195. Freezing objects from other compartments fail,
 // so we use `Object.freeze` from the same component as objects
 // `hasOwnProperty`. Since `hasOwnProperty` here will be from other component
 // we override it to support our workaround.
 module.exports = Object.create(tabs, {
   isPrototypeOf: { value: Object.prototype.isPrototypeOf }
 });
--- a/addon-sdk/source/lib/sdk/tabs/utils.js
+++ b/addon-sdk/source/lib/sdk/tabs/utils.js
@@ -97,20 +97,23 @@ function getWindowHoldingTab(rawTab) {
 function openTab(window, url, options) {
   options = options || {};
 
   // fennec?
   if (window.BrowserApp) {
     return window.BrowserApp.addTab(url, {
       selected: options.inBackground ? false : true,
       pinned: options.isPinned || false,
-      isPrivate: options.private || false
+      isPrivate: options.isPrivate || false
     });
   }
-  return window.gBrowser.addTab(url);
+  let tab = window.gBrowser.addTab(url);
+  if (!options.inBackground)
+    activateTab(tab);
+  return tab;
 };
 exports.openTab = openTab;
 
 function isTabOpen(tab) {
   // try normal case then fennec case
   return !!((tab.linkedBrowser) || getWindowHoldingTab(tab));
 }
 exports.isTabOpen = isTabOpen;
--- a/addon-sdk/source/lib/sdk/windows/firefox.js
+++ b/addon-sdk/source/lib/sdk/windows/firefox.js
@@ -14,17 +14,18 @@ const { Cc, Ci, Cr } = require('chrome')
       { Options } = require('../tabs/common'),
       apiUtils = require('../deprecated/api-utils'),
       unload = require('../system/unload'),
       windowUtils = require('../deprecated/window-utils'),
       { WindowTrackerTrait } = windowUtils,
       { ns } = require('../core/namespace'),
       { observer: windowObserver } = require('./observer'),
       { getOwnerWindow } = require('../private-browsing/window/utils'),
-      viewNS = require('sdk/core/namespace').ns();
+      viewNS = require('../core/namespace').ns(),
+      { isPrivateBrowsingSupported } = require('../self');
 
 /**
  * Window trait composes safe wrappers for browser window that are E10S
  * compatible.
  */
 const BrowserWindowTrait = Trait.compose(
   EventEmitter,
   WindowDom.resolve({ close: '_close' }),
@@ -63,17 +64,17 @@ const BrowserWindowTrait = Trait.compose
         this._tabOptions = Array.isArray(options.tabs) ?
                            options.tabs.map(Options) :
                            [ Options(options.tabs) ];
       }
       else if ('url' in options) {
         this._tabOptions = [ Options(options.url) ];
       }
 
-      this._private = !!options.private;
+      this._isPrivate = isPrivateBrowsingSupported && !!options.isPrivate;
 
       this._load();
 
       viewNS(this._public).window = this._window;
       getOwnerWindow.implement(this._public, getChromeWindow);
 
       return this;
     },
@@ -204,19 +205,23 @@ const browserWindows = Trait.resolve({ t
      * Property is non-enumerable, in order to preserve array like enumeration.
      * @type {Window|null}
      */
     get activeWindow() {
       let window = windowUtils.activeBrowserWindow;
       return window ? BrowserWindow({window: window}) : null;
     },
     open: function open(options) {
-      if (typeof options === "string")
+      if (typeof options === "string") {
         // `tabs` option is under review and may be removed.
-        options = { tabs: [Options(options)] };
+        options = {
+          tabs: [Options(options)],
+          isPrivate: isPrivateBrowsingSupported && options.isPrivate
+        };
+      }
       return BrowserWindow(options);
     },
 
      /**
       * Internal listener which is called whenever new window gets open.
       * Creates wrapper and adds to this list.
       * @param {nsIWindow} chromeWindow
       */
--- a/addon-sdk/source/lib/sdk/windows/loader.js
+++ b/addon-sdk/source/lib/sdk/windows/loader.js
@@ -36,17 +36,17 @@ const WindowLoader = Trait.compose({
    * is dispatched. Please note that this trait will not handle exceptions that
    * may be thrown by this method so method itself should take care of
    * handling them.
    */
   _onUnload: Trait.required,
   _load: function _load() {
     if (this.__window) return;
     this._window = openDialog({
-      private: this._private,
+      private: this._isPrivate,
       args: this._tabOptions.map(function(options) options.url).join("|")
     });
   },
   /**
    * Private window who's load event is being tracked. Once window is loaded
    * `_onLoad` is called.
    * @type {nsIWindow}
    */
--- a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
+++ b/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
@@ -12,21 +12,25 @@ const { openTab, getTabs, getSelectedTab
 const { Options } = require('../tabs/common');
 const { on, once, off, emit } = require('../event/core');
 const { method } = require('../lang/functional');
 const { EVENTS } = require('../tabs/events');
 const { EventTarget } = require('../event/target');
 const { when: unload } = require('../system/unload');
 const { windowIterator } = require('../deprecated/window-utils');
 const { List, addListItem, removeListItem } = require('../util/list');
+const { isPrivateBrowsingSupported } = require('sdk/self');
+const { isTabPBSupported } = require('sdk/private-browsing/utils');
 
 const mainWindow = windowNS(browserWindows.activeWindow).window;
 
 const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
 
+const supportPrivateTabs = isPrivateBrowsingSupported && isTabPBSupported;
+
 const Tabs = Class({
   implements: [ List ],
   extends: EventTarget,
   initialize: function initialize(options) {
     let tabsInternals = tabsNS(this);
     let window = tabsNS(this).window = options.window || mainWindow;
 
     EventTarget.prototype.initialize.call(this, options);
@@ -48,17 +52,18 @@ const Tabs = Class({
     options = Options(options);
     let activeWin = browserWindows.activeWindow;
 
     if (options.isPinned) {
       console.error(ERR_FENNEC_MSG); // TODO
     }
 
     let rawTab = openTab(windowNS(activeWin).window, options.url, {
-      inBackground: options.inBackground
+      inBackground: options.inBackground,
+      isPrivate: supportPrivateTabs && options.isPrivate
     });
 
     // by now the tab has been created
     let tab = getTabForRawTab(rawTab);
 
     if (options.onClose)
       tab.on('close', options.onClose);
 
--- a/addon-sdk/source/lib/sdk/windows/tabs-firefox.js
+++ b/addon-sdk/source/lib/sdk/windows/tabs-firefox.js
@@ -8,19 +8,20 @@ module.metadata = {
 };
 
 const { Trait } = require("../deprecated/traits");
 const { List } = require("../deprecated/list");
 const { Tab } = require("../tabs/tab");
 const { EventEmitter } = require("../deprecated/events");
 const { EVENTS } = require("../tabs/events");
 const { getOwnerWindow, getActiveTab, getTabs,
-        openTab, activateTab } = require("../tabs/utils");
+        openTab } = require("../tabs/utils");
 const { Options } = require("../tabs/common");
 const { observer: tabsObserver } = require("../tabs/observer");
+const { isWindowPrivate } = require("../private-browsing/utils");
 
 const TAB_BROWSER = "tabbrowser";
 
 /**
  * This is a trait that is used in composition of window wrapper. Trait tracks
  * tab related events of the wrapped window in order to keep track of open
  * tabs and maintain their wrappers. Every new tab gets wrapped and jetpack
  * type event is emitted.
@@ -147,21 +148,24 @@ const TabList = List.resolve({ construct
       // This list is not going to emit any events, object holding this list
       // will do it instead, to make that possible we return a private API.
       return this;
     },
     get activeTab() this._activeTab,
     _activeTab: null,
 
     open: function open(options) {
+      let window = this._window;
+      let chromeWindow = window._window;
       options = Options(options);
-      this._window._tabOptions.push(options);
-      let tab = openTab(this._window._window, options.url);
-      if (!options.inBackground)
-        activateTab(tab);
+
+      // save the tab options
+      window._tabOptions.push(options);
+      // open the tab
+      let tab = openTab(chromeWindow, options.url, options);
     }
   // This is ugly, but necessary. Will be removed by #596248
   }).resolve({ toString: null })
 );
 
 /**
  * Combined list of all open tabs on all the windows.
  * type {TabList}
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -156,16 +156,38 @@ parser_groups = (
                                 metavar=None,
                                 type="choice",
                                 choices=["firefox", "fennec",
                                          "fennec-on-device", "thunderbird",
                                          "xulrunner"],
                                 default="firefox",
                                 cmds=['test', 'run', 'testex', 'testpkgs',
                                       'testall'])),
+        (("-o", "--overload-modules",), dict(dest="overload_modules",
+                                     help=("Overload JS modules integrated into"
+                                           " Firefox with the one from your SDK"
+                                           " repository"),
+                                     action="store_true",
+                                     default=False,
+                                     cmds=['run', 'test', 'testex', 'testpkgs',
+                                           'testall'])),
+        (("", "--strip-sdk",), dict(dest="bundle_sdk",
+                                    help=("Do not ship SDK modules in the xpi"),
+                                    action="store_false",
+                                    default=True,
+                                    cmds=['run', 'test', 'testex', 'testpkgs',
+                                          'testall', 'xpi'])),
+        (("", "--force-use-bundled-sdk",), dict(dest="force_use_bundled_sdk",
+                                    help=("When --strip-sdk isn't passed, "
+                                          "force using sdk modules shipped in "
+                                          "the xpi instead of firefox ones"),
+                                    action="store_true",
+                                    default=False,
+                                    cmds=['run', 'test', 'testex', 'testpkgs',
+                                          'testall', 'xpi'])),
         (("", "--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,
@@ -759,16 +781,24 @@ def run(arguments=sys.argv[1:], target_c
     harness_options = {
         'jetpackID': jid,
         'staticArgs': options.static_args,
         'name': target,
         }
 
     harness_options.update(build)
 
+    # When cfx is run from sdk root directory, we will strip sdk modules and
+    # override them with local modules.
+    # So that integration tools will continue to work and use local modules
+    if os.getcwd() == env_root:
+        options.bundle_sdk = True
+        options.force_use_bundled_sdk = False
+        options.overload_modules = True
+
     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'] = 'sdk/test/runner'
         harness_options['mainPath'] = 'sdk/test/runner'
     else:
         harness_options['main'] = target_cfg.get('main')
@@ -787,24 +817,42 @@ def run(arguments=sys.argv[1:], target_c
     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()
-    if len(harness_options['allTestModules']) == 0 and command == "test":
-        sys.exit(0)
+    harness_options['manifest'] = \
+        manifest.get_harness_options_manifest(options.bundle_sdk)
+
+    # Gives an hint to tell if sdk modules are bundled or not
+    harness_options['is-sdk-bundled'] = options.bundle_sdk
+
+    if options.force_use_bundled_sdk:
+        if not options.bundle_sdk:
+            print >>sys.stderr, ("--force-use-bundled-sdk and --strip-sdk "
+                                 "can't be used at the same time.")
+            sys.exit(1)
+        if options.overload_modules:
+            print >>sys.stderr, ("--force-use-bundled-sdk and --overload-modules "
+                                 "can't be used at the same time.")
+            sys.exit(1)
+        # Pass a flag in order to force using sdk modules shipped in the xpi
+        harness_options['force-use-bundled-sdk'] = True
+
+    # Pass the list of absolute path for all test modules
+    if command == "test":
+        harness_options['allTestModules'] = manifest.get_all_test_modules()
+        if len(harness_options['allTestModules']) == 0:
+            sys.exit(0)
 
     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,
@@ -820,17 +868,17 @@ def run(arguments=sys.argv[1:], target_c
         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())
+        used_files = set(manifest.get_used_files(options.bundle_sdk))
 
     if options.no_strip_xpi:
         used_files = None # disables the filter, includes all files
 
     if command == 'xpi':
         from cuddlefish.xpi import build_xpi
         # Generate extra options
         extra_harness_options = {}
@@ -867,17 +915,21 @@ def run(arguments=sys.argv[1:], target_c
                              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)
+                             mobile_app_name=options.mobile_app_name,
+                             env_root=env_root,
+                             is_running_tests=(command == "test"),
+                             overload_modules=options.overload_modules,
+                             bundle_sdk=options.bundle_sdk)
         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()
--- a/addon-sdk/source/python-lib/cuddlefish/manifest.py
+++ b/addon-sdk/source/python-lib/cuddlefish/manifest.py
@@ -255,35 +255,41 @@ class ManifestBuilder:
 
     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):
+    def get_used_files(self, bundle_sdk_modules):
         # 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 datamap in self.datamaps.values():
             for (zipname, absname) in datamap.files_to_copy:
                 yield absname
 
         for me in self.get_module_entries():
-            yield me.js_filename
+            # Do not add manifest entries for system modules,
+            # so that we won't ship SDK files.
+            if me.packageName != "addon-sdk" or bundle_sdk_modules:
+                yield me.js_filename
 
     def get_all_test_modules(self):
         return self.test_modules
 
-    def get_harness_options_manifest(self):
+    def get_harness_options_manifest(self, bundle_sdk_modules):
         manifest = {}
         for me in self.get_module_entries():
             path = me.get_path()
-            manifest[path] = me.get_entry_for_manifest()
+            # Do not add manifest entries for system modules,
+            # so that we won't ship SDK files.
+            if me.packageName != "addon-sdk" or bundle_sdk_modules:
+                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
--- a/addon-sdk/source/python-lib/cuddlefish/runner.py
+++ b/addon-sdk/source/python-lib/cuddlefish/runner.py
@@ -375,28 +375,48 @@ class XulrunnerAppRunner(mozrunner.Runne
         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):
+            mobile_app_name=None,
+            env_root=None,
+            is_running_tests=False,
+            overload_modules=False,
+            bundle_sdk=True):
     if binary:
         binary = os.path.expanduser(binary)
 
     if addons is None:
         addons = []
     else:
         addons = list(addons)
 
     cmdargs = []
     preferences = dict(DEFAULT_COMMON_PREFS)
 
+    # Overload global commonjs path with lib/ folders
+    file_scheme = "file://"
+    # win32 file scheme needs 3 slashes
+    if not env_root.startswith("/"):
+      file_scheme = file_scheme + "/"
+    addon_id = harness_options["jetpackID"]
+    pref_prefix = "extensions.modules." + addon_id + ".path"
+    if overload_modules:
+        preferences[pref_prefix] = file_scheme + \
+            os.path.join(env_root, "lib").replace("\\", "/") + "/"
+
+    # Overload tests/ mapping with test/ folder, only when running test
+    if is_running_tests:
+        preferences[pref_prefix + ".tests"] = file_scheme + \
+            os.path.join(env_root, "test").replace("\\", "/") + "/"
+
     # 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
@@ -478,17 +498,18 @@ def run_app(harness_root_dir, manifest_r
     # 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)
+              limit_to=used_files,
+              bundle_sdk=bundle_sdk)
     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
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
@@ -38,17 +38,17 @@ class Basic(unittest.TestCase):
         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-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "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()
+        m = m.get_harness_options_manifest(False)
 
         def assertReqIs(modname, reqname, path):
             reqs = m["one/%s" % modname]["requirements"]
             self.failUnlessEqual(reqs[reqname], path)
         assertReqIs("main", "panel", "sdk/panel")
         assertReqIs("main", "two.js", "one/two")
         assertReqIs("main", "./two", "one/two")
         assertReqIs("main", "sdk/tabs.js", "sdk/tabs")
@@ -67,17 +67,17 @@ class Basic(unittest.TestCase):
         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-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "three"])
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        m = m.get_harness_options_manifest()
+        m = m.get_harness_options_manifest(False)
         def assertReqIs(modname, reqname, path):
             reqs = m["three/%s" % modname]["requirements"]
             self.failUnlessEqual(reqs[reqname], path)
         assertReqIs("main", "three-a", "three-a/main")
         assertReqIs("main", "three-b", "three-b/main")
         assertReqIs("main", "three-c", "three-c/main")
 
     def test_relative_main_in_top(self):
@@ -85,17 +85,17 @@ class Basic(unittest.TestCase):
         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-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "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()
+        m = m.get_harness_options_manifest(False)
         reqs = m["five/main"]["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)
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
@@ -197,17 +197,17 @@ class SmallXPI(unittest.TestCase):
         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-sdk"])
         addon_sdk_dir = pkg_cfg.packages["addon-sdk"].lib[0]
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        used_files = list(m.get_used_files())
+        used_files = list(m.get_used_files(True))
         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"),
--- a/addon-sdk/source/python-lib/cuddlefish/xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/xpi.py
@@ -17,17 +17,18 @@ def make_zipfile_path(localroot, localpa
     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={}):
+              harness_options, limit_to=None, extra_harness_options={},
+              bundle_sdk=True):
     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')
 
     # Handle add-on icon
     if 'icon' in harness_options:
@@ -79,16 +80,20 @@ def build_xpi(template_root_dir, manifes
             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])
+      # Eventually strip sdk files. We need to do that in addition to the
+      # whilelist as the whitelist is only used for `cfx xpi`:
+      if not bundle_sdk and packageName == 'addon-sdk':
+          continue
       # 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.
--- a/addon-sdk/source/test/addons/private-browsing-supported/main.js
+++ b/addon-sdk/source/test/addons/private-browsing-supported/main.js
@@ -1,13 +1,166 @@
 /* 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 { Ci } = require('chrome');
 const { isPrivateBrowsingSupported } = require('sdk/self');
+const tabs = require('sdk/tabs');
+const { browserWindows: windows } = require('sdk/windows');
+const { isPrivate } = require('sdk/private-browsing');
+const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
+const { is } = require('sdk/system/xul-app');
+const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
+
+const TAB_URL = 'data:text/html;charset=utf-8,TEST-TAB';
 
 exports.testIsPrivateBrowsingTrue = function(assert) {
   assert.ok(isPrivateBrowsingSupported,
             'isPrivateBrowsingSupported property is true');
 };
 
+// test tab.open with isPrivate: true
+// test isPrivate on a tab
+// test getOwnerWindow on windows and tabs
+exports.testGetOwnerWindow = function(assert, done) {
+  let window = windows.activeWindow;
+  let chromeWindow = getOwnerWindow(window);
+  assert.ok(chromeWindow instanceof Ci.nsIDOMWindow, 'associated window is found');
+
+  tabs.open({
+    url: 'about:blank',
+    isPrivate: true,
+    onOpen: function(tab) {
+      // test that getOwnerWindow works as expected
+      if (is('Fennec')) {
+        assert.notStrictEqual(chromeWindow, getOwnerWindow(tab)); 
+        assert.ok(getOwnerWindow(tab) instanceof Ci.nsIDOMWindow); 
+      }
+      else {
+        if (isWindowPBSupported) {
+          assert.notStrictEqual(chromeWindow,
+          	                    getOwnerWindow(tab),
+          	                    'associated window is not the same for window and window\'s tab'); 
+        }
+        else {
+          assert.strictEqual(chromeWindow,
+          	                 getOwnerWindow(tab),
+          	                 'associated window is the same for window and window\'s tab');
+        }
+      }
+
+      let pbSupported = isTabPBSupported || isWindowPBSupported;
+
+      // test that the tab is private if it should be
+      assert.equal(isPrivate(tab), pbSupported);
+      assert.equal(isPrivate(getOwnerWindow(tab)), pbSupported);
+
+      tab.close(function() done());
+    }
+  });
+};
+
+// test that it is possible to open a private tab
+exports.testTabOpenPrivate = function(assert, done) {
+  tabs.open({
+    url: TAB_URL,
+    isPrivate: true,
+    onReady: function(tab) {
+      assert.equal(tab.url, TAB_URL, 'opened correct tab');
+      assert.equal(isPrivate(tab), (isWindowPBSupported || isTabPBSupported));
+
+      tab.close(function() {
+        done();
+      });
+    }
+  });
+}
+
+
+// test that it is possible to open a non private tab
+exports.testTabOpenPrivateDefault = function(assert, done) {
+  tabs.open({
+    url: TAB_URL,
+    onReady: function(tab) {
+      assert.equal(tab.url, TAB_URL, 'opened correct tab');
+      assert.equal(isPrivate(tab), false);
+
+      tab.close(function() {
+        done();
+      });
+    }
+  });
+}
+
+// test that it is possible to open a non private tab in explicit case
+exports.testTabOpenPrivateOffExplicit = function(assert, done) {
+  tabs.open({
+    url: TAB_URL,
+    isPrivate: false,
+    onReady: function(tab) {
+      assert.equal(tab.url, TAB_URL, 'opened correct tab');
+      assert.equal(isPrivate(tab), false);
+
+      tab.close(function() {
+        done();
+      });
+    }
+  });
+}
+
+// test windows.open with isPrivate: true
+// test isPrivate on a window
+if (!is('Fennec')) {
+  // test that it is possible to open a private window
+  exports.testWindowOpenPrivate = function(assert, done) {
+    windows.open({
+      url: TAB_URL,
+      isPrivate: true,
+      onOpen: function(window) {
+        let tab = window.tabs[0];
+        tab.once('ready', function() {
+          assert.equal(tab.url, TAB_URL, 'opened correct tab');
+          assert.equal(isPrivate(tab), isWindowPBSupported, 'tab is private');
+
+          window.close(function() {
+            done();
+          });
+        });
+      }
+    });
+  };
+
+  exports.testIsPrivateOnWindowOn = function(assert, done) {
+    windows.open({
+      isPrivate: true,
+      onOpen: function(window) {
+        assert.equal(isPrivate(window), isWindowPBSupported, 'isPrivate for a window is true when it should be');
+        assert.equal(isPrivate(window.tabs[0]), isWindowPBSupported, 'isPrivate for a tab is false when it should be');
+        window.close(done);
+      }
+    });
+  };
+
+  exports.testIsPrivateOnWindowOffImplicit = function(assert, done) {
+    windows.open({
+      onOpen: function(window) {
+        assert.equal(isPrivate(window), false, 'isPrivate for a window is false when it should be');
+        assert.equal(isPrivate(window.tabs[0]), false, 'isPrivate for a tab is false when it should be');
+        window.close(done);
+      }
+    })
+  }
+
+  exports.testIsPrivateOnWindowOffExplicit = function(assert, done) {
+    windows.open({
+      isPrivate: false,
+      onOpen: function(window) {
+        assert.equal(isPrivate(window), false, 'isPrivate for a window is false when it should be');
+        assert.equal(isPrivate(window.tabs[0]), false, 'isPrivate for a tab is false when it should be');
+        window.close(done);
+      }
+    })
+  }
+}
+
 require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/private-browsing/tabs.js
+++ b/addon-sdk/source/test/private-browsing/tabs.js
@@ -7,17 +7,17 @@ exports.testIsPrivateOnTab = function(te
   const { openTab, closeTab } = pbLoader.require('sdk/tabs/utils');
 
   let window = pbLoader.require('sdk/windows').browserWindows.activeWindow;
   let chromeWindow = pbLoader.require('sdk/private-browsing/window/utils').getOwnerWindow(window);
   test.assert(chromeWindow instanceof Ci.nsIDOMWindow, 'associated window is found');
   test.assert(!pb.isPrivate(chromeWindow), 'the top level window is not private');
 
   let rawTab = openTab(chromeWindow, 'data:text/html,<h1>Hi!</h1>', {
-  	private: true
+  	isPrivate: true
   });
 
   // test that the tab is private
   test.assert(rawTab.browser.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing);
   test.assert(pb.isPrivate(rawTab.browser.contentWindow));
   test.assert(pb.isPrivate(rawTab.browser));
 
   closeTab(rawTab);
--- a/addon-sdk/source/test/private-browsing/windows.js
+++ b/addon-sdk/source/test/private-browsing/windows.js
@@ -27,20 +27,20 @@ exports.testPerWindowPrivateBrowsingGett
     }, false);
 
     win.close();
   }, false);
 }
 
 exports.testIsPrivateOnWindowOn = function(assert, done) {
   windows.open({
-    private: true,
+    isPrivate: true,
     onOpen: function(window) {
-      assert.equal(isPrivate(window), true, 'isPrivate for a window is true when it should be');
-      assert.equal(isPrivate(window.tabs[0]), true, 'isPrivate for a tab is false when it should be');
+      assert.equal(isPrivate(window), false, 'isPrivate for a window is true when it should be');
+      assert.equal(isPrivate(window.tabs[0]), false, 'isPrivate for a tab is false when it should be');
       window.close(done);
     }
   });
 }
 
 exports.testIsPrivateOnWindowOff = function(assert, done) {
   windows.open({
     onOpen: function(window) {
--- a/addon-sdk/source/test/test-deprecate.js
+++ b/addon-sdk/source/test/test-deprecate.js
@@ -88,17 +88,17 @@ exports.testDeprecateEvent = function(as
       assert.equal(errors.length, 1, "only one error is dispatched");
       loader.unload();
       done();
     })
     assert.equal(errors.length, 1, "only one error is dispatched");
     emit(testObj, 'water');
   });
   assert.equal(errors.length, 1, "only one error is dispatched");
-  let msg = errors[0];console.log(msg);
+  let msg = errors[0];
   assert.ok(msg.indexOf("BAD") !== -1, "message contains the given message");
   assert.ok(msg.indexOf("deprecateEvent") !== -1,
             "message contains name of the caller function");
   assert.ok(msg.indexOf(module.uri) !== -1,
             "message contains URI of the caller module");
 
   emit(testObj, 'fire');
 }
--- a/addon-sdk/source/test/test-private-browsing.js
+++ b/addon-sdk/source/test/test-private-browsing.js
@@ -2,16 +2,17 @@
  * 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 { Ci } = require('chrome');
 const { pb, pbUtils, getOwnerWindow } = require('./private-browsing/helper');
 const { merge } = require('sdk/util/object');
 const windows = require('sdk/windows').browserWindows;
+const tabs = require('sdk/tabs');
 const winUtils = require('sdk/window/utils');
 const { isPrivateBrowsingSupported } = require('sdk/self');
 const { is } = require('sdk/system/xul-app');
 const { isPrivate } = require('sdk/private-browsing');
 
 // is global pb is enabled?
 if (pbUtils.isGlobalPBSupported) {
   merge(module.exports, require('./private-browsing/global'));
@@ -65,29 +66,30 @@ exports.testIsPrivateBrowsingFalseDefaul
 
 exports.testGetOwnerWindow = function(test) {
   test.waitUntilDone();
 
   let window = windows.activeWindow;
   let chromeWindow = getOwnerWindow(window);
   test.assert(chromeWindow instanceof Ci.nsIDOMWindow, 'associated window is found');
 
-  window.tabs.open({
+  tabs.open({
     url: 'about:blank',
-    private: true, // should be ignored in this case
+    isPrivate: true,
     onOpen: function(tab) {
       // test that getOwnerWindow works as expected
       if (is('Fennec')) {
         test.assertNotStrictEqual(chromeWindow, getOwnerWindow(tab)); 
         test.assert(getOwnerWindow(tab) instanceof Ci.nsIDOMWindow); 
       }
       else {
         test.assertStrictEqual(chromeWindow, getOwnerWindow(tab), 'associated window is the same for window and window\'s tab');
       }
 
       // test that the tab is not private
       // private flag should be ignored by default
       test.assert(!isPrivate(tab));
+      test.assert(!isPrivate(getOwnerWindow(tab)));
 
       tab.close(function() test.done());
     }
   });
 };
--- a/addon-sdk/source/test/test-tabs-common.js
+++ b/addon-sdk/source/test/test-tabs-common.js
@@ -1,16 +1,18 @@
 /* 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 { Loader } = require('sdk/test/loader');
 const { browserWindows } = require('sdk/windows');
 const tabs = require('sdk/tabs');
+const { isPrivate } = require('sdk/private-browsing');
+const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
 
 const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';
 
 // TEST: tab count
 exports.testTabCounts = function(test) {
   test.waitUntilDone();
 
   tabs.open({
@@ -284,13 +286,34 @@ exports.testTabContentTypeAndReload = fu
     url: url,
     onReady: function(tab) {
       if (tab.url === url) {
         test.assertEqual(tab.contentType, "text/html");
         tab.url = urlXML;
       }
       else {
         test.assertEqual(tab.contentType, "text/xml");
-        tab.close(function() test.done());
+        tab.close(function() {
+          test.done();
+        });
       }
     }
   });
 };
+
+// test that it is possible to open a private tab
+exports.testTabOpenPrivate = function(test) {
+  test.waitUntilDone();
+
+  let url = 'about:blank';
+  tabs.open({
+    url: url,
+    isPrivate: true,
+    onReady: function(tab) {
+      test.assertEqual(tab.url, url, 'opened correct tab');
+      test.assertEqual(isPrivate(tab), false, 'private tabs arenot supported by default');
+
+      tab.close(function() {
+        test.done();
+      });
+    }
+  });
+}
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -7,16 +7,18 @@ const { Cc, Ci } = require('chrome');
 const { setTimeout } = require('sdk/timers');
 const { Loader } = require('sdk/test/loader');
 const wm = Cc['@mozilla.org/appshell/window-mediator;1'].
            getService(Ci.nsIWindowMediator);
 
 const { browserWindows } = require("sdk/windows");
 const tabs = require("sdk/tabs");
 const { WindowTracker } = require("sdk/deprecated/window-utils");
+const { isPrivate } = require('sdk/private-browsing');
+const { isWindowPBSupported } = require('sdk/private-browsing/utils');
 
 // TEST: open & close window
 exports.testOpenAndCloseWindow = function(test) {
   test.waitUntilDone();
 
   test.assertEqual(browserWindows.length, 1, "Only one window open");
 
   browserWindows.open({
@@ -96,17 +98,17 @@ exports.testWindowTabsObject = function(
           test.assertEqual(tab.title, "tab " + i++, "Correct title");
 
         window.close();
       }
     });
   }
   browserWindows.open({
     url: "data:text/html;charset=utf-8,<title>tab 1</title>",
-    onActivate: function onOpen(win) {
+    onActivate: function onActivate(win) {
       window = win;
       runTest();
     },
     onClose: function onClose(window) {
       test.assertEqual(window.tabs.length, 0, "No more tabs on closed window");
       test.done();
     }
   });
@@ -365,8 +367,29 @@ exports.testTrackWindows = function(test
     // only concerned with windows opened for this test
     if (index < 0)
       return;
     actions.push("global deactivate " + index)
   })
 
   openWindow();
 }
+
+// test that it is not possible to open a private window by default
+exports.testWindowOpenPrivateDefault = function(test) {
+  test.waitUntilDone();
+
+  browserWindows.open({
+    url: 'about:mozilla',
+    isPrivate: true,
+    onOpen: function(window) {
+      let tab = window.tabs[0];
+      tab.once('ready', function() {
+        test.assertEqual(tab.url, 'about:mozilla', 'opened correct tab');
+        test.assertEqual(isPrivate(tab), false, 'tab is not private');
+
+        window.close(function() {
+          test.done();
+        });
+      });
+    }
+  });
+}