fix(packages): Make sure we can migrate and correctly disable new packages

- Add a package migration manager to be able to migrate external
packages into N1, and decide if they should be enabled or disabled by
default when added.
This commit is contained in:
Juan Tejada 2016-09-01 12:19:08 -07:00
parent 2e86fe81ac
commit 4fd06c1e16
3 changed files with 90 additions and 46 deletions

View file

@ -6,6 +6,11 @@
"ui-light"
],
"disabledPackages": [
"message-view-on-github",
"personal-level-indicators",
"phishing-detection",
"github-contact-card",
"keybase"
]
}
}

View file

@ -7,6 +7,7 @@ import ApplicationMenu from './application-menu';
import AutoUpdateManager from './auto-update-manager';
import PerformanceMonitor from './performance-monitor'
import NylasProtocolHandler from './nylas-protocol-handler';
import PackageMigrationManager from './package-migration-manager';
import ConfigPersistenceManager from './config-persistence-manager';
import {BrowserWindow, Menu, app, ipcMain, dialog} from 'electron';
@ -44,7 +45,8 @@ export default class Application extends EventEmitter {
this.configPersistenceManager = new ConfigPersistenceManager({configDirPath, resourcePath});
config.load();
this.temporaryInitializeDisabledPackages();
this.packageMigrationManager = new PackageMigrationManager({config, configDirPath, version})
this.packageMigrationManager.migrate()
let initializeInBackground = options.background;
if (initializeInBackground === undefined) {
@ -78,51 +80,6 @@ export default class Application extends EventEmitter {
return this.quitting;
}
temporaryInitializeDisabledPackages() {
if (this.config.get('core.disabledPackagesInitialized')) {
return;
}
const exampleNewNames = {
'N1-Message-View-on-Github': 'message-view-on-github',
'N1-Personal-Level-Indicators': 'personal-level-indicators',
'N1-Phishing-Detection': 'phishing-detection',
'N1-Github-Contact-Card-Section': 'github-contact-card',
'N1-Keybase': 'keybase',
'N1-Markdown': 'composer-markdown',
}
const exampleOldNames = Object.keys(exampleNewNames);
let examplesEnabled = [];
// Temporary: Find the examples that have been manually installed
if (fs.existsSync(path.join(this.configDirPath, 'packages'))) {
const packages = fs.readdirSync(path.join(this.configDirPath, 'packages'));
examplesEnabled = packages.filter((packageName) =>
exampleOldNames.includes(packageName) && (packageName[0] !== '.')
);
// Move old installed examples to a deprecated folder
const deprecatedPath = path.join(this.configDirPath, 'packages-deprecated')
if (!fs.existsSync(deprecatedPath)) {
fs.mkdirSync(deprecatedPath);
}
examplesEnabled.forEach((dir) => {
const prevPath = path.join(this.configDirPath, 'packages', dir)
const nextPath = path.join(deprecatedPath, dir)
fs.renameSync(prevPath, nextPath);
});
}
// Disable examples not specifically enabled
for (const oldName of Object.keys(exampleNewNames)) {
if (examplesEnabled.includes(oldName)) {
continue;
}
this.config.pushAtKeyPath('core.disabledPackages', exampleNewNames[oldName]);
}
this.config.set('core.disabledPackagesInitialized', true);
}
temporaryMigrateConfig() {
const oldConfigFilePath = fs.resolve(this.configDirPath, 'config.cson');
const newConfigFilePath = path.join(this.configDirPath, 'config.json');

View file

@ -0,0 +1,82 @@
import fs from 'fs'
import path from 'path'
import semver from 'semver'
const PACKAGE_MIGRATIONS = [
{
"version": "0.4.50",
"package-migrations": [{
"new-name": "composer-markdown",
"old-name": "N1-Markdown-Composer",
"enabled-by-default": false,
}],
},
]
class PackageMigrationManager {
constructor({config, version, configDirPath} = {}) {
this.config = config
this.configDirPath = configDirPath
this.version = version
this.savedMigrationVersion = this.config.get('core.packageMigrationVersion')
}
getMigrationsToRun() {
let migrations;
if (this.savedMigrationVersion) {
migrations = PACKAGE_MIGRATIONS
.filter((migration) => semver.gt(migration.version, this.savedMigrationVersion))
.map(migration => migration['package-migrations'])
} else {
migrations = PACKAGE_MIGRATIONS.map(migration => migration['package-migrations'])
}
return [].concat.apply([], migrations)
}
migrate() {
if (this.savedMigrationVersion === this.version) { return }
const migrations = this.getMigrationsToRun()
const oldPackNames = migrations.map((mig) => mig['old-name'])
const disabledPackNames = this.config.get('core.disabledPackages') || []
let oldEnabledPackNames = []
if (fs.existsSync(path.join(this.configDirPath, 'packages'))) {
// Find any external packages that have been manually installed
const toMigrate = fs.readdirSync(path.join(this.configDirPath, 'packages'))
.filter((packName) => oldPackNames.includes(packName))
.filter((packName) => packName[0] !== '.')
// Move old installed packages to a deprecated folder
const deprecatedPath = path.join(this.configDirPath, 'packages-deprecated')
if (!fs.existsSync(deprecatedPath)) {
fs.mkdirSync(deprecatedPath);
}
toMigrate.forEach((packName) => {
const prevPath = path.join(this.configDirPath, 'packages', packName)
const nextPath = path.join(deprecatedPath, packName)
fs.renameSync(prevPath, nextPath);
});
oldEnabledPackNames = toMigrate.filter((packName) => (
!(disabledPackNames).includes(packName)
))
}
// Enable any packages that were migrated from an old install and were
// enabled, or that should be enabled by default
migrations.forEach((migration) => {
// If the old install was enabled, keep it that way
if (oldEnabledPackNames.includes(migration['old-name'])) { return }
// If we want to enable the package by default,
if (migration['enabled-by-default']) { return }
const newName = migration['new-name']
this.config.pushAtKeyPath('core.disabledPackages', newName);
})
this.config.set('core.packageMigrationVersion', this.version)
}
}
export default PackageMigrationManager