diff options
Diffstat (limited to 'devtools/client/devtools-startup.js')
-rw-r--r-- | devtools/client/devtools-startup.js | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/devtools/client/devtools-startup.js b/devtools/client/devtools-startup.js new file mode 100644 index 000000000..2271dd790 --- /dev/null +++ b/devtools/client/devtools-startup.js @@ -0,0 +1,215 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This XPCOM component is loaded very early. + * It handles command line arguments like -jsconsole, but also ensures starting + * core modules like 'devtools-browser.js' that hooks the browser windows + * and ensure setting up tools. + * + * Be careful to lazy load dependencies as much as possible. + **/ + +"use strict"; + +const { interfaces: Ci, utils: Cu } = Components; +const kDebuggerPrefs = [ + "devtools.debugger.remote-enabled", + "devtools.chrome.enabled" +]; +const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); +XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); + +function DevToolsStartup() {} + +DevToolsStartup.prototype = { + handle: function (cmdLine) { + let consoleFlag = cmdLine.handleFlag("jsconsole", false); + let debuggerFlag = cmdLine.handleFlag("jsdebugger", false); + let devtoolsFlag = cmdLine.handleFlag("devtools", false); + + if (consoleFlag) { + this.handleConsoleFlag(cmdLine); + } + if (debuggerFlag) { + this.handleDebuggerFlag(cmdLine); + } + let debuggerServerFlag; + try { + debuggerServerFlag = + cmdLine.handleFlagWithParam("start-debugger-server", false); + } catch (e) { + // We get an error if the option is given but not followed by a value. + // By catching and trying again, the value is effectively optional. + debuggerServerFlag = cmdLine.handleFlag("start-debugger-server", false); + } + if (debuggerServerFlag) { + this.handleDebuggerServerFlag(cmdLine, debuggerServerFlag); + } + + let onStartup = function (window) { + Services.obs.removeObserver(onStartup, + "browser-delayed-startup-finished"); + // Ensure loading core module once firefox is ready + this.initDevTools(); + + if (devtoolsFlag) { + this.handleDevToolsFlag(window); + } + }.bind(this); + Services.obs.addObserver(onStartup, "browser-delayed-startup-finished", + false); + }, + + initDevTools: function () { + let { loader } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + // Ensure loading main devtools module that hooks up into browser UI + // and initialize all devtools machinery. + loader.require("devtools/client/framework/devtools-browser"); + }, + + handleConsoleFlag: function (cmdLine) { + let window = Services.wm.getMostRecentWindow("devtools:webconsole"); + if (!window) { + this.initDevTools(); + + let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + let hudservice = require("devtools/client/webconsole/hudservice"); + let { console } = Cu.import("resource://gre/modules/Console.jsm", {}); + hudservice.toggleBrowserConsole().then(null, console.error); + } else { + // the Browser Console was already open + window.focus(); + } + + if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) { + cmdLine.preventDefault = true; + } + }, + + // Open the toolbox on the selected tab once the browser starts up. + handleDevToolsFlag: function (window) { + const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); + const {gDevTools} = require("devtools/client/framework/devtools"); + const {TargetFactory} = require("devtools/client/framework/target"); + let target = TargetFactory.forTab(window.gBrowser.selectedTab); + gDevTools.showToolbox(target); + }, + + _isRemoteDebuggingEnabled() { + let remoteDebuggingEnabled = false; + try { + remoteDebuggingEnabled = kDebuggerPrefs.every(pref => { + return Services.prefs.getBoolPref(pref); + }); + } catch (ex) { + console.error(ex); + return false; + } + if (!remoteDebuggingEnabled) { + let errorMsg = "Could not run chrome debugger! You need the following " + + "prefs to be set to true: " + kDebuggerPrefs.join(", "); + console.error(new Error(errorMsg)); + // Dump as well, as we're doing this from a commandline, make sure people + // don't miss it: + dump(errorMsg + "\n"); + } + return remoteDebuggingEnabled; + }, + + handleDebuggerFlag: function (cmdLine) { + if (!this._isRemoteDebuggingEnabled()) { + return; + } + const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}); + BrowserToolboxProcess.init(); + + if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) { + cmdLine.preventDefault = true; + } + }, + + /** + * Handle the --start-debugger-server command line flag. The options are: + * --start-debugger-server + * The portOrPath parameter is boolean true in this case. Reads and uses the defaults + * from devtools.debugger.remote-port and devtools.debugger.remote-websocket prefs. + * The default values of these prefs are port 6000, WebSocket disabled. + * + * --start-debugger-server 6789 + * Start the non-WebSocket server on port 6789. + * + * --start-debugger-server /path/to/filename + * Start the server on a Unix domain socket. + * + * --start-debugger-server ws:6789 + * Start the WebSocket server on port 6789. + * + * --start-debugger-server ws: + * Start the WebSocket server on the default port (taken from d.d.remote-port) + */ + handleDebuggerServerFlag: function (cmdLine, portOrPath) { + if (!this._isRemoteDebuggingEnabled()) { + return; + } + + let webSocket = false; + let defaultPort = Services.prefs.getIntPref("devtools.debugger.remote-port"); + if (portOrPath === true) { + // Default to pref values if no values given on command line + webSocket = Services.prefs.getBoolPref("devtools.debugger.remote-websocket"); + portOrPath = defaultPort; + } else if (portOrPath.startsWith("ws:")) { + webSocket = true; + let port = portOrPath.slice(3); + portOrPath = Number(port) ? port : defaultPort; + } + + let { DevToolsLoader } = + Cu.import("resource://devtools/shared/Loader.jsm", {}); + + try { + // Create a separate loader instance, so that we can be sure to receive + // a separate instance of the DebuggingServer from the rest of the + // devtools. This allows us to safely use the tools against even the + // actors and DebuggingServer itself, especially since we can mark + // serverLoader as invisible to the debugger (unlike the usual loader + // settings). + let serverLoader = new DevToolsLoader(); + serverLoader.invisibleToDebugger = true; + let { DebuggerServer: debuggerServer } = + serverLoader.require("devtools/server/main"); + debuggerServer.init(); + debuggerServer.addBrowserActors(); + debuggerServer.allowChromeProcess = true; + + let listener = debuggerServer.createListener(); + listener.portOrPath = portOrPath; + listener.webSocket = webSocket; + listener.open(); + dump("Started debugger server on " + portOrPath + "\n"); + } catch (e) { + dump("Unable to start debugger server on " + portOrPath + ": " + e); + } + + if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) { + cmdLine.preventDefault = true; + } + }, + + /* eslint-disable max-len */ + helpInfo: " --jsconsole Open the Browser Console.\n" + + " --jsdebugger Open the Browser Toolbox.\n" + + " --devtools Open DevTools on initial load.\n" + + " --start-debugger-server [ws:][ <port> | <path> ] Start the debugger server on\n" + + " a TCP port or Unix domain socket path. Defaults to TCP port\n" + + " 6000. Use WebSocket protocol if ws: prefix is specified.\n", + /* eslint-disable max-len */ + + classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory( + [DevToolsStartup]); |