summaryrefslogtreecommitdiffstats
path: root/devtools/client/webide/modules/app-manager.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webide/modules/app-manager.js')
-rw-r--r--devtools/client/webide/modules/app-manager.js850
1 files changed, 0 insertions, 850 deletions
diff --git a/devtools/client/webide/modules/app-manager.js b/devtools/client/webide/modules/app-manager.js
deleted file mode 100644
index 88dfcdd44..000000000
--- a/devtools/client/webide/modules/app-manager.js
+++ /dev/null
@@ -1,850 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const {Cu} = require("chrome");
-
-const promise = require("promise");
-const {TargetFactory} = require("devtools/client/framework/target");
-const Services = require("Services");
-const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
-const EventEmitter = require("devtools/shared/event-emitter");
-const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
-const {AppProjects} = require("devtools/client/webide/modules/app-projects");
-const TabStore = require("devtools/client/webide/modules/tab-store");
-const {AppValidator} = require("devtools/client/webide/modules/app-validator");
-const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager");
-const {AppActorFront} = require("devtools/shared/apps/app-actor-front");
-const {getDeviceFront} = require("devtools/shared/fronts/device");
-const {getPreferenceFront} = require("devtools/shared/fronts/preference");
-const {getSettingsFront} = require("devtools/shared/fronts/settings");
-const {Task} = require("devtools/shared/task");
-const {RuntimeScanners, RuntimeTypes} = require("devtools/client/webide/modules/runtimes");
-const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
-const Telemetry = require("devtools/client/shared/telemetry");
-const {ProjectBuilding} = require("./build");
-
-const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties");
-
-var AppManager = exports.AppManager = {
-
- DEFAULT_PROJECT_ICON: "chrome://webide/skin/default-app-icon.png",
- DEFAULT_PROJECT_NAME: "--",
-
- _initialized: false,
-
- init: function () {
- if (this._initialized) {
- return;
- }
- this._initialized = true;
-
- let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
- this.connection = ConnectionManager.createConnection("localhost", port);
- this.onConnectionChanged = this.onConnectionChanged.bind(this);
- this.connection.on(Connection.Events.STATUS_CHANGED, this.onConnectionChanged);
-
- this.tabStore = new TabStore(this.connection);
- this.onTabList = this.onTabList.bind(this);
- this.onTabNavigate = this.onTabNavigate.bind(this);
- this.onTabClosed = this.onTabClosed.bind(this);
- this.tabStore.on("tab-list", this.onTabList);
- this.tabStore.on("navigate", this.onTabNavigate);
- this.tabStore.on("closed", this.onTabClosed);
-
- this._clearRuntimeList();
- this._rebuildRuntimeList = this._rebuildRuntimeList.bind(this);
- RuntimeScanners.on("runtime-list-updated", this._rebuildRuntimeList);
- RuntimeScanners.enable();
- this._rebuildRuntimeList();
-
- this.onInstallProgress = this.onInstallProgress.bind(this);
-
- this._telemetry = new Telemetry();
- },
-
- destroy: function () {
- if (!this._initialized) {
- return;
- }
- this._initialized = false;
-
- this.selectedProject = null;
- this.selectedRuntime = null;
- RuntimeScanners.off("runtime-list-updated", this._rebuildRuntimeList);
- RuntimeScanners.disable();
- this.runtimeList = null;
- this.tabStore.off("tab-list", this.onTabList);
- this.tabStore.off("navigate", this.onTabNavigate);
- this.tabStore.off("closed", this.onTabClosed);
- this.tabStore.destroy();
- this.tabStore = null;
- this.connection.off(Connection.Events.STATUS_CHANGED, this.onConnectionChanged);
- this._listTabsResponse = null;
- this.connection.disconnect();
- this.connection = null;
- },
-
- /**
- * This module emits various events when state changes occur. The basic event
- * naming scheme is that event "X" means "X has changed" or "X is available".
- * Some names are more detailed to clarify their precise meaning.
- *
- * The events this module may emit include:
- * before-project:
- * The selected project is about to change. The event includes a special
- * |cancel| callback that will abort the project change if desired.
- * connection:
- * The connection status has changed (connected, disconnected, etc.)
- * install-progress:
- * A project being installed to a runtime has made further progress. This
- * event contains additional details about exactly how far the process is
- * when such information is available.
- * project:
- * The selected project has changed.
- * project-started:
- * The selected project started running on the connected runtime.
- * project-stopped:
- * The selected project stopped running on the connected runtime.
- * project-removed:
- * The selected project was removed from the project list.
- * project-validated:
- * The selected project just completed validation. As part of validation,
- * many pieces of metadata about the project are refreshed, including its
- * name, manifest details, etc.
- * runtime:
- * The selected runtime has changed.
- * runtime-apps-icons:
- * The list of URLs for the runtime app icons are available.
- * runtime-global-actors:
- * The list of global actors for the entire runtime (but not actors for a
- * specific tab or app) are now available, so we can test for features
- * like preferences and settings.
- * runtime-details:
- * The selected runtime's details have changed, such as its user-visible
- * name.
- * runtime-list:
- * The list of available runtimes has changed, or any of the user-visible
- * details (like names) for the non-selected runtimes has changed.
- * runtime-telemetry:
- * Detailed runtime telemetry has been recorded. Used by tests.
- * runtime-targets:
- * The list of remote runtime targets available from the currently
- * connected runtime (such as tabs or apps) has changed, or any of the
- * user-visible details (like names) for the non-selected runtime targets
- * has changed. This event includes |type| in the details, to distinguish
- * "apps" and "tabs".
- */
- update: function (what, details) {
- // Anything we want to forward to the UI
- this.emit("app-manager-update", what, details);
- },
-
- reportError: function (l10nProperty, ...l10nArgs) {
- let win = Services.wm.getMostRecentWindow("devtools:webide");
- if (win) {
- win.UI.reportError(l10nProperty, ...l10nArgs);
- } else {
- let text;
- if (l10nArgs.length > 0) {
- text = Strings.formatStringFromName(l10nProperty, l10nArgs, l10nArgs.length);
- } else {
- text = Strings.GetStringFromName(l10nProperty);
- }
- console.error(text);
- }
- },
-
- onConnectionChanged: function () {
- console.log("Connection status changed: " + this.connection.status);
-
- if (this.connection.status == Connection.Status.DISCONNECTED) {
- this.selectedRuntime = null;
- }
-
- if (!this.connected) {
- if (this._appsFront) {
- this._appsFront.off("install-progress", this.onInstallProgress);
- this._appsFront.unwatchApps();
- this._appsFront = null;
- }
- this._listTabsResponse = null;
- } else {
- this.connection.client.listTabs((response) => {
- if (response.webappsActor) {
- let front = new AppActorFront(this.connection.client,
- response);
- front.on("install-progress", this.onInstallProgress);
- front.watchApps(() => this.checkIfProjectIsRunning())
- .then(() => {
- // This can't be done earlier as many operations
- // in the apps actor require watchApps to be called
- // first.
- this._appsFront = front;
- this._listTabsResponse = response;
- this._recordRuntimeInfo();
- this.update("runtime-global-actors");
- })
- .then(() => {
- this.checkIfProjectIsRunning();
- this.update("runtime-targets", { type: "apps" });
- front.fetchIcons().then(() => this.update("runtime-apps-icons"));
- });
- } else {
- this._listTabsResponse = response;
- this._recordRuntimeInfo();
- this.update("runtime-global-actors");
- }
- });
- }
-
- this.update("connection");
- },
-
- get connected() {
- return this.connection &&
- this.connection.status == Connection.Status.CONNECTED;
- },
-
- get apps() {
- if (this._appsFront) {
- return this._appsFront.apps;
- } else {
- return new Map();
- }
- },
-
- onInstallProgress: function (event, details) {
- this.update("install-progress", details);
- },
-
- isProjectRunning: function () {
- if (this.selectedProject.type == "mainProcess" ||
- this.selectedProject.type == "tab") {
- return true;
- }
-
- let app = this._getProjectFront(this.selectedProject);
- return app && app.running;
- },
-
- checkIfProjectIsRunning: function () {
- if (this.selectedProject) {
- if (this.isProjectRunning()) {
- this.update("project-started");
- } else {
- this.update("project-stopped");
- }
- }
- },
-
- listTabs: function () {
- return this.tabStore.listTabs();
- },
-
- onTabList: function () {
- this.update("runtime-targets", { type: "tabs" });
- },
-
- // TODO: Merge this into TabProject as part of project-agnostic work
- onTabNavigate: function () {
- this.update("runtime-targets", { type: "tabs" });
- if (this.selectedProject.type !== "tab") {
- return;
- }
- let tab = this.selectedProject.app = this.tabStore.selectedTab;
- let uri = NetUtil.newURI(tab.url);
- // Wanted to use nsIFaviconService here, but it only works for visited
- // tabs, so that's no help for any remote tabs. Maybe some favicon wizard
- // knows how to get high-res favicons easily, or we could offer actor
- // support for this (bug 1061654).
- tab.favicon = uri.prePath + "/favicon.ico";
- tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
- if (uri.scheme.startsWith("http")) {
- tab.name = uri.host + ": " + tab.name;
- }
- this.selectedProject.location = tab.url;
- this.selectedProject.name = tab.name;
- this.selectedProject.icon = tab.favicon;
- this.update("project-validated");
- },
-
- onTabClosed: function () {
- if (this.selectedProject.type !== "tab") {
- return;
- }
- this.selectedProject = null;
- },
-
- reloadTab: function () {
- if (this.selectedProject && this.selectedProject.type != "tab") {
- return promise.reject("tried to reload non-tab project");
- }
- return this.getTarget().then(target => {
- target.activeTab.reload();
- }, console.error.bind(console));
- },
-
- getTarget: function () {
- if (this.selectedProject.type == "mainProcess") {
- // Fx >=39 exposes a ChromeActor to debug the main process
- if (this.connection.client.mainRoot.traits.allowChromeProcess) {
- return this.connection.client.getProcess()
- .then(aResponse => {
- return TargetFactory.forRemoteTab({
- form: aResponse.form,
- client: this.connection.client,
- chrome: true
- });
- });
- } else {
- // Fx <39 exposes tab actors on the root actor
- return TargetFactory.forRemoteTab({
- form: this._listTabsResponse,
- client: this.connection.client,
- chrome: true,
- isTabActor: false
- });
- }
- }
-
- if (this.selectedProject.type == "tab") {
- return this.tabStore.getTargetForTab();
- }
-
- let app = this._getProjectFront(this.selectedProject);
- if (!app) {
- return promise.reject("Can't find app front for selected project");
- }
-
- return Task.spawn(function* () {
- // Once we asked the app to launch, the app isn't necessary completely loaded.
- // launch request only ask the app to launch and immediatly returns.
- // We have to keep trying to get app tab actors required to create its target.
-
- for (let i = 0; i < 10; i++) {
- try {
- return yield app.getTarget();
- } catch (e) {}
- let deferred = promise.defer();
- setTimeout(deferred.resolve, 500);
- yield deferred.promise;
- }
-
- AppManager.reportError("error_cantConnectToApp", app.manifest.manifestURL);
- throw new Error("can't connect to app");
- });
- },
-
- getProjectManifestURL: function (project) {
- let manifest = null;
- if (project.type == "runtimeApp") {
- manifest = project.app.manifestURL;
- }
-
- if (project.type == "hosted") {
- manifest = project.location;
- }
-
- if (project.type == "packaged" && project.packagedAppOrigin) {
- manifest = "app://" + project.packagedAppOrigin + "/manifest.webapp";
- }
-
- return manifest;
- },
-
- _getProjectFront: function (project) {
- let manifest = this.getProjectManifestURL(project);
- if (manifest && this._appsFront) {
- return this._appsFront.apps.get(manifest);
- }
- return null;
- },
-
- _selectedProject: null,
- set selectedProject(project) {
- // A regular comparison doesn't work as we recreate a new object every time
- let prev = this._selectedProject;
- if (!prev && !project) {
- return;
- } else if (prev && project && prev.type === project.type) {
- let type = project.type;
- if (type === "runtimeApp") {
- if (prev.app.manifestURL === project.app.manifestURL) {
- return;
- }
- } else if (type === "tab") {
- if (prev.app.actor === project.app.actor) {
- return;
- }
- } else if (type === "packaged" || type === "hosted") {
- if (prev.location === project.location) {
- return;
- }
- } else if (type === "mainProcess") {
- return;
- } else {
- throw new Error("Unsupported project type: " + type);
- }
- }
-
- let cancelled = false;
- this.update("before-project", { cancel: () => { cancelled = true; } });
- if (cancelled) {
- return;
- }
-
- this._selectedProject = project;
-
- // Clear out tab store's selected state, if any
- this.tabStore.selectedTab = null;
-
- if (project) {
- if (project.type == "packaged" ||
- project.type == "hosted") {
- this.validateAndUpdateProject(project);
- }
- if (project.type == "tab") {
- this.tabStore.selectedTab = project.app;
- }
- }
-
- this.update("project");
- this.checkIfProjectIsRunning();
- },
- get selectedProject() {
- return this._selectedProject;
- },
-
- removeSelectedProject: Task.async(function* () {
- let location = this.selectedProject.location;
- AppManager.selectedProject = null;
- // If the user cancels the removeProject operation, don't remove the project
- if (AppManager.selectedProject != null) {
- return;
- }
-
- yield AppProjects.remove(location);
- AppManager.update("project-removed");
- }),
-
- packageProject: Task.async(function* (project) {
- if (!project) {
- return;
- }
- if (project.type == "packaged" ||
- project.type == "hosted") {
- yield ProjectBuilding.build({
- project: project,
- logger: this.update.bind(this, "pre-package")
- });
- }
- }),
-
- _selectedRuntime: null,
- set selectedRuntime(value) {
- this._selectedRuntime = value;
- if (!value && this.selectedProject &&
- (this.selectedProject.type == "mainProcess" ||
- this.selectedProject.type == "runtimeApp" ||
- this.selectedProject.type == "tab")) {
- this.selectedProject = null;
- }
- this.update("runtime");
- },
-
- get selectedRuntime() {
- return this._selectedRuntime;
- },
-
- connectToRuntime: function (runtime) {
-
- if (this.connected && this.selectedRuntime === runtime) {
- // Already connected
- return promise.resolve();
- }
-
- let deferred = promise.defer();
-
- this.disconnectRuntime().then(() => {
- this.selectedRuntime = runtime;
-
- let onConnectedOrDisconnected = () => {
- this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
- this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
- if (this.connected) {
- deferred.resolve();
- } else {
- deferred.reject();
- }
- };
- this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected);
- this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
- try {
- // Reset the connection's state to defaults
- this.connection.resetOptions();
- // Only watch for errors here. Final resolution occurs above, once
- // we've reached the CONNECTED state.
- this.selectedRuntime.connect(this.connection)
- .then(null, e => deferred.reject(e));
- } catch (e) {
- deferred.reject(e);
- }
- }, deferred.reject);
-
- // Record connection result in telemetry
- let logResult = result => {
- this._telemetry.log("DEVTOOLS_WEBIDE_CONNECTION_RESULT", result);
- if (runtime.type) {
- this._telemetry.log("DEVTOOLS_WEBIDE_" + runtime.type +
- "_CONNECTION_RESULT", result);
- }
- };
- deferred.promise.then(() => logResult(true), () => logResult(false));
-
- // If successful, record connection time in telemetry
- deferred.promise.then(() => {
- const timerId = "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS";
- this._telemetry.startTimer(timerId);
- this.connection.once(Connection.Events.STATUS_CHANGED, () => {
- this._telemetry.stopTimer(timerId);
- });
- }).catch(() => {
- // Empty rejection handler to silence uncaught rejection warnings
- // |connectToRuntime| caller should listen for rejections.
- // Bug 1121100 may find a better way to silence these.
- });
-
- return deferred.promise;
- },
-
- _recordRuntimeInfo: Task.async(function* () {
- if (!this.connected) {
- return;
- }
- let runtime = this.selectedRuntime;
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE",
- runtime.type || "UNKNOWN", true);
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID",
- runtime.id || "unknown", true);
- if (!this.deviceFront) {
- this.update("runtime-telemetry");
- return;
- }
- let d = yield this.deviceFront.getDescription();
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR",
- d.processor, true);
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS",
- d.os, true);
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION",
- d.platformversion, true);
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE",
- d.apptype, true);
- this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION",
- d.version, true);
- this.update("runtime-telemetry");
- }),
-
- isMainProcessDebuggable: function () {
- // Fx <39 exposes chrome tab actors on RootActor
- // Fx >=39 exposes a dedicated actor via getProcess request
- return this.connection.client &&
- this.connection.client.mainRoot &&
- this.connection.client.mainRoot.traits.allowChromeProcess ||
- (this._listTabsResponse &&
- this._listTabsResponse.consoleActor);
- },
-
- get deviceFront() {
- if (!this._listTabsResponse) {
- return null;
- }
- return getDeviceFront(this.connection.client, this._listTabsResponse);
- },
-
- get preferenceFront() {
- if (!this._listTabsResponse) {
- return null;
- }
- return getPreferenceFront(this.connection.client, this._listTabsResponse);
- },
-
- get settingsFront() {
- if (!this._listTabsResponse) {
- return null;
- }
- return getSettingsFront(this.connection.client, this._listTabsResponse);
- },
-
- disconnectRuntime: function () {
- if (!this.connected) {
- return promise.resolve();
- }
- let deferred = promise.defer();
- this.connection.once(Connection.Events.DISCONNECTED, () => deferred.resolve());
- this.connection.disconnect();
- return deferred.promise;
- },
-
- launchRuntimeApp: function () {
- if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
- return promise.reject("attempting to launch a non-runtime app");
- }
- let app = this._getProjectFront(this.selectedProject);
- return app.launch();
- },
-
- launchOrReloadRuntimeApp: function () {
- if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
- return promise.reject("attempting to launch / reload a non-runtime app");
- }
- let app = this._getProjectFront(this.selectedProject);
- if (!app.running) {
- return app.launch();
- } else {
- return app.reload();
- }
- },
-
- runtimeCanHandleApps: function () {
- return !!this._appsFront;
- },
-
- installAndRunProject: function () {
- let project = this.selectedProject;
-
- if (!project || (project.type != "packaged" && project.type != "hosted")) {
- console.error("Can't install project. Unknown type of project.");
- return promise.reject("Can't install");
- }
-
- if (!this._listTabsResponse) {
- this.reportError("error_cantInstallNotFullyConnected");
- return promise.reject("Can't install");
- }
-
- if (!this._appsFront) {
- console.error("Runtime doesn't have a webappsActor");
- return promise.reject("Can't install");
- }
-
- return Task.spawn(function* () {
- let self = AppManager;
-
- // Package and validate project
- yield self.packageProject(project);
- yield self.validateAndUpdateProject(project);
-
- if (project.errorsCount > 0) {
- self.reportError("error_cantInstallValidationErrors");
- return;
- }
-
- let installPromise;
-
- if (project.type != "packaged" && project.type != "hosted") {
- return promise.reject("Don't know how to install project");
- }
-
- let response;
- if (project.type == "packaged") {
- let packageDir = yield ProjectBuilding.getPackageDir(project);
- console.log("Installing app from " + packageDir);
-
- response = yield self._appsFront.installPackaged(packageDir,
- project.packagedAppOrigin);
-
- // If the packaged app specified a custom origin override,
- // we need to update the local project origin
- project.packagedAppOrigin = response.appId;
- // And ensure the indexed db on disk is also updated
- AppProjects.update(project);
- }
-
- if (project.type == "hosted") {
- let manifestURLObject = Services.io.newURI(project.location, null, null);
- let origin = Services.io.newURI(manifestURLObject.prePath, null, null);
- let appId = origin.host;
- let metadata = {
- origin: origin.spec,
- manifestURL: project.location
- };
- response = yield self._appsFront.installHosted(appId,
- metadata,
- project.manifest);
- }
-
- // Addons don't have any document to load (yet?)
- // So that there is no need to run them, installing is enough
- if (project.manifest.manifest_version || project.manifest.role === "addon") {
- return;
- }
-
- let {app} = response;
- if (!app.running) {
- let deferred = promise.defer();
- self.on("app-manager-update", function onUpdate(event, what) {
- if (what == "project-started") {
- self.off("app-manager-update", onUpdate);
- deferred.resolve();
- }
- });
- yield app.launch();
- yield deferred.promise;
- } else {
- yield app.reload();
- }
- });
- },
-
- stopRunningApp: function () {
- let app = this._getProjectFront(this.selectedProject);
- return app.close();
- },
-
- /* PROJECT VALIDATION */
-
- validateAndUpdateProject: function (project) {
- if (!project) {
- return promise.reject();
- }
-
- return Task.spawn(function* () {
-
- let packageDir = yield ProjectBuilding.getPackageDir(project);
- let validation = new AppValidator({
- type: project.type,
- // Build process may place the manifest in a non-root directory
- location: packageDir
- });
-
- yield validation.validate();
-
- if (validation.manifest) {
- let manifest = validation.manifest;
- let iconPath;
- if (manifest.icons) {
- let size = Object.keys(manifest.icons).sort((a, b) => b - a)[0];
- if (size) {
- iconPath = manifest.icons[size];
- }
- }
- if (!iconPath) {
- project.icon = AppManager.DEFAULT_PROJECT_ICON;
- } else {
- if (project.type == "hosted") {
- let manifestURL = Services.io.newURI(project.location, null, null);
- let origin = Services.io.newURI(manifestURL.prePath, null, null);
- project.icon = Services.io.newURI(iconPath, null, origin).spec;
- } else if (project.type == "packaged") {
- let projectFolder = FileUtils.File(packageDir);
- let folderURI = Services.io.newFileURI(projectFolder).spec;
- project.icon = folderURI + iconPath.replace(/^\/|\\/, "");
- }
- }
- project.manifest = validation.manifest;
-
- if ("name" in project.manifest) {
- project.name = project.manifest.name;
- } else {
- project.name = AppManager.DEFAULT_PROJECT_NAME;
- }
- } else {
- project.manifest = null;
- project.icon = AppManager.DEFAULT_PROJECT_ICON;
- project.name = AppManager.DEFAULT_PROJECT_NAME;
- }
-
- project.validationStatus = "valid";
-
- if (validation.warnings.length > 0) {
- project.warningsCount = validation.warnings.length;
- project.warnings = validation.warnings;
- project.validationStatus = "warning";
- } else {
- project.warnings = "";
- project.warningsCount = 0;
- }
-
- if (validation.errors.length > 0) {
- project.errorsCount = validation.errors.length;
- project.errors = validation.errors;
- project.validationStatus = "error";
- } else {
- project.errors = "";
- project.errorsCount = 0;
- }
-
- if (project.warningsCount && project.errorsCount) {
- project.validationStatus = "error warning";
- }
-
- if (project.type === "hosted" && project.location !== validation.manifestURL) {
- yield AppProjects.updateLocation(project, validation.manifestURL);
- } else if (AppProjects.get(project.location)) {
- yield AppProjects.update(project);
- }
-
- if (AppManager.selectedProject === project) {
- AppManager.update("project-validated");
- }
- });
- },
-
- /* RUNTIME LIST */
-
- _clearRuntimeList: function () {
- this.runtimeList = {
- usb: [],
- wifi: [],
- simulator: [],
- other: []
- };
- },
-
- _rebuildRuntimeList: function () {
- let runtimes = RuntimeScanners.listRuntimes();
- this._clearRuntimeList();
-
- // Reorganize runtimes by type
- for (let runtime of runtimes) {
- switch (runtime.type) {
- case RuntimeTypes.USB:
- this.runtimeList.usb.push(runtime);
- break;
- case RuntimeTypes.WIFI:
- this.runtimeList.wifi.push(runtime);
- break;
- case RuntimeTypes.SIMULATOR:
- this.runtimeList.simulator.push(runtime);
- break;
- default:
- this.runtimeList.other.push(runtime);
- }
- }
-
- this.update("runtime-details");
- this.update("runtime-list");
- },
-
- /* MANIFEST UTILS */
-
- writeManifest: function (project) {
- if (project.type != "packaged") {
- return promise.reject("Not a packaged app");
- }
-
- if (!project.manifest) {
- project.manifest = {};
- }
-
- let folder = project.location;
- let manifestPath = OS.Path.join(folder, "manifest.webapp");
- let text = JSON.stringify(project.manifest, null, 2);
- let encoder = new TextEncoder();
- let array = encoder.encode(text);
- return OS.File.writeAtomic(manifestPath, array, {tmpPath: manifestPath + ".tmp"});
- },
-};
-
-EventEmitter.decorate(AppManager);