Bug 1192032 - Add edge bookmarks/favorites migrator. r=MattN, a=sledru
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Tue, 11 Aug 2015 16:53:10 +0100
changeset 288999 98983a6fd50d6eb8166116c12d980694be24101e
parent 288998 a9438a2e6b2771b18d2c06432727dd79df9fec4b
child 289000 e975c8dbdb1832a034a9b8dd2aafb4d52201b81d
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN, sledru
bugs1192032
milestone42.0a2
Bug 1192032 - Add edge bookmarks/favorites migrator. r=MattN, a=sledru
browser/components/migration/BrowserProfileMigrators.manifest
browser/components/migration/EdgeProfileMigrator.js
browser/components/migration/IEProfileMigrator.js
browser/components/migration/MSMigrationUtils.jsm
browser/components/migration/MigrationUtils.jsm
browser/components/migration/content/migration.xul
browser/components/migration/moz.build
browser/components/migration/tests/unit/test_Edge_availability.js
browser/components/migration/tests/unit/xpcshell.ini
browser/installer/package-manifest.in
--- a/browser/components/migration/BrowserProfileMigrators.manifest
+++ b/browser/components/migration/BrowserProfileMigrators.manifest
@@ -13,16 +13,21 @@ contract @mozilla.org/profile/migrator;1
 component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js
 contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386}
 
 #ifdef HAS_IE_MIGRATOR
 component {3d2532e3-4932-4774-b7ba-968f5899d3a4} IEProfileMigrator.js
 contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774-b7ba-968f5899d3a4}
 #endif
 
+#ifdef HAS_EDGE_MIGRATOR
+component {62e8834b-2d17-49f5-96ff-56344903a2ae} EdgeProfileMigrator.js
+contract @mozilla.org/profile/migrator;1?app=browser&type=edge {62e8834b-2d17-49f5-96ff-56344903a2ae}
+#endif
+
 #ifdef HAS_SAFARI_MIGRATOR
 component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
 contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
 #endif
 #ifdef HAS_360SE_MIGRATOR
 component {d0037b95-296a-4a4e-94b2-c3d075d20ab1} 360seProfileMigrator.js
 contract @mozilla.org/profile/migrator;1?app=browser&type=360se {d0037b95-296a-4a4e-94b2-c3d075d20ab1}
 #endif
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/EdgeProfileMigrator.js
@@ -0,0 +1,29 @@
+/* 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 { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource:///modules/MigrationUtils.jsm");
+Cu.import("resource:///modules/MSMigrationUtils.jsm");
+
+function EdgeProfileMigrator() {
+}
+
+EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
+
+EdgeProfileMigrator.prototype.getResources = function() {
+  let resources = [
+    MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
+  ];
+  return resources.filter(r => r.exists);
+};
+
+EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
+EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
+EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -10,16 +10,17 @@ const Cu = Components.utils;
 const Cr = Components.results;
 
 const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource:///modules/MigrationUtils.jsm");
+Cu.import("resource:///modules/MSMigrationUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
                                   "resource://gre/modules/ctypes.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
                                   "resource://gre/modules/WindowsRegistry.jsm");
 
@@ -131,119 +132,16 @@ function hostIsIPAddress(aHost) {
     return true;
   } catch (e) {}
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Resources
 
-function Bookmarks() {
-}
-
-Bookmarks.prototype = {
-  type: MigrationUtils.resourceTypes.BOOKMARKS,
-
-  get exists() !!this._favoritesFolder,
-
-  __favoritesFolder: null,
-  get _favoritesFolder() {
-    if (!this.__favoritesFolder) {
-      let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
-      if (favoritesFolder.exists() && favoritesFolder.isReadable())
-        this.__favoritesFolder = favoritesFolder;
-    }
-    return this.__favoritesFolder;
-  },
-
-  __toolbarFolderName: null,
-  get _toolbarFolderName() {
-    if (!this.__toolbarFolderName) {
-      // Retrieve the name of IE's favorites subfolder that holds the bookmarks
-      // in the toolbar. This was previously stored in the registry and changed
-      // in IE7 to always be called "Links".
-      let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
-                                                  "Software\\Microsoft\\Internet Explorer\\Toolbar",
-                                                  "LinksFolderName");
-      this.__toolbarFolderName = folderName || "Links";
-    }
-    return this.__toolbarFolderName;
-  },
-
-  migrate: function B_migrate(aCallback) {
-    return Task.spawn(function* () {
-      // Import to the bookmarks menu.
-      let folderGuid = PlacesUtils.bookmarks.menuGuid;
-      if (!MigrationUtils.isStartupMigration) {
-        folderGuid =
-          yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
-      }
-      yield this._migrateFolder(this._favoritesFolder, folderGuid);
-    }.bind(this)).then(() => aCallback(true),
-                        e => { Cu.reportError(e); aCallback(false) });
-  },
-
-  _migrateFolder: Task.async(function* (aSourceFolder, aDestFolderGuid) {
-    // TODO (bug 741993): the favorites order is stored in the Registry, at
-    // HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
-    // Until we support it, bookmarks are imported in alphabetical order.
-    let entries = aSourceFolder.directoryEntries;
-    while (entries.hasMoreElements()) {
-      let entry = entries.getNext().QueryInterface(Ci.nsIFile);
-      try {
-        // Make sure that entry.path == entry.target to not follow .lnk folder
-        // shortcuts which could lead to infinite cycles.
-        // Don't use isSymlink(), since it would throw for invalid
-        // lnk files pointing to URLs or to unresolvable paths.
-        if (entry.path == entry.target && entry.isDirectory()) {
-          let folderGuid;
-          if (entry.leafName == this._toolbarFolderName &&
-              entry.parent.equals(this._favoritesFolder)) {
-            // Import to the bookmarks toolbar.
-            folderGuid = PlacesUtils.bookmarks.toolbarGuid;
-            if (!MigrationUtils.isStartupMigration) {
-              folderGuid =
-                yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
-            }
-          }
-          else {
-            // Import to a new folder.
-            folderGuid = (yield PlacesUtils.bookmarks.insert({
-              type: PlacesUtils.bookmarks.TYPE_FOLDER,
-              parentGuid: aDestFolderGuid,
-              title: entry.leafName
-            })).guid;
-          }
-
-          if (entry.isReadable()) {
-            // Recursively import the folder.
-            yield this._migrateFolder(entry, folderGuid);
-          }
-        }
-        else {
-          // Strip the .url extension, to both check this is a valid link file,
-          // and get the associated title.
-          let matches = entry.leafName.match(/(.+)\.url$/i);
-          if (matches) {
-            let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
-                              getService(Ci.nsIFileProtocolHandler);
-            let uri = fileHandler.readURLFile(entry);
-            let title = matches[1];
-
-            yield PlacesUtils.bookmarks.insert({
-              parentGuid: aDestFolderGuid, url: uri, title
-            });
-          }
-        }
-      } catch (ex) {
-        Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex);
-      }
-    }
-  })
-};
 
 function History() {
 }
 
 History.prototype = {
   type: MigrationUtils.resourceTypes.HISTORY,
 
   get exists() true,
@@ -601,17 +499,17 @@ Settings.prototype = {
 function IEProfileMigrator()
 {
 }
 
 IEProfileMigrator.prototype = Object.create(MigratorPrototype);
 
 IEProfileMigrator.prototype.getResources = function IE_getResources() {
   let resources = [
-    new Bookmarks()
+    MSMigrationUtils.getBookmarksMigrator()
   , new History()
   , new Cookies()
   , new Settings()
   ];
   return [r for each (r in resources) if (r.exists)];
 };
 
 Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -0,0 +1,172 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = ["MSMigrationUtils"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource:///modules/MigrationUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
+                                  "resource://gre/modules/WindowsRegistry.jsm");
+
+const EDGE_FAVORITES = "AC\\MicrosoftEdge\\User\\Default\\Favorites";
+
+function Bookmarks(migrationType) {
+  this._migrationType = migrationType;
+}
+
+Bookmarks.prototype = {
+  type: MigrationUtils.resourceTypes.BOOKMARKS,
+
+  get exists() !!this._favoritesFolder,
+
+  get importedAppLabel() this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE ? "IE" : "Edge",
+
+  __favoritesFolder: null,
+  get _favoritesFolder() {
+    if (!this.__favoritesFolder) {
+      if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) {
+        let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
+        if (favoritesFolder.exists() && favoritesFolder.isReadable())
+          return this.__favoritesFolder = favoritesFolder;
+      }
+      if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_EDGE) {
+        let appData = Services.dirsvc.get("LocalAppData", Ci.nsIFile);
+        appData.append("Packages");
+        try {
+          let edgeDir = appData.clone();
+          edgeDir.append("Microsoft.MicrosoftEdge_8wekyb3d8bbwe");
+          edgeDir.appendRelativePath(EDGE_FAVORITES);
+          if (edgeDir.exists() && edgeDir.isDirectory()) {
+            return this.__favoritesFolder = edgeDir;
+          }
+        } catch (ex) {} /* Ignore e.g. permissions errors here. */
+
+        // Let's try the long way:
+        try {
+          let dirEntries = appData.directoryEntries;
+          while (dirEntries.hasMoreElements()) {
+            let subDir = dirEntries.getNext();
+            subDir.QueryInterface(Ci.nsIFile);
+            if (subDir.leafName.startsWith("Microsoft.MicrosoftEdge")) {
+              subDir.appendRelativePath(EDGE_FAVORITES);
+              if (subDir.exists() && subDir.isDirectory()) {
+                return this.__favoritesFolder = subDir;
+              }
+            }
+          }
+        } catch (ex) {
+          Cu.reportError("Exception trying to find the Edge favorites directory: " + ex);
+        }
+      }
+    }
+    return this.__favoritesFolder;
+  },
+
+  __toolbarFolderName: null,
+  get _toolbarFolderName() {
+    if (!this.__toolbarFolderName) {
+      if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) {
+        // Retrieve the name of IE's favorites subfolder that holds the bookmarks
+        // in the toolbar. This was previously stored in the registry and changed
+        // in IE7 to always be called "Links".
+        let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                                    "Software\\Microsoft\\Internet Explorer\\Toolbar",
+                                                    "LinksFolderName");
+        this.__toolbarFolderName = folderName || "Links";
+      } else {
+        this.__toolbarFolderName = "Links";
+      }
+    }
+    return this.__toolbarFolderName;
+  },
+
+  migrate: function B_migrate(aCallback) {
+    return Task.spawn(function* () {
+      // Import to the bookmarks menu.
+      let folderGuid = PlacesUtils.bookmarks.menuGuid;
+      if (!MigrationUtils.isStartupMigration) {
+        folderGuid =
+          yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
+      }
+      yield this._migrateFolder(this._favoritesFolder, folderGuid);
+    }.bind(this)).then(() => aCallback(true),
+                        e => { Cu.reportError(e); aCallback(false) });
+  },
+
+  _migrateFolder: Task.async(function* (aSourceFolder, aDestFolderGuid) {
+    // TODO (bug 741993): the favorites order is stored in the Registry, at
+    // HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
+    // for IE, and in a similar location for Edge.
+    // Until we support it, bookmarks are imported in alphabetical order.
+    let entries = aSourceFolder.directoryEntries;
+    while (entries.hasMoreElements()) {
+      let entry = entries.getNext().QueryInterface(Ci.nsIFile);
+      try {
+        // Make sure that entry.path == entry.target to not follow .lnk folder
+        // shortcuts which could lead to infinite cycles.
+        // Don't use isSymlink(), since it would throw for invalid
+        // lnk files pointing to URLs or to unresolvable paths.
+        if (entry.path == entry.target && entry.isDirectory()) {
+          let folderGuid;
+          if (entry.leafName == this._toolbarFolderName &&
+              entry.parent.equals(this._favoritesFolder)) {
+            // Import to the bookmarks toolbar.
+            folderGuid = PlacesUtils.bookmarks.toolbarGuid;
+            if (!MigrationUtils.isStartupMigration) {
+              folderGuid =
+                yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
+            }
+          }
+          else {
+            // Import to a new folder.
+            folderGuid = (yield PlacesUtils.bookmarks.insert({
+              type: PlacesUtils.bookmarks.TYPE_FOLDER,
+              parentGuid: aDestFolderGuid,
+              title: entry.leafName
+            })).guid;
+          }
+
+          if (entry.isReadable()) {
+            // Recursively import the folder.
+            yield this._migrateFolder(entry, folderGuid);
+          }
+        }
+        else {
+          // Strip the .url extension, to both check this is a valid link file,
+          // and get the associated title.
+          let matches = entry.leafName.match(/(.+)\.url$/i);
+          if (matches) {
+            let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
+                              getService(Ci.nsIFileProtocolHandler);
+            let uri = fileHandler.readURLFile(entry);
+            let title = matches[1];
+
+            yield PlacesUtils.bookmarks.insert({
+              parentGuid: aDestFolderGuid, url: uri, title
+            });
+          }
+        }
+      } catch (ex) {
+        Components.utils.reportError("Unable to import " + this.importedAppLabel + " favorite (" + entry.leafName + "): " + ex);
+      }
+    }
+  })
+};
+
+let MSMigrationUtils = {
+  MIGRATION_TYPE_IE: 1,
+  MIGRATION_TYPE_EDGE: 2,
+  getBookmarksMigrator(migrationType = this.MIGRATION_TYPE_IE) {
+    return new Bookmarks(migrationType);
+  },
+};
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -452,16 +452,17 @@ this.MigrationUtils = Object.freeze({
   },
 
   /*
    * Returns the migrator for the given source, if any data is available
    * for this source, or null otherwise.
    *
    * @param aKey internal name of the migration source.
    *             Supported values: ie (windows),
+   *                               edge (windows),
    *                               safari (mac/windows),
    *                               canary (mac/windows),
    *                               chrome (mac/windows/linux),
    *                               chromium (mac/windows/linux),
    *                               360se (windows),
    *                               firefox.
    *
    * If null is returned,  either no data can be imported
@@ -477,29 +478,31 @@ this.MigrationUtils = Object.freeze({
     if (this._migrators.has(aKey)) {
       migrator = this._migrators.get(aKey);
     }
     else {
       try {
         migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=" +
                       aKey].createInstance(Ci.nsIBrowserProfileMigrator);
       }
-      catch(ex) { }
+      catch(ex) { Cu.reportError(ex) }
       this._migrators.set(aKey, migrator);
     }
 
-    return migrator && migrator.sourceExists ? migrator : null;
+    try {
+      return migrator && migrator.sourceExists ? migrator : null;
+    } catch (ex) { Cu.reportError(ex); return null }
   },
 
   // Iterates the available migrators, in the most suitable
   // order for the running platform.
   get migrators() {
     let migratorKeysOrdered = [
 #ifdef XP_WIN
-      "firefox", "ie", "chrome", "chromium", "safari", "360se", "canary"
+      "firefox", "edge", "ie", "chrome", "chromium", "safari", "360se", "canary"
 #elifdef XP_MACOSX
       "firefox", "safari", "chrome", "chromium", "canary"
 #elifdef XP_UNIX
       "firefox", "chrome", "chromium"
 #endif
     ];
 
     // If a supported default browser is found check it first
--- a/browser/components/migration/content/migration.xul
+++ b/browser/components/migration/content/migration.xul
@@ -29,16 +29,17 @@
 #else
     <description id="importAll" control="importSourceGroup">&importFromUnix.label;</description>
 #endif
     <description id="importBookmarks" control="importSourceGroup" hidden="true">&importFromBookmarks.label;</description>
 
     <radiogroup id="importSourceGroup" align="start">
       <radio id="firefox"   label="&importFromFirefox.label;"   accesskey="&importFromFirefox.accesskey;"/>
 #ifdef XP_WIN
+      <radio id="edge"      label="&importFromEdge.label;"      accesskey="&importFromEdge.accesskey;"/>
       <radio id="ie"        label="&importFromIE.label;"        accesskey="&importFromIE.accesskey;"/>
       <radio id="chrome"    label="&importFromChrome.label;"    accesskey="&importFromChrome.accesskey;"/>
       <radio id="chromium"  label="&importFromChromium.label;"  accesskey="&importFromChromium.accesskey;"/>
       <radio id="safari"    label="&importFromSafari.label;"    accesskey="&importFromSafari.accesskey;"/>
       <radio id="canary"    label="&importFromCanary.label;"    accesskey="&importFromCanary.accesskey;"/>
       <radio id="360se"     label="&importFrom360se.label;"     accesskey="&importFrom360se.accesskey;"/>
 #elifdef XP_MACOSX
       <radio id="safari"    label="&importFromSafari.label;"    accesskey="&importFromSafari.accesskey;"/>
--- a/browser/components/migration/moz.build
+++ b/browser/components/migration/moz.build
@@ -22,20 +22,22 @@ if CONFIG['OS_ARCH'] == 'WINNT':
 EXTRA_COMPONENTS += [
     'FirefoxProfileMigrator.js',
     'ProfileMigrator.js',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXTRA_COMPONENTS += [
         '360seProfileMigrator.js',
+        'EdgeProfileMigrator.js',
         'IEProfileMigrator.js',
     ]
     DEFINES['HAS_360SE_MIGRATOR'] = True
     DEFINES['HAS_IE_MIGRATOR'] = True
+    DEFINES['HAS_EDGE_MIGRATOR'] = True
 
 EXTRA_PP_COMPONENTS += [
     'BrowserProfileMigrators.manifest',
     'ChromeProfileMigrator.js',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXTRA_PP_COMPONENTS += [
@@ -48,14 +50,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
         'SafariProfileMigrator.js',
     ]
     DEFINES['HAS_SAFARI_MIGRATOR'] = True
 
 EXTRA_PP_JS_MODULES += [
     'MigrationUtils.jsm',
 ]
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    EXTRA_JS_MODULES += [
+        'MSMigrationUtils.jsm',
+    ]
+
 FINAL_LIBRARY = 'browsercomps'
 
 FAIL_ON_WARNINGS = True
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Migration')
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/tests/unit/test_Edge_availability.js
@@ -0,0 +1,7 @@
+add_task(function* () {
+  let migrator = MigrationUtils.getMigrator("edge");
+  Cu.import("resource://gre/modules/AppConstants.jsm");
+  Assert.equal(!!(migrator && migrator.sourceExists), AppConstants.isPlatformAndVersionAtLeast("win", "10"),
+               "Edge should be available for migration if and only if we're on Win 10+");
+});
+
--- a/browser/components/migration/tests/unit/xpcshell.ini
+++ b/browser/components/migration/tests/unit/xpcshell.ini
@@ -6,15 +6,16 @@ skip-if = toolkit == 'android' || toolki
 support-files =
   Library/**
   AppData/**
 
 [test_Chrome_cookies.js]
 skip-if = os != "mac" # Relies on ULibDir
 [test_Chrome_passwords.js]
 skip-if = os != "win"
+[test_Edge_availability.js]
 [test_fx_fhr.js]
 [test_IE_bookmarks.js]
 skip-if = os != "win"
 [test_IE_cookies.js]
 skip-if = os != "win"
 [test_Safari_bookmarks.js]
 skip-if = os != "mac"
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -484,16 +484,17 @@
 @RESPATH@/components/contentAreaDropListener.manifest
 @RESPATH@/components/contentAreaDropListener.js
 @RESPATH@/browser/components/BrowserProfileMigrators.manifest
 @RESPATH@/browser/components/ProfileMigrator.js
 @RESPATH@/browser/components/ChromeProfileMigrator.js
 @RESPATH@/browser/components/FirefoxProfileMigrator.js
 #ifdef XP_WIN
 @RESPATH@/browser/components/360seProfileMigrator.js
+@RESPATH@/browser/components/EdgeProfileMigrator.js
 @RESPATH@/browser/components/IEProfileMigrator.js
 @RESPATH@/browser/components/SafariProfileMigrator.js
 #endif
 #ifdef XP_MACOSX
 @RESPATH@/browser/components/SafariProfileMigrator.js
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @RESPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@